From nobody Thu May 2 08:52:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; arc=pass (i=1 dmarc=pass fromdomain=suse.com); dmarc=pass(p=quarantine dis=none) header.from=suse.com ARC-Seal: i=2; a=rsa-sha256; t=1628684605; cv=pass; d=zohomail.com; s=zohoarc; b=MGJ0N5MRrPH4PSsi4M+lxA+kyIKqJok2/QbANETAueBYsv8b6ZAFhs1imS1ReXz1VC6Egrwy+3FTCJRfM0U/y/ri2fvzF2XsUIWIxwWbg7uPHLUaTjJWgRo9in7DKFx4U+uuQVK99XQbyNzVyS9SGIVaVG4CaiAvv+hhyfXusBY= ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1628684605; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=e8+t6pl6PvtXYXb42f9JTaiE9W++IXan+EkDSi7PXMk=; b=BpOIzSzjYIoU2WqcfM9Ea57gzoxC+kKevAjFDmAmc5srTMS4CKIGcHr8StkRXZ9oH3enS2zXs+jxHSUtTXKj3Xj9jcrO9/fXkobnly2JpEHjMF2PmmLCTVfTmnw21WPjAE+vta+I8FQ6Hia7jiSmyFF+u+hGHNaOBrB5kKPsaOg= ARC-Authentication-Results: i=2; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; arc=pass (i=1 dmarc=pass fromdomain=suse.com); dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1628684605938627.3116862434171; Wed, 11 Aug 2021 05:23:25 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.165975.303129 (Exim 4.92) (envelope-from ) id 1mDnGC-0005yG-8b; Wed, 11 Aug 2021 12:23:04 +0000 Received: by outflank-mailman (output) from mailman id 165975.303129; Wed, 11 Aug 2021 12:23:04 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1mDnGC-0005y9-57; Wed, 11 Aug 2021 12:23:04 +0000 Received: by outflank-mailman (input) for mailman id 165975; Wed, 11 Aug 2021 12:23:03 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1mDnGB-0005y1-GF for xen-devel@lists.xenproject.org; Wed, 11 Aug 2021 12:23:03 +0000 Received: from de-smtp-delivery-102.mimecast.com (unknown [194.104.111.102]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id dca93d4c-fa9e-11eb-a06c-12813bfff9fa; Wed, 11 Aug 2021 12:22:58 +0000 (UTC) Received: from EUR05-VI1-obe.outbound.protection.outlook.com (mail-vi1eur05lp2169.outbound.protection.outlook.com [104.47.17.169]) (Using TLS) by relay.mimecast.com with ESMTP id de-mta-40-29zxl_CDO4K5HE6QqZTecQ-1; Wed, 11 Aug 2021 14:22:55 +0200 Received: from VI1PR04MB5600.eurprd04.prod.outlook.com (2603:10a6:803:e7::16) by VI1PR0402MB3535.eurprd04.prod.outlook.com (2603:10a6:803:11::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4394.21; Wed, 11 Aug 2021 12:22:53 +0000 Received: from VI1PR04MB5600.eurprd04.prod.outlook.com ([fe80::99d3:99cd:8adf:3eea]) by VI1PR04MB5600.eurprd04.prod.outlook.com ([fe80::99d3:99cd:8adf:3eea%5]) with mapi id 15.20.4394.025; Wed, 11 Aug 2021 12:22:53 +0000 Received: from [10.156.60.236] (37.24.206.209) by AM0P190CA0015.EURP190.PROD.OUTLOOK.COM (2603:10a6:208:190::25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4415.16 via Frontend Transport; Wed, 11 Aug 2021 12:22:53 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: dca93d4c-fa9e-11eb-a06c-12813bfff9fa DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=mimecast20200619; t=1628684577; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=e8+t6pl6PvtXYXb42f9JTaiE9W++IXan+EkDSi7PXMk=; b=Q+Zk9WqbPqbgEHPZUi4w9+XOSgvbRtwigecD8AHcW9DCgjwTM+QNOCxrEP+XmM+px1wcGb /KcT4CU3Mz1KadqQu7eWDWDQPvjZdxugFzJzfZMrZ8YyC3iToD2FRHv/f5qkxrWLhTI9mT au4pmSEThiBSqB3G3rorOR3ntj2qFK0= X-MC-Unique: 29zxl_CDO4K5HE6QqZTecQ-1 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=IkxoTQYBzDDIYq5H9jA4ouzk5B9s1vJK+lDyMGCkuMzd94VT1f/2wvFZkMnbivnhSY3fvtKVmyCsVbD/FhccxFSvXUQYlucsMawPPZwUFbSFsL1Ukqowj0YnXAALH7hj8ALGfbiYdHknu3Ke5LMlGQBmEo4TqVH7pcuV3rup6trQF/ekIdY7iSsq1xX1LWfeMgYWea0cA2sq6uGSdkZGYxyC6vZrXf/9uDzdfAEhPD++SihpsFDRn0uOR4TmY/By47Ffbs2xfT9cBcQVrINzZ7UBxPY7axxBRtS0yEgGyxzw6EzsBmmMRHZTcDSxI31bMGlIG3pR2HCFQ2yTyqmRPQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=e8+t6pl6PvtXYXb42f9JTaiE9W++IXan+EkDSi7PXMk=; b=ObD1dSpYGcQxBlz73ozUyOv30QNUyuGEslzfYzuurC96NgQ06Vxerykfumndt6VTtZJUd8ZgJbIYwGGEkumwfaRImc+8YXATZxcu5DU1UZOMjh0q7fCGBO2OqIWIGBkhSyj+BpE4VwN3vdfR649uIxSW9HS7udrLJMf0XP0qtuIUsMnHxfGMUhYrk+0mqzqCd4eamShRqCdzGBR/WEpWIPAJ3LGIbRfU8QyQYkROkBUspo8NxZpISDxNtodKRa6LRsYrafPIVx2xU61lOnGPf4Kaw/saTXzJ17UGuPCHGHpANspeajlbe0fu48mHuwCt9AP9XvaddDzuI+hah5+u3g== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=suse.com; dmarc=pass action=none header.from=suse.com; dkim=pass header.d=suse.com; arc=none Authentication-Results: citrix.com; dkim=none (message not signed) header.d=none;citrix.com; dmarc=none action=none header.from=suse.com; Subject: [PATCH 1/7] x86emul: split off opcode 0f01 handling From: Jan Beulich To: "xen-devel@lists.xenproject.org" Cc: Andrew Cooper , Wei Liu , =?UTF-8?Q?Roger_Pau_Monn=c3=a9?= References: Message-ID: <8b8021e0-f688-54d2-007a-154a39790bd4@suse.com> Date: Wed, 11 Aug 2021 14:22:52 +0200 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Thunderbird/78.12.0 In-Reply-To: Content-Language: en-US Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: AM0P190CA0015.EURP190.PROD.OUTLOOK.COM (2603:10a6:208:190::25) To VI1PR04MB5600.eurprd04.prod.outlook.com (2603:10a6:803:e7::16) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 0eb4c16a-6210-440f-5a1f-08d95cc2be2d X-MS-TrafficTypeDiagnostic: VI1PR0402MB3535: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:983; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: KmGyn62A1dyfw/z+deMQxN6QfjyATd0VKMbF53gJE2o/3dyKi/0JaCoN4db09nr48Y4CEff5DufF7/fw7DHK8hxKDrd65MzffkJJi5vI1IQyT6jUIX7lCMLuh8Af58NSS2wfRMIOCMHC/9oJlTvh2TldlC3ot7doVpXdXf49FaX2xZ0Ks5RGk7BG41bWMySBMZocwNLewHzf7BltXMHGcyb2mUJlHzcsSPIuGS/bCPaREpxGOqtvJ0u52mdM3Xq6wurfuHRTg91+ZxRm4raRAfpgkYHDhK5IIn4/usEC9JskGVkhlr5wWH9v9VOalyh8XjW1zt8U0lHogZbz5w28+DaBeCgujD/DBdHBg1TijxVAWG0ABeD4flvyutZccaTZ00zVnM63tTa/SRH8GDGUILewHNfVr01MB10VoF7j1k7F2dtmrYSp0SWjQSwYKwPpab9xH4o37VUTiCyAWmydpYU+TJfCZ/aIKVXgCUtd/s0YUNz+ewHWN0CvCoTaYHJCQwPFLk4gVtzzqAY9Yxpogdhp2mk0Wl1oKpExoLsFil015Yd4ysCv6e2i2Y5sbVdUKeU3oafTnPe0LoW9tb2vInFP2JSOSrq44r1+qiqjKX8QZ6BxELYGwsCW109q00WGAHq90KN5/eY4EBtaMuWvgUaDtZGA6/CnvOgFAIPW3M0/3DHukhkUTjRL9HxCNRAWDEBZCMJouU1tcYMbIj2m1+8AARNmxS7voRFrPA0jQVKv8tT4PwKGkc2Z68uPA9h+e0H0+W6rk1KcXon08jPeTup2d/Lr6FONHuUM03PNbN+Ftq+qblUJuYkyhcBexNGq7Lj053P42Eve4G+TH3VNsw== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:VI1PR04MB5600.eurprd04.prod.outlook.com;PTR:;CAT:NONE;SFS:(396003)(136003)(366004)(346002)(39860400002)(376002)(66574015)(83380400001)(5660300002)(26005)(2906002)(30864003)(956004)(4326008)(2616005)(38100700002)(478600001)(186003)(16576012)(8676002)(316002)(6916009)(66946007)(8936002)(36756003)(31696002)(54906003)(86362001)(66476007)(6486002)(31686004)(66556008)(2004002)(45980500001)(43740500002)(579004)(559001);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?RkdzMTloTjRJbWMrTlhvV0F0R2dHU1lNc0dmRlFYeDNkNUl3Sk9NbHVTbHMx?= =?utf-8?B?b3dBbS9qd1FmbmlhVHM2blI0eWoxcitVaDVISGh3T1dvV25iL3l2YW9jMXg2?= =?utf-8?B?MG9jRk9pWVpNTjFGdXg0K3QvcDdqVmJEeGtJNytraW00T1lFZVBTWVQwbnRG?= =?utf-8?B?dGN2cjl6Q1NxcFI1b2llbGdRZHh2dUdGK3VOQXJMMVpHdzFLYll2bHFiVk5U?= =?utf-8?B?V1ZXeFBjanBuTzcwMnRubVlZVWlTNXJHSS9aM2Zqa0V3S2FoZ2RiN3BBejVS?= =?utf-8?B?Mmg0QlRvRzJsQmkza0dFUC96b1Z2U2xaeGY3UHgyblBZSElJeTdkY3Y5dUFp?= =?utf-8?B?SEMvVnNNb0lhdlhiUkJVWmVINHhYM3JNbURDOGZBd05nNUVWWHp0bkowdlNu?= =?utf-8?B?OU9yd3JJa1M4R2RxRHdwUHNrY05SODVDMlZyR3FrQUVEUVdiaEhaN0loWTVC?= =?utf-8?B?MzhoVC9QSWVZaDlOZEpGME5nbVZaT0FsTGxQb05vc2lFN0d0Rm5KdVAwMUZk?= =?utf-8?B?YjNNYnZ5OUxjRWgyeDRjOHU4eGJDK0RvNTNzTVRNQzFqY1dZRFZ5WlZKeFdY?= =?utf-8?B?cWpVdDZ4TnU5TzduNzJCNTRuM2IvZlJ5cThNbHFJQWxHbEZzZlFDeTBDYU1P?= =?utf-8?B?eGUrbzRFL0thZ2hEM1A1VDBUalpmY1BwbUU1WmR1STN5VnVuRVZWSmlnM2JM?= =?utf-8?B?Rk9aRVVnSVFjTldXN2lKb21uY09CMVNNMUl3SXI1V0JJa3FrZ2x0a2Vvd3RS?= =?utf-8?B?RHpGb2hBaUxqVzlQUlpxMWJYdzRsS1ZnYU8wSXFTNkJhSE1UcXZlLy9Jak04?= =?utf-8?B?aitsbEF0dXhkVUFyRjVQc1RPbG9lK1pjODMyVk9FZWdzejhCOFBSblN1VzRs?= =?utf-8?B?SlNzY1RudGtKU3B3YWp2ZWhyRWZHWlFnUTB0Zmp0d1pRVGxQdWNSQnFrNlk2?= =?utf-8?B?cGJkY2hTNFcycERjSGNZNlY1ck9nQ25JYzBsRzV5bUhyWGJqV1A3RFAxNk1a?= =?utf-8?B?Qno5QlBvSzlVRWY2bzhSWDdLYzJNZ1FSdjRiT1J3V1ByUEV4ay9FQjdrcXpQ?= =?utf-8?B?QkNTNDFpZy8yU0s2UHRnRGRwaXVpRmI2bk1VRWorTFhUemZUMjJMVUtEMlor?= =?utf-8?B?U3l3cU9OUExXUU5KZ2JOblVNLy9ZRXN3VXRqRHNNeFQrMXduU0l2MzVKZkhP?= =?utf-8?B?aVNQR0taeEkvR0RSVGJOaVVNdGFVWmtKUDdqOUdtaWUyTDF0N0EyNXRLNVBL?= =?utf-8?B?OFFUclVObDB2alh3S2pqTzh5b01DN2g4bjkyS3FLTEFzS1NERzZKM0QrbTVr?= =?utf-8?B?aGg5d3VJV1VUdjRIMHk2MEY0NmRnaVNrVEVtUGQ0ZmFucjhka29pbE9KOHIr?= =?utf-8?B?MTQwMmpPOTNUTVhhK1JuaGtrU0t1eHJOTG84b2I4bm1FalIyYS90M0plZFh1?= =?utf-8?B?bmJQODhtUnh3dXRjL2hidGlsaTNjcUtoL1JpaXlWY2JlOTBDUGJudlJWOUo2?= =?utf-8?B?SER5cFg2d0pXblRFaWlZczBNMGIwZ284VlVXVWoxSFFmZ3dPL2ZnVlJ2SXht?= =?utf-8?B?dnR2NmxiMUpCcUUzZ1RvbzdUUEd0UGh2TU1VenJUVWVZOWJYS25HN0ZyMmJJ?= =?utf-8?B?a1ZYbXAyVVdQamIyWmxrblhZUXR5WXA4VGw0cTBONDJzMjgyVnZSVDZQc0Yx?= =?utf-8?B?dU9WbmpsSnlGQS8xOW9BNENyRmtLTzQyeXorK0g5bWQ1eks1cXBZVEpBWmVD?= =?utf-8?Q?XQGXoMOhlhMxaP7xcvHL24JNyajpdlAwBaFrXZp?= X-OriginatorOrg: suse.com X-MS-Exchange-CrossTenant-Network-Message-Id: 0eb4c16a-6210-440f-5a1f-08d95cc2be2d X-MS-Exchange-CrossTenant-AuthSource: VI1PR04MB5600.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 11 Aug 2021 12:22:53.5568 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: f7a17af6-1c5c-4a36-aa8b-f5be247aa4ba X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 2n9zdIjpQyLZNyO2KJgKrDAcE/yCV786u5VUCFWJNt0aJC7YQk1EbjPV3OwzDjDDVN5PguVjyFsc0gALqBUvDw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR0402MB3535 X-ZohoMail-DKIM: pass (identity @suse.com) X-ZM-MESSAGEID: 1628684606718100001 Content-Type: text/plain; charset="utf-8" There's a fair amount of sub-cases (with some yet to be implemented), so a separate function seems warranted. Code moved gets slightly adjusted in a few places, e.g. replacing EXC_* by X86_EXC_* (such that EXC_* don't need to move as well; we want these to be phased out anyway). Signed-off-by: Jan Beulich --- a/tools/fuzz/x86_instruction_emulator/Makefile +++ b/tools/fuzz/x86_instruction_emulator/Makefile @@ -11,10 +11,13 @@ endif # Add libx86 to the build vpath %.c $(XEN_ROOT)/xen/lib/x86 =20 +.PHONY: x86_emulate x86_emulate: - [ -L $@ ] || ln -sf $(XEN_ROOT)/xen/arch/x86/$@ + mkdir -p $@ + ln -sf $(XEN_ROOT)/xen/arch/x86/$@/*.[ch] $@/ =20 -x86_emulate/%: x86_emulate ; +x86_emulate/%.c: x86_emulate ; +x86_emulate/%.h: x86_emulate ; =20 x86-emulate.c x86-emulate.h wrappers.c: %: [ -L $* ] || ln -sf $(XEN_ROOT)/tools/tests/x86_emulator/$* @@ -31,18 +34,27 @@ x86.h :=3D $(addprefix $(XEN_ROOT)/tools/i cpuid.h cpuid-autogen.h) x86_emulate.h :=3D x86-emulate.h x86_emulate/x86_emulate.h $(x86.h) =20 +OBJS :=3D fuzz-emul.o x86-emulate.o +OBJS +=3D x86_emulate/0f01.o + # x86-emulate.c will be implicit for both -x86-emulate.o x86-emulate-cov.o: x86_emulate/x86_emulate.c $(x86_emulate.h) +x86-emulate.o x86-emulate-cov.o: x86_emulate/x86_emulate.c $(x86_emulate.h= ) x86_emulate/private.h =20 fuzz-emul.o fuzz-emulate-cov.o cpuid.o wrappers.o: $(x86_emulate.h) =20 -x86-insn-fuzzer.a: fuzz-emul.o x86-emulate.o cpuid.o +$(filter x86_emulate/%.o,$(OBJS)): x86_emulate/%.o: x86_emulate/%.c x86_em= ulate/private.h $(x86_emulate.h) + $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_$*.o) -c -o $@ $< $(APPEND_CFLAGS) + +$(patsubst %.o,%-cov.o,$(filter x86_emulate/%.o,$(OBJS))): x86_emulate/%-c= ov.o: x86_emulate/%.c x86_emulate/private.h $(x86_emulate.h) + $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_$*.o) $(GCOV_FLAGS) -c -o $@ $< $(AP= PEND_CFLAGS) + +x86-insn-fuzzer.a: $(OBJS) cpuid.o $(AR) rc $@ $^ =20 -afl-harness: afl-harness.o fuzz-emul.o x86-emulate.o cpuid.o wrappers.o +afl-harness: afl-harness.o $(OBJS) cpuid.o wrappers.o $(CC) $(CFLAGS) $^ -o $@ =20 -afl-harness-cov: afl-harness-cov.o fuzz-emul-cov.o x86-emulate-cov.o cpuid= .o wrappers.o +afl-harness-cov: afl-harness-cov.o $(patsubst %.o,%-cov.o,$(OBJS)) cpuid.o= wrappers.o $(CC) $(CFLAGS) $(GCOV_FLAGS) $^ -o $@ =20 # Common targets --- a/tools/tests/x86_emulator/Makefile +++ b/tools/tests/x86_emulator/Makefile @@ -29,7 +29,7 @@ OPMASK :=3D avx512f avx512dq avx512bw =20 ifeq ($(origin XEN_COMPILE_ARCH),override) =20 -HOSTCFLAGS +=3D -m32 +HOSTCFLAGS +=3D -m32 -I.. =20 else =20 @@ -250,7 +250,10 @@ xop.h avx512f.h: simd-fma.c =20 endif # 32-bit override =20 -$(TARGET): x86-emulate.o cpuid.o test_x86_emulator.o evex-disp8.o predicat= es.o wrappers.o +OBJS :=3D x86-emulate.o cpuid.o test_x86_emulator.o evex-disp8.o predicate= s.o wrappers.o +OBJS +=3D x86_emulate/0f01.o + +$(TARGET): $(OBJS) $(HOSTCC) $(HOSTCFLAGS) -o $@ $^ =20 .PHONY: clean @@ -274,8 +277,10 @@ else run32 clean32: %32: % endif =20 +.PHONY: x86_emulate x86_emulate: - [ -L $@ ] || ln -sf $(XEN_ROOT)/xen/arch/x86/$@ + mkdir -p $@ + ln -sf $(XEN_ROOT)/xen/arch/x86/$@/*.[ch] $@/ =20 x86_emulate/%: x86_emulate ; =20 @@ -287,13 +292,13 @@ x86.h :=3D $(addprefix $(XEN_ROOT)/tools/i x86-vendors.h x86-defns.h msr-index.h) \ $(addprefix $(XEN_ROOT)/tools/include/xen/lib/x86/, \ cpuid.h cpuid-autogen.h) -x86_emulate.h :=3D x86-emulate.h x86_emulate/x86_emulate.h $(x86.h) +x86_emulate.h :=3D x86-emulate.h x86_emulate/x86_emulate.h x86_emulate/pri= vate.h $(x86.h) =20 -x86-emulate.o cpuid.o test_x86_emulator.o evex-disp8.o predicates.o wrappe= rs.o: %.o: %.c $(x86_emulate.h) +$(OBJS): %.o: %.c $(x86_emulate.h) $(HOSTCC) $(HOSTCFLAGS) -c -g -o $@ $< =20 x86-emulate.o: x86_emulate/x86_emulate.c -x86-emulate.o: HOSTCFLAGS +=3D -D__XEN_TOOLS__ +x86-emulate.o x86_emulate/%.o: HOSTCFLAGS +=3D -D__XEN_TOOLS__ =20 # In order for our custom .type assembler directives to reliably land after # gcc's, we need to keep it from re-ordering top-level constructs. --- a/tools/tests/x86_emulator/x86-emulate.c +++ b/tools/tests/x86_emulator/x86-emulate.c @@ -22,11 +22,9 @@ =20 /* For generic assembly code: use macros to define operation/operand sizes= . */ #ifdef __i386__ -# define r(name) e ## name # define __OS "l" /* Operation Suffix */ # define __OP "e" /* Operand Prefix */ #else -# define r(name) r ## name # define __OS "q" /* Operation Suffix */ # define __OP "r" /* Operand Prefix */ #endif @@ -265,12 +263,12 @@ void emul_test_put_fpu( =20 static uint32_t pkru; =20 -static unsigned int rdpkru(void) +unsigned int rdpkru(void) { return pkru; } =20 -static void wrpkru(unsigned int val) +void wrpkru(unsigned int val) { pkru =3D val; } --- a/tools/tests/x86_emulator/x86-emulate.h +++ b/tools/tests/x86_emulator/x86-emulate.h @@ -1,3 +1,6 @@ +#ifndef X86_EMULATE_H +#define X86_EMULATE_H + #include #include #include @@ -128,6 +131,9 @@ static inline bool xcr0_mask(uint64_t ma return cpu_has_xsave && ((xgetbv(0) & mask) =3D=3D mask); } =20 +unsigned int rdpkru(void); +void wrpkru(unsigned int val); + #define cache_line_size() (cp.basic.clflush_size * 8) #define cpu_has_fpu cp.basic.fpu #define cpu_has_mmx cp.basic.mmx @@ -205,3 +211,5 @@ void emul_test_put_fpu( struct x86_emulate_ctxt *ctxt, enum x86_emulate_fpu_type backout, const struct x86_emul_fpu_aux *aux); + +#endif /* X86_EMULATE_H */ --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -7,6 +7,7 @@ obj-y +=3D mm/ obj-$(CONFIG_XENOPROF) +=3D oprofile/ obj-$(CONFIG_PV) +=3D pv/ obj-y +=3D x86_64/ +obj-y +=3D x86_emulate/ =20 alternative-y :=3D alternative.init.o alternative-$(CONFIG_LIVEPATCH) :=3D --- a/xen/arch/x86/x86_emulate.c +++ b/xen/arch/x86/x86_emulate.c @@ -23,8 +23,6 @@ #undef cpuid #undef wbinvd =20 -#define r(name) r ## name - #define cpu_has_amd_erratum(nr) \ cpu_has_amd_erratum(¤t_cpu_data, AMD_ERRATUM_##nr) =20 @@ -45,12 +43,6 @@ =20 #define FXSAVE_AREA current->arch.fpu_ctxt =20 -#ifndef CONFIG_HVM -# define X86EMUL_NO_FPU -# define X86EMUL_NO_MMX -# define X86EMUL_NO_SIMD -#endif - #include "x86_emulate/x86_emulate.c" =20 int x86emul_read_xcr(unsigned int reg, uint64_t *val, --- /dev/null +++ b/xen/arch/x86/x86_emulate/0f01.c @@ -0,0 +1,349 @@ +/*************************************************************************= ***** + * 0f01.c - helper for x86_emulate.c + * + * Generic x86 (32-bit and 64-bit) instruction decoder and emulator. + * + * Copyright (c) 2005-2007 Keir Fraser + * Copyright (c) 2005-2007 XenSource Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; If not, see . + */ + +#include "private.h" + +#define ad_bytes (s->ad_bytes) /* for truncate_ea() */ + +int x86emul_0f01(struct x86_emulate_state *s, + struct cpu_user_regs *regs, + struct operand *dst, + struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops) +{ + enum x86_segment seg =3D (s->modrm_reg & 1) ? x86_seg_idtr : x86_seg_g= dtr; + int rc; + + switch ( s->modrm ) + { + unsigned long base, limit, cr0, cr0w, cr4; + struct segment_register sreg; + uint64_t msr_val; + + case 0xca: /* clac */ + case 0xcb: /* stac */ + vcpu_must_have(smap); + generate_exception_if(s->vex.pfx || !mode_ring0(), X86_EXC_UD); + + regs->eflags &=3D ~X86_EFLAGS_AC; + if ( s->modrm =3D=3D 0xcb ) + regs->eflags |=3D X86_EFLAGS_AC; + break; + + case 0xd0: /* xgetbv */ + generate_exception_if(s->vex.pfx, X86_EXC_UD); + if ( !ops->read_cr || !ops->read_xcr || + ops->read_cr(4, &cr4, ctxt) !=3D X86EMUL_OKAY ) + cr4 =3D 0; + generate_exception_if(!(cr4 & X86_CR4_OSXSAVE), X86_EXC_UD); + rc =3D ops->read_xcr(regs->ecx, &msr_val, ctxt); + if ( rc !=3D X86EMUL_OKAY ) + goto done; + regs->r(ax) =3D (uint32_t)msr_val; + regs->r(dx) =3D msr_val >> 32; + break; + + case 0xd1: /* xsetbv */ + generate_exception_if(s->vex.pfx, X86_EXC_UD); + if ( !ops->read_cr || !ops->write_xcr || + ops->read_cr(4, &cr4, ctxt) !=3D X86EMUL_OKAY ) + cr4 =3D 0; + generate_exception_if(!(cr4 & X86_CR4_OSXSAVE), X86_EXC_UD); + generate_exception_if(!mode_ring0(), X86_EXC_GP, 0); + rc =3D ops->write_xcr(regs->ecx, + regs->eax | ((uint64_t)regs->edx << 32), ctxt); + if ( rc !=3D X86EMUL_OKAY ) + goto done; + break; + + case 0xd4: /* vmfunc */ + generate_exception_if(s->vex.pfx, X86_EXC_UD); + fail_if(!ops->vmfunc); + if ( (rc =3D ops->vmfunc(ctxt)) !=3D X86EMUL_OKAY ) + goto done; + break; + + case 0xd5: /* xend */ + generate_exception_if(s->vex.pfx, X86_EXC_UD); + generate_exception_if(!vcpu_has_rtm(), X86_EXC_UD); + generate_exception_if(vcpu_has_rtm(), X86_EXC_GP, 0); + break; + + case 0xd6: /* xtest */ + generate_exception_if(s->vex.pfx, X86_EXC_UD); + generate_exception_if(!vcpu_has_rtm() && !vcpu_has_hle(), + X86_EXC_UD); + /* Neither HLE nor RTM can be active when we get here. */ + regs->eflags |=3D X86_EFLAGS_ZF; + break; + + case 0xdf: /* invlpga */ + fail_if(!ops->read_msr); + if ( (rc =3D ops->read_msr(MSR_EFER, + &msr_val, ctxt)) !=3D X86EMUL_OKAY ) + goto done; + /* Finding SVME set implies vcpu_has_svm(). */ + generate_exception_if(!(msr_val & EFER_SVME) || + !in_protmode(ctxt, ops), X86_EXC_UD); + generate_exception_if(!mode_ring0(), X86_EXC_GP, 0); + fail_if(!ops->tlb_op); + if ( (rc =3D ops->tlb_op(x86emul_invlpga, truncate_ea(regs->r(ax)), + regs->ecx, ctxt)) !=3D X86EMUL_OKAY ) + goto done; + break; + + case 0xe8: + switch ( s->vex.pfx ) + { + case vex_none: /* serialize */ + host_and_vcpu_must_have(serialize); + asm volatile ( ".byte 0x0f, 0x01, 0xe8" ); + break; + case vex_f2: /* xsusldtrk */ + vcpu_must_have(tsxldtrk); + /* + * We're never in a transactional region when coming here + * - nothing else to do. + */ + break; + default: + return X86EMUL_UNIMPLEMENTED; + } + break; + + case 0xe9: + switch ( s->vex.pfx ) + { + case vex_f2: /* xresldtrk */ + vcpu_must_have(tsxldtrk); + /* + * We're never in a transactional region when coming here + * - nothing else to do. + */ + break; + default: + return X86EMUL_UNIMPLEMENTED; + } + break; + + case 0xee: + switch ( s->vex.pfx ) + { + case vex_none: /* rdpkru */ + if ( !ops->read_cr || + ops->read_cr(4, &cr4, ctxt) !=3D X86EMUL_OKAY ) + cr4 =3D 0; + generate_exception_if(!(cr4 & X86_CR4_PKE), X86_EXC_UD); + generate_exception_if(regs->ecx, X86_EXC_GP, 0); + regs->r(ax) =3D rdpkru(); + regs->r(dx) =3D 0; + break; + default: + return X86EMUL_UNIMPLEMENTED; + } + break; + + case 0xef: + switch ( s->vex.pfx ) + { + case vex_none: /* wrpkru */ + if ( !ops->read_cr || + ops->read_cr(4, &cr4, ctxt) !=3D X86EMUL_OKAY ) + cr4 =3D 0; + generate_exception_if(!(cr4 & X86_CR4_PKE), X86_EXC_UD); + generate_exception_if(regs->ecx | regs->edx, X86_EXC_GP, 0); + wrpkru(regs->eax); + break; + default: + return X86EMUL_UNIMPLEMENTED; + } + break; + + case 0xf8: /* swapgs */ + generate_exception_if(!mode_64bit(), X86_EXC_UD); + generate_exception_if(!mode_ring0(), X86_EXC_GP, 0); + fail_if(!ops->read_segment || !ops->read_msr || + !ops->write_segment || !ops->write_msr); + if ( (rc =3D ops->read_segment(x86_seg_gs, &sreg, + ctxt)) !=3D X86EMUL_OKAY || + (rc =3D ops->read_msr(MSR_SHADOW_GS_BASE, &msr_val, + ctxt)) !=3D X86EMUL_OKAY || + (rc =3D ops->write_msr(MSR_SHADOW_GS_BASE, sreg.base, + ctxt)) !=3D X86EMUL_OKAY ) + goto done; + sreg.base =3D msr_val; + if ( (rc =3D ops->write_segment(x86_seg_gs, &sreg, + ctxt)) !=3D X86EMUL_OKAY ) + { + /* Best effort unwind (i.e. no error checking). */ + ops->write_msr(MSR_SHADOW_GS_BASE, msr_val, ctxt); + goto done; + } + break; + + case 0xf9: /* rdtscp */ + fail_if(ops->read_msr =3D=3D NULL); + if ( (rc =3D ops->read_msr(MSR_TSC_AUX, + &msr_val, ctxt)) !=3D X86EMUL_OKAY ) + goto done; + regs->r(cx) =3D (uint32_t)msr_val; + return X86EMUL_rdtsc; + + case 0xfc: /* clzero */ + { + unsigned long zero =3D 0; + + vcpu_must_have(clzero); + + base =3D ad_bytes =3D=3D 8 ? regs->r(ax) : + ad_bytes =3D=3D 4 ? regs->eax : regs->ax; + limit =3D ctxt->cpuid->basic.clflush_size * 8; + generate_exception_if(limit < sizeof(long) || + (limit & (limit - 1)), X86_EXC_UD); + base &=3D ~(limit - 1); + if ( ops->rep_stos ) + { + unsigned long nr_reps =3D limit / sizeof(zero); + + rc =3D ops->rep_stos(&zero, s->ea.mem.seg, base, sizeof(zero), + &nr_reps, ctxt); + if ( rc =3D=3D X86EMUL_OKAY ) + { + base +=3D nr_reps * sizeof(zero); + limit -=3D nr_reps * sizeof(zero); + } + else if ( rc !=3D X86EMUL_UNHANDLEABLE ) + goto done; + } + fail_if(limit && !ops->write); + while ( limit ) + { + rc =3D ops->write(s->ea.mem.seg, base, &zero, sizeof(zero), ct= xt); + if ( rc !=3D X86EMUL_OKAY ) + goto done; + base +=3D sizeof(zero); + limit -=3D sizeof(zero); + } + break; + } + +#define _GRP7(mod, reg) \ + (((mod) << 6) | ((reg) << 3)) ... (((mod) << 6) | ((reg) << 3) | 7) +#define GRP7_MEM(reg) _GRP7(0, reg): case _GRP7(1, reg): case _GRP7(2, reg) +#define GRP7_ALL(reg) GRP7_MEM(reg): case _GRP7(3, reg) + + case GRP7_MEM(0): /* sgdt */ + case GRP7_MEM(1): /* sidt */ + ASSERT(s->ea.type =3D=3D OP_MEM); + generate_exception_if(umip_active(ctxt, ops), X86_EXC_GP, 0); + fail_if(!ops->read_segment || !ops->write); + if ( (rc =3D ops->read_segment(seg, &sreg, ctxt)) ) + goto done; + if ( mode_64bit() ) + s->op_bytes =3D 8; + else if ( s->op_bytes =3D=3D 2 ) + { + sreg.base &=3D 0xffffff; + s->op_bytes =3D 4; + } + if ( (rc =3D ops->write(s->ea.mem.seg, s->ea.mem.off, &sreg.limit, + 2, ctxt)) !=3D X86EMUL_OKAY || + (rc =3D ops->write(s->ea.mem.seg, truncate_ea(s->ea.mem.off += 2), + &sreg.base, s->op_bytes, ctxt)) !=3D X86EMUL= _OKAY ) + goto done; + break; + + case GRP7_MEM(2): /* lgdt */ + case GRP7_MEM(3): /* lidt */ + ASSERT(s->ea.type =3D=3D OP_MEM); + generate_exception_if(!mode_ring0(), X86_EXC_GP, 0); + fail_if(ops->write_segment =3D=3D NULL); + memset(&sreg, 0, sizeof(sreg)); + if ( (rc =3D read_ulong(s->ea.mem.seg, s->ea.mem.off, + &limit, 2, ctxt, ops)) || + (rc =3D read_ulong(s->ea.mem.seg, truncate_ea(s->ea.mem.off += 2), + &base, mode_64bit() ? 8 : 4, ctxt, ops)) ) + goto done; + generate_exception_if(!is_canonical_address(base), X86_EXC_GP, 0); + sreg.base =3D base; + sreg.limit =3D limit; + if ( !mode_64bit() && s->op_bytes =3D=3D 2 ) + sreg.base &=3D 0xffffff; + if ( (rc =3D ops->write_segment(seg, &sreg, ctxt)) ) + goto done; + break; + + case GRP7_ALL(4): /* smsw */ + generate_exception_if(umip_active(ctxt, ops), X86_EXC_GP, 0); + if ( s->ea.type =3D=3D OP_MEM ) + { + fail_if(!ops->write); + s->desc |=3D Mov; /* force writeback */ + s->ea.bytes =3D 2; + } + else + s->ea.bytes =3D s->op_bytes; + *dst =3D s->ea; + fail_if(ops->read_cr =3D=3D NULL); + if ( (rc =3D ops->read_cr(0, &dst->val, ctxt)) ) + goto done; + break; + + case GRP7_ALL(6): /* lmsw */ + fail_if(ops->read_cr =3D=3D NULL); + fail_if(ops->write_cr =3D=3D NULL); + generate_exception_if(!mode_ring0(), X86_EXC_GP, 0); + if ( (rc =3D ops->read_cr(0, &cr0, ctxt)) ) + goto done; + if ( s->ea.type =3D=3D OP_REG ) + cr0w =3D *s->ea.reg; + else if ( (rc =3D read_ulong(s->ea.mem.seg, s->ea.mem.off, + &cr0w, 2, ctxt, ops)) ) + goto done; + /* LMSW can: (1) set bits 0-3; (2) clear bits 1-3. */ + cr0 =3D (cr0 & ~0xe) | (cr0w & 0xf); + if ( (rc =3D ops->write_cr(0, cr0, ctxt)) ) + goto done; + break; + + case GRP7_MEM(7): /* invlpg */ + ASSERT(s->ea.type =3D=3D OP_MEM); + generate_exception_if(!mode_ring0(), X86_EXC_GP, 0); + fail_if(!ops->tlb_op); + if ( (rc =3D ops->tlb_op(x86emul_invlpg, s->ea.mem.off, s->ea.mem.= seg, + ctxt)) !=3D X86EMUL_OKAY ) + goto done; + break; + +#undef GRP7_ALL +#undef GRP7_MEM +#undef _GRP7 + + default: + return X86EMUL_UNIMPLEMENTED; + } + + rc =3D X86EMUL_OKAY; + + done: + return rc; +} --- /dev/null +++ b/xen/arch/x86/x86_emulate/Makefile @@ -0,0 +1 @@ +obj-y +=3D 0f01.o --- /dev/null +++ b/xen/arch/x86/x86_emulate/private.h @@ -0,0 +1,531 @@ +/*************************************************************************= ***** + * private.h - interface between x86_emulate.c and its helpers + * + * Copyright (c) 2005-2007 Keir Fraser + * Copyright (c) 2005-2007 XenSource Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; If not, see . + */ + +#ifdef __XEN__ + +# include +# include +# include + +# ifndef CONFIG_HVM +# define X86EMUL_NO_FPU +# define X86EMUL_NO_MMX +# define X86EMUL_NO_SIMD +# endif + +#else /* !__XEN__ */ +# include "x86-emulate.h" +#endif + +#ifdef __i386__ +# define mode_64bit() false +# define r(name) e ## name +#else +# define mode_64bit() (ctxt->addr_size =3D=3D 64) +# define r(name) r ## name +#endif + +/* Operand sizes: 8-bit operands or specified/overridden size. */ +#define ByteOp (1<<0) /* 8-bit operands. */ +/* Destination operand type. */ +#define DstNone (0<<1) /* No destination operand. */ +#define DstImplicit (0<<1) /* Destination operand is implicit in the opcod= e. */ +#define DstBitBase (1<<1) /* Memory operand, bit string. */ +#define DstReg (2<<1) /* Register operand. */ +#define DstEax DstReg /* Register EAX (aka DstReg with no ModRM) */ +#define DstMem (3<<1) /* Memory operand. */ +#define DstMask (3<<1) +/* Source operand type. */ +#define SrcNone (0<<3) /* No source operand. */ +#define SrcImplicit (0<<3) /* Source operand is implicit in the opcode. */ +#define SrcReg (1<<3) /* Register operand. */ +#define SrcEax SrcReg /* Register EAX (aka SrcReg with no ModRM) */ +#define SrcMem (2<<3) /* Memory operand. */ +#define SrcMem16 (3<<3) /* Memory operand (16-bit). */ +#define SrcImm (4<<3) /* Immediate operand. */ +#define SrcImmByte (5<<3) /* 8-bit sign-extended immediate operand. */ +#define SrcImm16 (6<<3) /* 16-bit zero-extended immediate operand. */ +#define SrcMask (7<<3) +/* Generic ModRM decode. */ +#define ModRM (1<<6) +/* vSIB addressing mode (0f38 extension opcodes only), aliasing ModRM. */ +#define vSIB (1<<6) +/* Destination is only written; never read. */ +#define Mov (1<<7) +/* VEX/EVEX (SIMD only): 2nd source operand unused (must be all ones) */ +#define TwoOp Mov +/* All operands are implicit in the opcode. */ +#define ImplicitOps (DstImplicit|SrcImplicit) + +typedef uint8_t opcode_desc_t; + +/* Type, address-of, and value of an instruction's operand. */ +struct operand { + enum { OP_REG, OP_MEM, OP_IMM, OP_NONE } type; + unsigned int bytes; + + /* Operand value. */ + unsigned long val; + + /* Original operand value. */ + unsigned long orig_val; + + /* OP_REG: Pointer to register field. */ + unsigned long *reg; + + /* OP_MEM: Segment and offset. */ + struct { + enum x86_segment seg; + unsigned long off; + } mem; +}; + +#define REX_PREFIX 0x40 +#define REX_B 0x01 +#define REX_X 0x02 +#define REX_R 0x04 +#define REX_W 0x08 + +enum simd_opsize { + simd_none, + + /* + * Ordinary packed integers: + * - 64 bits without prefix 66 (MMX) + * - 128 bits with prefix 66 (SSEn) + * - 128/256/512 bits depending on VEX.L/EVEX.LR (AVX+) + */ + simd_packed_int, + + /* + * Ordinary packed/scalar floating point: + * - 128 bits without prefix or with prefix 66 (SSEn) + * - 128/256/512 bits depending on VEX.L/EVEX.LR (AVX+) + * - 32 bits with prefix F3 (scalar single) + * - 64 bits with prefix F2 (scalar doubgle) + */ + simd_any_fp, + + /* + * Packed floating point: + * - 128 bits without prefix or with prefix 66 (SSEn) + * - 128/256/512 bits depending on VEX.L/EVEX.LR (AVX+) + */ + simd_packed_fp, + + /* + * Single precision packed/scalar floating point: + * - 128 bits without prefix (SSEn) + * - 128/256/512 bits depending on VEX.L/EVEX.LR (AVX+) + * - 32 bits with prefix F3 (scalar) + */ + simd_single_fp, + + /* + * Scalar floating point: + * - 32 bits with low opcode bit clear (scalar single) + * - 64 bits with low opcode bit set (scalar double) + */ + simd_scalar_opc, + + /* + * Scalar floating point: + * - 32/64 bits depending on VEX.W/EVEX.W + */ + simd_scalar_vexw, + + /* + * 128 bits of integer or floating point data, with no further + * formatting information, or with it encoded by EVEX.W. + */ + simd_128, + + /* + * 256 bits of integer or floating point data, with formatting + * encoded by EVEX.W. + */ + simd_256, + + /* Operand size encoded in non-standard way. */ + simd_other +}; +typedef uint8_t simd_opsize_t; + +#define vex_none 0 + +enum vex_opcx { + vex_0f =3D vex_none + 1, + vex_0f38, + vex_0f3a, +}; + +enum vex_pfx { + vex_66 =3D vex_none + 1, + vex_f3, + vex_f2 +}; + +union vex { + uint8_t raw[2]; + struct { /* SDM names */ + uint8_t opcx:5; /* mmmmm */ + uint8_t b:1; /* B */ + uint8_t x:1; /* X */ + uint8_t r:1; /* R */ + uint8_t pfx:2; /* pp */ + uint8_t l:1; /* L */ + uint8_t reg:4; /* vvvv */ + uint8_t w:1; /* W */ + }; +}; + +union evex { + uint8_t raw[3]; + struct { /* SDM names */ + uint8_t opcx:2; /* mm */ + uint8_t mbz:2; + uint8_t R:1; /* R' */ + uint8_t b:1; /* B */ + uint8_t x:1; /* X */ + uint8_t r:1; /* R */ + uint8_t pfx:2; /* pp */ + uint8_t mbs:1; + uint8_t reg:4; /* vvvv */ + uint8_t w:1; /* W */ + uint8_t opmsk:3; /* aaa */ + uint8_t RX:1; /* V' */ + uint8_t brs:1; /* b */ + uint8_t lr:2; /* L'L */ + uint8_t z:1; /* z */ + }; +}; + +struct x86_emulate_state { + unsigned int op_bytes, ad_bytes; + + enum { + ext_none =3D vex_none, + ext_0f =3D vex_0f, + ext_0f38 =3D vex_0f38, + ext_0f3a =3D vex_0f3a, + /* + * For XOP use values such that the respective instruction field + * can be used without adjustment. + */ + ext_8f08 =3D 8, + ext_8f09, + ext_8f0a, + } ext; + enum { + rmw_NONE, + rmw_adc, + rmw_add, + rmw_and, + rmw_btc, + rmw_btr, + rmw_bts, + rmw_dec, + rmw_inc, + rmw_neg, + rmw_not, + rmw_or, + rmw_rcl, + rmw_rcr, + rmw_rol, + rmw_ror, + rmw_sar, + rmw_sbb, + rmw_shl, + rmw_shld, + rmw_shr, + rmw_shrd, + rmw_sub, + rmw_xadd, + rmw_xchg, + rmw_xor, + } rmw; + enum { + blk_NONE, + blk_enqcmd, +#ifndef X86EMUL_NO_FPU + blk_fld, /* FLDENV, FRSTOR */ + blk_fst, /* FNSTENV, FNSAVE */ +#endif +#if !defined(X86EMUL_NO_FPU) || !defined(X86EMUL_NO_MMX) || \ + !defined(X86EMUL_NO_SIMD) + blk_fxrstor, + blk_fxsave, +#endif + blk_movdir, + } blk; + uint8_t modrm, modrm_mod, modrm_reg, modrm_rm; + uint8_t sib_index, sib_scale; + uint8_t rex_prefix; + bool lock_prefix; + bool not_64bit; /* Instruction not available in 64bit. */ + bool fpu_ctrl; /* Instruction is an FPU control one. */ + opcode_desc_t desc; + union vex vex; + union evex evex; + enum simd_opsize simd_size; + + /* + * Data operand effective address (usually computed from ModRM). + * Default is a memory operand relative to segment DS. + */ + struct operand ea; + + /* Immediate operand values, if any. Use otherwise unused fields. */ +#define imm1 ea.val +#define imm2 ea.orig_val + + unsigned long ip; + struct cpu_user_regs *regs; + +#ifndef NDEBUG + /* + * Track caller of x86_decode_insn() to spot missing as well as + * premature calls to x86_emulate_free_state(). + */ + void *caller; +#endif +}; + +/* + * Externally visible return codes from x86_emulate() are non-negative. + * Use negative values for internal state change indicators from helpers + * to the main function. + */ +#define X86EMUL_rdtsc (-1) + +/* + * These EFLAGS bits are restored from saved value during emulation, and + * any changes are written back to the saved value after emulation. + */ +#define EFLAGS_MASK (X86_EFLAGS_OF | X86_EFLAGS_SF | X86_EFLAGS_ZF | \ + X86_EFLAGS_AF | X86_EFLAGS_PF | X86_EFLAGS_CF) + +/* + * These EFLAGS bits are modifiable (by POPF and IRET), possibly subject + * to further CPL and IOPL constraints. + */ +#define EFLAGS_MODIFIABLE (X86_EFLAGS_ID | X86_EFLAGS_AC | X86_EFLAGS_RF |= \ + X86_EFLAGS_NT | X86_EFLAGS_IOPL | X86_EFLAGS_DF= | \ + X86_EFLAGS_IF | X86_EFLAGS_TF | EFLAGS_MASK) + +#define truncate_word(ea, byte_width) \ +({ unsigned long __ea =3D (ea); \ + unsigned int _width =3D (byte_width); \ + ((_width =3D=3D sizeof(unsigned long)) ? __ea : \ + (__ea & ((1UL << (_width << 3)) - 1))); \ +}) +#define truncate_ea(ea) truncate_word((ea), ad_bytes) + +#define fail_if(p) \ +do { \ + rc =3D (p) ? X86EMUL_UNHANDLEABLE : X86EMUL_OKAY; \ + if ( rc ) goto done; \ +} while (0) + +#define EXPECT(p) \ +do { \ + if ( unlikely(!(p)) ) \ + { \ + ASSERT_UNREACHABLE(); \ + goto unhandleable; \ + } \ +} while (0) + +static inline int mkec(uint8_t e, int32_t ec, ...) +{ + return (e < 32 && ((1u << e) & X86_EXC_HAVE_EC)) ? ec : X86_EVENT_NO_E= C; +} + +#define generate_exception_if(p, e, ec...) \ +({ if ( (p) ) { \ + x86_emul_hw_exception(e, mkec(e, ##ec, 0), ctxt); \ + rc =3D X86EMUL_EXCEPTION; = \ + goto done; \ + } \ +}) + +#define generate_exception(e, ec...) generate_exception_if(true, e, ##ec) + +static inline bool +in_realmode( + struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops) +{ + unsigned long cr0; + int rc; + + if ( ops->read_cr =3D=3D NULL ) + return 0; + + rc =3D ops->read_cr(0, &cr0, ctxt); + return (!rc && !(cr0 & X86_CR0_PE)); +} + +static inline bool +in_protmode( + struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops) +{ + return !(in_realmode(ctxt, ops) || (ctxt->regs->eflags & X86_EFLAGS_VM= )); +} + +#define mode_ring0() ({ \ + int _cpl =3D x86emul_get_cpl(ctxt, ops); \ + fail_if(_cpl < 0); \ + (_cpl =3D=3D 0); \ +}) + +#define vcpu_has_fpu() (ctxt->cpuid->basic.fpu) +#define vcpu_has_sep() (ctxt->cpuid->basic.sep) +#define vcpu_has_cx8() (ctxt->cpuid->basic.cx8) +#define vcpu_has_cmov() (ctxt->cpuid->basic.cmov) +#define vcpu_has_clflush() (ctxt->cpuid->basic.clflush) +#define vcpu_has_mmx() (ctxt->cpuid->basic.mmx) +#define vcpu_has_fxsr() (ctxt->cpuid->basic.fxsr) +#define vcpu_has_sse() (ctxt->cpuid->basic.sse) +#define vcpu_has_sse2() (ctxt->cpuid->basic.sse2) +#define vcpu_has_sse3() (ctxt->cpuid->basic.sse3) +#define vcpu_has_pclmulqdq() (ctxt->cpuid->basic.pclmulqdq) +#define vcpu_has_ssse3() (ctxt->cpuid->basic.ssse3) +#define vcpu_has_fma() (ctxt->cpuid->basic.fma) +#define vcpu_has_cx16() (ctxt->cpuid->basic.cx16) +#define vcpu_has_sse4_1() (ctxt->cpuid->basic.sse4_1) +#define vcpu_has_sse4_2() (ctxt->cpuid->basic.sse4_2) +#define vcpu_has_movbe() (ctxt->cpuid->basic.movbe) +#define vcpu_has_popcnt() (ctxt->cpuid->basic.popcnt) +#define vcpu_has_aesni() (ctxt->cpuid->basic.aesni) +#define vcpu_has_avx() (ctxt->cpuid->basic.avx) +#define vcpu_has_f16c() (ctxt->cpuid->basic.f16c) +#define vcpu_has_rdrand() (ctxt->cpuid->basic.rdrand) + +#define vcpu_has_mmxext() (ctxt->cpuid->extd.mmxext || vcpu_has_sse()) +#define vcpu_has_3dnow_ext() (ctxt->cpuid->extd._3dnowext) +#define vcpu_has_3dnow() (ctxt->cpuid->extd._3dnow) +#define vcpu_has_lahf_lm() (ctxt->cpuid->extd.lahf_lm) +#define vcpu_has_cr8_legacy() (ctxt->cpuid->extd.cr8_legacy) +#define vcpu_has_lzcnt() (ctxt->cpuid->extd.abm) +#define vcpu_has_sse4a() (ctxt->cpuid->extd.sse4a) +#define vcpu_has_misalignsse() (ctxt->cpuid->extd.misalignsse) +#define vcpu_has_xop() (ctxt->cpuid->extd.xop) +#define vcpu_has_fma4() (ctxt->cpuid->extd.fma4) +#define vcpu_has_tbm() (ctxt->cpuid->extd.tbm) +#define vcpu_has_clzero() (ctxt->cpuid->extd.clzero) +#define vcpu_has_wbnoinvd() (ctxt->cpuid->extd.wbnoinvd) + +#define vcpu_has_bmi1() (ctxt->cpuid->feat.bmi1) +#define vcpu_has_hle() (ctxt->cpuid->feat.hle) +#define vcpu_has_avx2() (ctxt->cpuid->feat.avx2) +#define vcpu_has_bmi2() (ctxt->cpuid->feat.bmi2) +#define vcpu_has_invpcid() (ctxt->cpuid->feat.invpcid) +#define vcpu_has_rtm() (ctxt->cpuid->feat.rtm) +#define vcpu_has_mpx() (ctxt->cpuid->feat.mpx) +#define vcpu_has_avx512f() (ctxt->cpuid->feat.avx512f) +#define vcpu_has_avx512dq() (ctxt->cpuid->feat.avx512dq) +#define vcpu_has_rdseed() (ctxt->cpuid->feat.rdseed) +#define vcpu_has_adx() (ctxt->cpuid->feat.adx) +#define vcpu_has_smap() (ctxt->cpuid->feat.smap) +#define vcpu_has_avx512_ifma() (ctxt->cpuid->feat.avx512_ifma) +#define vcpu_has_clflushopt() (ctxt->cpuid->feat.clflushopt) +#define vcpu_has_clwb() (ctxt->cpuid->feat.clwb) +#define vcpu_has_avx512pf() (ctxt->cpuid->feat.avx512pf) +#define vcpu_has_avx512er() (ctxt->cpuid->feat.avx512er) +#define vcpu_has_avx512cd() (ctxt->cpuid->feat.avx512cd) +#define vcpu_has_sha() (ctxt->cpuid->feat.sha) +#define vcpu_has_avx512bw() (ctxt->cpuid->feat.avx512bw) +#define vcpu_has_avx512vl() (ctxt->cpuid->feat.avx512vl) +#define vcpu_has_avx512_vbmi() (ctxt->cpuid->feat.avx512_vbmi) +#define vcpu_has_avx512_vbmi2() (ctxt->cpuid->feat.avx512_vbmi2) +#define vcpu_has_gfni() (ctxt->cpuid->feat.gfni) +#define vcpu_has_vaes() (ctxt->cpuid->feat.vaes) +#define vcpu_has_vpclmulqdq() (ctxt->cpuid->feat.vpclmulqdq) +#define vcpu_has_avx512_vnni() (ctxt->cpuid->feat.avx512_vnni) +#define vcpu_has_avx512_bitalg() (ctxt->cpuid->feat.avx512_bitalg) +#define vcpu_has_avx512_vpopcntdq() (ctxt->cpuid->feat.avx512_vpopcntdq) +#define vcpu_has_tsxldtrk() (ctxt->cpuid->feat.tsxldtrk) +#define vcpu_has_rdpid() (ctxt->cpuid->feat.rdpid) +#define vcpu_has_movdiri() (ctxt->cpuid->feat.movdiri) +#define vcpu_has_movdir64b() (ctxt->cpuid->feat.movdir64b) +#define vcpu_has_enqcmd() (ctxt->cpuid->feat.enqcmd) +#define vcpu_has_avx512_4vnniw() (ctxt->cpuid->feat.avx512_4vnniw) +#define vcpu_has_avx512_4fmaps() (ctxt->cpuid->feat.avx512_4fmaps) +#define vcpu_has_avx512_vp2intersect() (ctxt->cpuid->feat.avx512_vp2inters= ect) +#define vcpu_has_serialize() (ctxt->cpuid->feat.serialize) +#define vcpu_has_avx_vnni() (ctxt->cpuid->feat.avx_vnni) +#define vcpu_has_avx512_bf16() (ctxt->cpuid->feat.avx512_bf16) + +#define vcpu_must_have(feat) \ + generate_exception_if(!vcpu_has_##feat(), X86_EXC_UD) + +#ifdef __XEN__ +/* + * Note the difference between vcpu_must_have() and + * host_and_vcpu_must_have(): The latter needs to be used when + * emulation code is using the same instruction class for carrying out + * the actual operation. + */ +# define host_and_vcpu_must_have(feat) ({ \ + generate_exception_if(!cpu_has_##feat, X86_EXC_UD); \ + vcpu_must_have(feat); \ +}) +#else +/* + * For the test harness both are fine to be used interchangeably, i.e. + * features known to always be available (e.g. SSE/SSE2) to (64-bit) Xen + * may be checked for by just vcpu_must_have(). + */ +# define host_and_vcpu_must_have(feat) vcpu_must_have(feat) +#endif + +int x86emul_get_cpl(struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops); + +int x86emul_0f01(struct x86_emulate_state *s, + struct cpu_user_regs *regs, + struct operand *dst, + struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops); + +static inline bool umip_active(struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops) +{ + unsigned long cr4; + + /* Intentionally not using mode_ring0() here to avoid its fail_if(). */ + return x86emul_get_cpl(ctxt, ops) > 0 && + ops->read_cr && ops->read_cr(4, &cr4, ctxt) =3D=3D X86EMUL_OKAY= && + (cr4 & X86_CR4_UMIP); +} + +/* Compatibility function: read guest memory, zero-extend result to a ulon= g. */ +static inline int read_ulong(enum x86_segment seg, + unsigned long offset, + unsigned long *val, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops) +{ + *val =3D 0; + return ops->read(seg, offset, val, bytes, ctxt); +} --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -20,39 +20,7 @@ * along with this program; If not, see . */ =20 -/* Operand sizes: 8-bit operands or specified/overridden size. */ -#define ByteOp (1<<0) /* 8-bit operands. */ -/* Destination operand type. */ -#define DstNone (0<<1) /* No destination operand. */ -#define DstImplicit (0<<1) /* Destination operand is implicit in the opcod= e. */ -#define DstBitBase (1<<1) /* Memory operand, bit string. */ -#define DstReg (2<<1) /* Register operand. */ -#define DstEax DstReg /* Register EAX (aka DstReg with no ModRM) */ -#define DstMem (3<<1) /* Memory operand. */ -#define DstMask (3<<1) -/* Source operand type. */ -#define SrcNone (0<<3) /* No source operand. */ -#define SrcImplicit (0<<3) /* Source operand is implicit in the opcode. */ -#define SrcReg (1<<3) /* Register operand. */ -#define SrcEax SrcReg /* Register EAX (aka SrcReg with no ModRM) */ -#define SrcMem (2<<3) /* Memory operand. */ -#define SrcMem16 (3<<3) /* Memory operand (16-bit). */ -#define SrcImm (4<<3) /* Immediate operand. */ -#define SrcImmByte (5<<3) /* 8-bit sign-extended immediate operand. */ -#define SrcImm16 (6<<3) /* 16-bit zero-extended immediate operand. */ -#define SrcMask (7<<3) -/* Generic ModRM decode. */ -#define ModRM (1<<6) -/* vSIB addressing mode (0f38 extension opcodes only), aliasing ModRM. */ -#define vSIB (1<<6) -/* Destination is only written; never read. */ -#define Mov (1<<7) -/* VEX/EVEX (SIMD only): 2nd source operand unused (must be all ones) */ -#define TwoOp Mov -/* All operands are implicit in the opcode. */ -#define ImplicitOps (DstImplicit|SrcImplicit) - -typedef uint8_t opcode_desc_t; +#include "private.h" =20 static const opcode_desc_t opcode_table[256] =3D { /* 0x00 - 0x07 */ @@ -184,71 +152,6 @@ static const opcode_desc_t opcode_table[ ImplicitOps, ImplicitOps, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|= ModRM }; =20 -enum simd_opsize { - simd_none, - - /* - * Ordinary packed integers: - * - 64 bits without prefix 66 (MMX) - * - 128 bits with prefix 66 (SSEn) - * - 128/256/512 bits depending on VEX.L/EVEX.LR (AVX+) - */ - simd_packed_int, - - /* - * Ordinary packed/scalar floating point: - * - 128 bits without prefix or with prefix 66 (SSEn) - * - 128/256/512 bits depending on VEX.L/EVEX.LR (AVX+) - * - 32 bits with prefix F3 (scalar single) - * - 64 bits with prefix F2 (scalar doubgle) - */ - simd_any_fp, - - /* - * Packed floating point: - * - 128 bits without prefix or with prefix 66 (SSEn) - * - 128/256/512 bits depending on VEX.L/EVEX.LR (AVX+) - */ - simd_packed_fp, - - /* - * Single precision packed/scalar floating point: - * - 128 bits without prefix (SSEn) - * - 128/256/512 bits depending on VEX.L/EVEX.LR (AVX+) - * - 32 bits with prefix F3 (scalar) - */ - simd_single_fp, - - /* - * Scalar floating point: - * - 32 bits with low opcode bit clear (scalar single) - * - 64 bits with low opcode bit set (scalar double) - */ - simd_scalar_opc, - - /* - * Scalar floating point: - * - 32/64 bits depending on VEX.W/EVEX.W - */ - simd_scalar_vexw, - - /* - * 128 bits of integer or floating point data, with no further - * formatting information, or with it encoded by EVEX.W. - */ - simd_128, - - /* - * 256 bits of integer or floating point data, with formatting - * encoded by EVEX.W. - */ - simd_256, - - /* Operand size encoded in non-standard way. */ - simd_other -}; -typedef uint8_t simd_opsize_t; - enum disp8scale { /* Values 0 ... 4 are explicit sizes. */ d8s_bw =3D 5, @@ -670,45 +573,11 @@ static const struct ext8f09_table { [0xe1 ... 0xe3] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, }; =20 -#define REX_PREFIX 0x40 -#define REX_B 0x01 -#define REX_X 0x02 -#define REX_R 0x04 -#define REX_W 0x08 - -#define vex_none 0 - -enum vex_opcx { - vex_0f =3D vex_none + 1, - vex_0f38, - vex_0f3a, -}; - -enum vex_pfx { - vex_66 =3D vex_none + 1, - vex_f3, - vex_f2 -}; - #define VEX_PREFIX_DOUBLE_MASK 0x1 #define VEX_PREFIX_SCALAR_MASK 0x2 =20 static const uint8_t sse_prefix[] =3D { 0x66, 0xf3, 0xf2 }; =20 -union vex { - uint8_t raw[2]; - struct { /* SDM names */ - uint8_t opcx:5; /* mmmmm */ - uint8_t b:1; /* B */ - uint8_t x:1; /* X */ - uint8_t r:1; /* R */ - uint8_t pfx:2; /* pp */ - uint8_t l:1; /* L */ - uint8_t reg:4; /* vvvv */ - uint8_t w:1; /* W */ - }; -}; - #ifdef __x86_64__ # define PFX2 REX_PREFIX #else @@ -748,27 +617,6 @@ union vex { } \ } while (0) =20 -union evex { - uint8_t raw[3]; - struct { /* SDM names */ - uint8_t opcx:2; /* mm */ - uint8_t mbz:2; - uint8_t R:1; /* R' */ - uint8_t b:1; /* B */ - uint8_t x:1; /* X */ - uint8_t r:1; /* R */ - uint8_t pfx:2; /* pp */ - uint8_t mbs:1; - uint8_t reg:4; /* vvvv */ - uint8_t w:1; /* W */ - uint8_t opmsk:3; /* aaa */ - uint8_t RX:1; /* V' */ - uint8_t brs:1; /* b */ - uint8_t lr:2; /* L'L */ - uint8_t z:1; /* z */ - }; -}; - #define EVEX_PFX_BYTES 4 #define init_evex(stub) ({ \ uint8_t *buf_ =3D get_stub(stub); \ @@ -789,118 +637,6 @@ union evex { #define repe_prefix() (vex.pfx =3D=3D vex_f3) #define repne_prefix() (vex.pfx =3D=3D vex_f2) =20 -/* Type, address-of, and value of an instruction's operand. */ -struct operand { - enum { OP_REG, OP_MEM, OP_IMM, OP_NONE } type; - unsigned int bytes; - - /* Operand value. */ - unsigned long val; - - /* Original operand value. */ - unsigned long orig_val; - - /* OP_REG: Pointer to register field. */ - unsigned long *reg; - - /* OP_MEM: Segment and offset. */ - struct { - enum x86_segment seg; - unsigned long off; - } mem; -}; - -struct x86_emulate_state { - unsigned int op_bytes, ad_bytes; - - enum { - ext_none =3D vex_none, - ext_0f =3D vex_0f, - ext_0f38 =3D vex_0f38, - ext_0f3a =3D vex_0f3a, - /* - * For XOP use values such that the respective instruction field - * can be used without adjustment. - */ - ext_8f08 =3D 8, - ext_8f09, - ext_8f0a, - } ext; - enum { - rmw_NONE, - rmw_adc, - rmw_add, - rmw_and, - rmw_btc, - rmw_btr, - rmw_bts, - rmw_dec, - rmw_inc, - rmw_neg, - rmw_not, - rmw_or, - rmw_rcl, - rmw_rcr, - rmw_rol, - rmw_ror, - rmw_sar, - rmw_sbb, - rmw_shl, - rmw_shld, - rmw_shr, - rmw_shrd, - rmw_sub, - rmw_xadd, - rmw_xchg, - rmw_xor, - } rmw; - enum { - blk_NONE, - blk_enqcmd, -#ifndef X86EMUL_NO_FPU - blk_fld, /* FLDENV, FRSTOR */ - blk_fst, /* FNSTENV, FNSAVE */ -#endif -#if !defined(X86EMUL_NO_FPU) || !defined(X86EMUL_NO_MMX) || \ - !defined(X86EMUL_NO_SIMD) - blk_fxrstor, - blk_fxsave, -#endif - blk_movdir, - } blk; - uint8_t modrm, modrm_mod, modrm_reg, modrm_rm; - uint8_t sib_index, sib_scale; - uint8_t rex_prefix; - bool lock_prefix; - bool not_64bit; /* Instruction not available in 64bit. */ - bool fpu_ctrl; /* Instruction is an FPU control one. */ - opcode_desc_t desc; - union vex vex; - union evex evex; - enum simd_opsize simd_size; - - /* - * Data operand effective address (usually computed from ModRM). - * Default is a memory operand relative to segment DS. - */ - struct operand ea; - - /* Immediate operand values, if any. Use otherwise unused fields. */ -#define imm1 ea.val -#define imm2 ea.orig_val - - unsigned long ip; - struct cpu_user_regs *regs; - -#ifndef NDEBUG - /* - * Track caller of x86_decode_insn() to spot missing as well as - * premature calls to x86_emulate_free_state(). - */ - void *caller; -#endif -}; - #ifdef __x86_64__ #define PTR_POISON ((void *)0x8086000000008086UL) /* non-canonical */ #else @@ -1049,21 +785,6 @@ struct x86_fxsr { #define _BYTES_PER_LONG "4" #endif =20 -/* - * These EFLAGS bits are restored from saved value during emulation, and - * any changes are written back to the saved value after emulation. - */ -#define EFLAGS_MASK (X86_EFLAGS_OF | X86_EFLAGS_SF | X86_EFLAGS_ZF | \ - X86_EFLAGS_AF | X86_EFLAGS_PF | X86_EFLAGS_CF) - -/* - * These EFLAGS bits are modifiable (by POPF and IRET), possibly subject - * to further CPL and IOPL constraints. - */ -#define EFLAGS_MODIFIABLE (X86_EFLAGS_ID | X86_EFLAGS_AC | X86_EFLAGS_RF |= \ - X86_EFLAGS_NT | X86_EFLAGS_IOPL | X86_EFLAGS_DF= | \ - X86_EFLAGS_IF | X86_EFLAGS_TF | EFLAGS_MASK) - /* Before executing instruction: restore necessary bits in EFLAGS. */ #define _PRE_EFLAGS(_sav, _msk, _tmp) \ /* EFLAGS =3D (_sav & _msk) | (EFLAGS & ~_msk); _sav &=3D ~_msk; */ \ @@ -1223,36 +944,6 @@ do{ asm volatile ( #define __emulate_1op_8byte(op, dst, eflags, extra...) #endif /* __i386__ */ =20 -#define fail_if(p) \ -do { \ - rc =3D (p) ? X86EMUL_UNHANDLEABLE : X86EMUL_OKAY; \ - if ( rc ) goto done; \ -} while (0) - -#define EXPECT(p) \ -do { \ - if ( unlikely(!(p)) ) \ - { \ - ASSERT_UNREACHABLE(); \ - goto unhandleable; \ - } \ -} while (0) - -static inline int mkec(uint8_t e, int32_t ec, ...) -{ - return (e < 32 && ((1u << e) & EXC_HAS_EC)) ? ec : X86_EVENT_NO_EC; -} - -#define generate_exception_if(p, e, ec...) \ -({ if ( (p) ) { \ - x86_emul_hw_exception(e, mkec(e, ##ec, 0), ctxt); \ - rc =3D X86EMUL_EXCEPTION; = \ - goto done; \ - } \ -}) - -#define generate_exception(e, ec...) generate_exception_if(true, e, ##ec) - #ifdef __XEN__ # define invoke_stub(pre, post, constraints...) do { \ stub_exn.info =3D (union stub_exception_token) { .raw =3D ~0 }; = \ @@ -1301,20 +992,6 @@ static inline int mkec(uint8_t e, int32_ }) #define insn_fetch_type(_type) ((_type)insn_fetch_bytes(sizeof(_type))) =20 -#define truncate_word(ea, byte_width) \ -({ unsigned long __ea =3D (ea); \ - unsigned int _width =3D (byte_width); \ - ((_width =3D=3D sizeof(unsigned long)) ? __ea : \ - (__ea & ((1UL << (_width << 3)) - 1))); \ -}) -#define truncate_ea(ea) truncate_word((ea), ad_bytes) - -#ifdef __x86_64__ -# define mode_64bit() (ctxt->addr_size =3D=3D 64) -#else -# define mode_64bit() false -#endif - /* * Given byte has even parity (even number of 1s)? SDM Vol. 1 Sec. 3.4.3.1, * "Status Flags": EFLAGS.PF reflects parity of least-sig. byte of result = only. @@ -1655,19 +1332,6 @@ static void __put_rep_prefix( ea__; \ }) =20 -/* Compatibility function: read guest memory, zero-extend result to a ulon= g. */ -static int read_ulong( - enum x86_segment seg, - unsigned long offset, - unsigned long *val, - unsigned int bytes, - struct x86_emulate_ctxt *ctxt, - const struct x86_emulate_ops *ops) -{ - *val =3D 0; - return ops->read(seg, offset, val, bytes, ctxt); -} - /* * Unsigned multiplication with double-word result. * IN: Multiplicand=3Dm[0], Multiplier=3Dm[1] @@ -1792,10 +1456,8 @@ test_cc( return (!!rc ^ (condition & 1)); } =20 -static int -get_cpl( - struct x86_emulate_ctxt *ctxt, - const struct x86_emulate_ops *ops) +int x86emul_get_cpl(struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops) { struct segment_register reg; =20 @@ -1814,17 +1476,12 @@ _mode_iopl( struct x86_emulate_ctxt *ctxt, const struct x86_emulate_ops *ops) { - int cpl =3D get_cpl(ctxt, ops); + int cpl =3D x86emul_get_cpl(ctxt, ops); if ( cpl =3D=3D -1 ) return -1; return cpl <=3D MASK_EXTR(ctxt->regs->eflags, X86_EFLAGS_IOPL); } =20 -#define mode_ring0() ({ \ - int _cpl =3D get_cpl(ctxt, ops); \ - fail_if(_cpl < 0); \ - (_cpl =3D=3D 0); \ -}) #define mode_iopl() ({ \ int _iopl =3D _mode_iopl(ctxt, ops); \ fail_if(_iopl < 0); \ @@ -1832,7 +1489,7 @@ _mode_iopl( }) #define mode_vif() ({ \ cr4 =3D 0; \ - if ( ops->read_cr && get_cpl(ctxt, ops) =3D=3D 3 ) \ + if ( ops->read_cr && x86emul_get_cpl(ctxt, ops) =3D=3D 3 ) \ { \ rc =3D ops->read_cr(4, &cr4, ctxt); \ if ( rc !=3D X86EMUL_OKAY ) goto done; \ @@ -1900,29 +1557,6 @@ static int ioport_access_check( } =20 static bool -in_realmode( - struct x86_emulate_ctxt *ctxt, - const struct x86_emulate_ops *ops) -{ - unsigned long cr0; - int rc; - - if ( ops->read_cr =3D=3D NULL ) - return 0; - - rc =3D ops->read_cr(0, &cr0, ctxt); - return (!rc && !(cr0 & X86_CR0_PE)); -} - -static bool -in_protmode( - struct x86_emulate_ctxt *ctxt, - const struct x86_emulate_ops *ops) -{ - return !(in_realmode(ctxt, ops) || (ctxt->regs->eflags & X86_EFLAGS_VM= )); -} - -static bool _amd_like(const struct cpuid_policy *cp) { return cp->x86_vendor & (X86_VENDOR_AMD | X86_VENDOR_HYGON); @@ -1934,107 +1568,6 @@ amd_like(const struct x86_emulate_ctxt * return _amd_like(ctxt->cpuid); } =20 -#define vcpu_has_fpu() (ctxt->cpuid->basic.fpu) -#define vcpu_has_sep() (ctxt->cpuid->basic.sep) -#define vcpu_has_cx8() (ctxt->cpuid->basic.cx8) -#define vcpu_has_cmov() (ctxt->cpuid->basic.cmov) -#define vcpu_has_clflush() (ctxt->cpuid->basic.clflush) -#define vcpu_has_mmx() (ctxt->cpuid->basic.mmx) -#define vcpu_has_fxsr() (ctxt->cpuid->basic.fxsr) -#define vcpu_has_sse() (ctxt->cpuid->basic.sse) -#define vcpu_has_sse2() (ctxt->cpuid->basic.sse2) -#define vcpu_has_sse3() (ctxt->cpuid->basic.sse3) -#define vcpu_has_pclmulqdq() (ctxt->cpuid->basic.pclmulqdq) -#define vcpu_has_ssse3() (ctxt->cpuid->basic.ssse3) -#define vcpu_has_fma() (ctxt->cpuid->basic.fma) -#define vcpu_has_cx16() (ctxt->cpuid->basic.cx16) -#define vcpu_has_sse4_1() (ctxt->cpuid->basic.sse4_1) -#define vcpu_has_sse4_2() (ctxt->cpuid->basic.sse4_2) -#define vcpu_has_movbe() (ctxt->cpuid->basic.movbe) -#define vcpu_has_popcnt() (ctxt->cpuid->basic.popcnt) -#define vcpu_has_aesni() (ctxt->cpuid->basic.aesni) -#define vcpu_has_avx() (ctxt->cpuid->basic.avx) -#define vcpu_has_f16c() (ctxt->cpuid->basic.f16c) -#define vcpu_has_rdrand() (ctxt->cpuid->basic.rdrand) - -#define vcpu_has_mmxext() (ctxt->cpuid->extd.mmxext || vcpu_has_sse()) -#define vcpu_has_3dnow_ext() (ctxt->cpuid->extd._3dnowext) -#define vcpu_has_3dnow() (ctxt->cpuid->extd._3dnow) -#define vcpu_has_lahf_lm() (ctxt->cpuid->extd.lahf_lm) -#define vcpu_has_cr8_legacy() (ctxt->cpuid->extd.cr8_legacy) -#define vcpu_has_lzcnt() (ctxt->cpuid->extd.abm) -#define vcpu_has_sse4a() (ctxt->cpuid->extd.sse4a) -#define vcpu_has_misalignsse() (ctxt->cpuid->extd.misalignsse) -#define vcpu_has_xop() (ctxt->cpuid->extd.xop) -#define vcpu_has_fma4() (ctxt->cpuid->extd.fma4) -#define vcpu_has_tbm() (ctxt->cpuid->extd.tbm) -#define vcpu_has_clzero() (ctxt->cpuid->extd.clzero) -#define vcpu_has_wbnoinvd() (ctxt->cpuid->extd.wbnoinvd) - -#define vcpu_has_bmi1() (ctxt->cpuid->feat.bmi1) -#define vcpu_has_hle() (ctxt->cpuid->feat.hle) -#define vcpu_has_avx2() (ctxt->cpuid->feat.avx2) -#define vcpu_has_bmi2() (ctxt->cpuid->feat.bmi2) -#define vcpu_has_invpcid() (ctxt->cpuid->feat.invpcid) -#define vcpu_has_rtm() (ctxt->cpuid->feat.rtm) -#define vcpu_has_mpx() (ctxt->cpuid->feat.mpx) -#define vcpu_has_avx512f() (ctxt->cpuid->feat.avx512f) -#define vcpu_has_avx512dq() (ctxt->cpuid->feat.avx512dq) -#define vcpu_has_rdseed() (ctxt->cpuid->feat.rdseed) -#define vcpu_has_adx() (ctxt->cpuid->feat.adx) -#define vcpu_has_smap() (ctxt->cpuid->feat.smap) -#define vcpu_has_avx512_ifma() (ctxt->cpuid->feat.avx512_ifma) -#define vcpu_has_clflushopt() (ctxt->cpuid->feat.clflushopt) -#define vcpu_has_clwb() (ctxt->cpuid->feat.clwb) -#define vcpu_has_avx512pf() (ctxt->cpuid->feat.avx512pf) -#define vcpu_has_avx512er() (ctxt->cpuid->feat.avx512er) -#define vcpu_has_avx512cd() (ctxt->cpuid->feat.avx512cd) -#define vcpu_has_sha() (ctxt->cpuid->feat.sha) -#define vcpu_has_avx512bw() (ctxt->cpuid->feat.avx512bw) -#define vcpu_has_avx512vl() (ctxt->cpuid->feat.avx512vl) -#define vcpu_has_avx512_vbmi() (ctxt->cpuid->feat.avx512_vbmi) -#define vcpu_has_avx512_vbmi2() (ctxt->cpuid->feat.avx512_vbmi2) -#define vcpu_has_gfni() (ctxt->cpuid->feat.gfni) -#define vcpu_has_vaes() (ctxt->cpuid->feat.vaes) -#define vcpu_has_vpclmulqdq() (ctxt->cpuid->feat.vpclmulqdq) -#define vcpu_has_avx512_vnni() (ctxt->cpuid->feat.avx512_vnni) -#define vcpu_has_avx512_bitalg() (ctxt->cpuid->feat.avx512_bitalg) -#define vcpu_has_avx512_vpopcntdq() (ctxt->cpuid->feat.avx512_vpopcntdq) -#define vcpu_has_tsxldtrk() (ctxt->cpuid->feat.tsxldtrk) -#define vcpu_has_rdpid() (ctxt->cpuid->feat.rdpid) -#define vcpu_has_movdiri() (ctxt->cpuid->feat.movdiri) -#define vcpu_has_movdir64b() (ctxt->cpuid->feat.movdir64b) -#define vcpu_has_enqcmd() (ctxt->cpuid->feat.enqcmd) -#define vcpu_has_avx512_4vnniw() (ctxt->cpuid->feat.avx512_4vnniw) -#define vcpu_has_avx512_4fmaps() (ctxt->cpuid->feat.avx512_4fmaps) -#define vcpu_has_avx512_vp2intersect() (ctxt->cpuid->feat.avx512_vp2inters= ect) -#define vcpu_has_serialize() (ctxt->cpuid->feat.serialize) -#define vcpu_has_avx_vnni() (ctxt->cpuid->feat.avx_vnni) -#define vcpu_has_avx512_bf16() (ctxt->cpuid->feat.avx512_bf16) - -#define vcpu_must_have(feat) \ - generate_exception_if(!vcpu_has_##feat(), EXC_UD) - -#ifdef __XEN__ -/* - * Note the difference between vcpu_must_have() and - * host_and_vcpu_must_have(): The latter needs to be used when - * emulation code is using the same instruction class for carrying out - * the actual operation. - */ -#define host_and_vcpu_must_have(feat) ({ \ - generate_exception_if(!cpu_has_##feat, EXC_UD); \ - vcpu_must_have(feat); \ -}) -#else -/* - * For the test harness both are fine to be used interchangeably, i.e. - * features known to always be available (e.g. SSE/SSE2) to (64-bit) Xen - * may be checked for by just vcpu_must_have(). - */ -#define host_and_vcpu_must_have(feat) vcpu_must_have(feat) -#endif - /* Initialise output state in x86_emulate_ctxt */ static void init_context(struct x86_emulate_ctxt *ctxt) { @@ -2081,7 +1614,7 @@ protmode_load_seg( enum x86_segment sel_seg =3D (sel & 4) ? x86_seg_ldtr : x86_seg_gdtr; struct { uint32_t a, b; } desc, desc_hi =3D {}; uint8_t dpl, rpl; - int cpl =3D get_cpl(ctxt, ops); + int cpl =3D x86emul_get_cpl(ctxt, ops); uint32_t a_flag =3D 0x100; int rc, fault_type =3D EXC_GP; =20 @@ -2481,17 +2014,6 @@ static bool is_branch_step(struct x86_em (debugctl & IA32_DEBUGCTLMSR_BTF); } =20 -static bool umip_active(struct x86_emulate_ctxt *ctxt, - const struct x86_emulate_ops *ops) -{ - unsigned long cr4; - - /* Intentionally not using mode_ring0() here to avoid its fail_if(). */ - return get_cpl(ctxt, ops) > 0 && - ops->read_cr && ops->read_cr(4, &cr4, ctxt) =3D=3D X86EMUL_OKAY= && - (cr4 & X86_CR4_UMIP); -} - static void adjust_bnd(struct x86_emulate_ctxt *ctxt, const struct x86_emulate_ops *ops, enum vex_pfx pfx) { @@ -5703,317 +5225,8 @@ x86_emulate( break; =20 case X86EMUL_OPC(0x0f, 0x01): /* Grp7 */ - { - unsigned long base, limit, cr0, cr0w; - - seg =3D (modrm_reg & 1) ? x86_seg_idtr : x86_seg_gdtr; - - switch( modrm ) - { - case 0xca: /* clac */ - case 0xcb: /* stac */ - vcpu_must_have(smap); - generate_exception_if(vex.pfx || !mode_ring0(), EXC_UD); - - _regs.eflags &=3D ~X86_EFLAGS_AC; - if ( modrm =3D=3D 0xcb ) - _regs.eflags |=3D X86_EFLAGS_AC; - break; - - case 0xd0: /* xgetbv */ - generate_exception_if(vex.pfx, EXC_UD); - if ( !ops->read_cr || !ops->read_xcr || - ops->read_cr(4, &cr4, ctxt) !=3D X86EMUL_OKAY ) - cr4 =3D 0; - generate_exception_if(!(cr4 & X86_CR4_OSXSAVE), EXC_UD); - rc =3D ops->read_xcr(_regs.ecx, &msr_val, ctxt); - if ( rc !=3D X86EMUL_OKAY ) - goto done; - _regs.r(ax) =3D (uint32_t)msr_val; - _regs.r(dx) =3D msr_val >> 32; - break; - - case 0xd1: /* xsetbv */ - generate_exception_if(vex.pfx, EXC_UD); - if ( !ops->read_cr || !ops->write_xcr || - ops->read_cr(4, &cr4, ctxt) !=3D X86EMUL_OKAY ) - cr4 =3D 0; - generate_exception_if(!(cr4 & X86_CR4_OSXSAVE), EXC_UD); - generate_exception_if(!mode_ring0(), EXC_GP, 0); - rc =3D ops->write_xcr(_regs.ecx, - _regs.eax | ((uint64_t)_regs.edx << 32), c= txt); - if ( rc !=3D X86EMUL_OKAY ) - goto done; - break; - - case 0xd4: /* vmfunc */ - generate_exception_if(vex.pfx, EXC_UD); - fail_if(!ops->vmfunc); - if ( (rc =3D ops->vmfunc(ctxt)) !=3D X86EMUL_OKAY ) - goto done; - break; - - case 0xd5: /* xend */ - generate_exception_if(vex.pfx, EXC_UD); - generate_exception_if(!vcpu_has_rtm(), EXC_UD); - generate_exception_if(vcpu_has_rtm(), EXC_GP, 0); - break; - - case 0xd6: /* xtest */ - generate_exception_if(vex.pfx, EXC_UD); - generate_exception_if(!vcpu_has_rtm() && !vcpu_has_hle(), - EXC_UD); - /* Neither HLE nor RTM can be active when we get here. */ - _regs.eflags |=3D X86_EFLAGS_ZF; - break; - - case 0xdf: /* invlpga */ - fail_if(!ops->read_msr); - if ( (rc =3D ops->read_msr(MSR_EFER, - &msr_val, ctxt)) !=3D X86EMUL_OKAY ) - goto done; - /* Finding SVME set implies vcpu_has_svm(). */ - generate_exception_if(!(msr_val & EFER_SVME) || - !in_protmode(ctxt, ops), EXC_UD); - generate_exception_if(!mode_ring0(), EXC_GP, 0); - fail_if(!ops->tlb_op); - if ( (rc =3D ops->tlb_op(x86emul_invlpga, truncate_ea(_regs.r(= ax)), - _regs.ecx, ctxt)) !=3D X86EMUL_OKAY ) - goto done; - break; - - case 0xe8: - switch ( vex.pfx ) - { - case vex_none: /* serialize */ - host_and_vcpu_must_have(serialize); - asm volatile ( ".byte 0x0f, 0x01, 0xe8" ); - break; - case vex_f2: /* xsusldtrk */ - vcpu_must_have(tsxldtrk); - /* - * We're never in a transactional region when coming here - * - nothing else to do. - */ - break; - default: - goto unimplemented_insn; - } - break; - - case 0xe9: - switch ( vex.pfx ) - { - case vex_f2: /* xresldtrk */ - vcpu_must_have(tsxldtrk); - /* - * We're never in a transactional region when coming here - * - nothing else to do. - */ - break; - default: - goto unimplemented_insn; - } - break; - - case 0xee: - switch ( vex.pfx ) - { - case vex_none: /* rdpkru */ - if ( !ops->read_cr || - ops->read_cr(4, &cr4, ctxt) !=3D X86EMUL_OKAY ) - cr4 =3D 0; - generate_exception_if(!(cr4 & X86_CR4_PKE), EXC_UD); - generate_exception_if(_regs.ecx, EXC_GP, 0); - _regs.r(ax) =3D rdpkru(); - _regs.r(dx) =3D 0; - break; - default: - goto unimplemented_insn; - } - break; - - case 0xef: - switch ( vex.pfx ) - { - case vex_none: /* wrpkru */ - if ( !ops->read_cr || - ops->read_cr(4, &cr4, ctxt) !=3D X86EMUL_OKAY ) - cr4 =3D 0; - generate_exception_if(!(cr4 & X86_CR4_PKE), EXC_UD); - generate_exception_if(_regs.ecx | _regs.edx, EXC_GP, 0); - wrpkru(_regs.eax); - break; - default: - goto unimplemented_insn; - } - break; - - case 0xf8: /* swapgs */ - generate_exception_if(!mode_64bit(), EXC_UD); - generate_exception_if(!mode_ring0(), EXC_GP, 0); - fail_if(!ops->read_segment || !ops->read_msr || - !ops->write_segment || !ops->write_msr); - if ( (rc =3D ops->read_segment(x86_seg_gs, &sreg, - ctxt)) !=3D X86EMUL_OKAY || - (rc =3D ops->read_msr(MSR_SHADOW_GS_BASE, &msr_val, - ctxt)) !=3D X86EMUL_OKAY || - (rc =3D ops->write_msr(MSR_SHADOW_GS_BASE, sreg.base, - ctxt)) !=3D X86EMUL_OKAY ) - goto done; - sreg.base =3D msr_val; - if ( (rc =3D ops->write_segment(x86_seg_gs, &sreg, - ctxt)) !=3D X86EMUL_OKAY ) - { - /* Best effort unwind (i.e. no error checking). */ - ops->write_msr(MSR_SHADOW_GS_BASE, msr_val, ctxt); - goto done; - } - break; - - case 0xf9: /* rdtscp */ - fail_if(ops->read_msr =3D=3D NULL); - if ( (rc =3D ops->read_msr(MSR_TSC_AUX, - &msr_val, ctxt)) !=3D X86EMUL_OKAY ) - goto done; - _regs.r(cx) =3D (uint32_t)msr_val; - goto rdtsc; - - case 0xfc: /* clzero */ - { - unsigned long zero =3D 0; - - vcpu_must_have(clzero); - - base =3D ad_bytes =3D=3D 8 ? _regs.r(ax) : - ad_bytes =3D=3D 4 ? _regs.eax : _regs.ax; - limit =3D ctxt->cpuid->basic.clflush_size * 8; - generate_exception_if(limit < sizeof(long) || - (limit & (limit - 1)), EXC_UD); - base &=3D ~(limit - 1); - if ( ops->rep_stos ) - { - unsigned long nr_reps =3D limit / sizeof(zero); - - rc =3D ops->rep_stos(&zero, ea.mem.seg, base, sizeof(zero), - &nr_reps, ctxt); - if ( rc =3D=3D X86EMUL_OKAY ) - { - base +=3D nr_reps * sizeof(zero); - limit -=3D nr_reps * sizeof(zero); - } - else if ( rc !=3D X86EMUL_UNHANDLEABLE ) - goto done; - } - fail_if(limit && !ops->write); - while ( limit ) - { - rc =3D ops->write(ea.mem.seg, base, &zero, sizeof(zero), c= txt); - if ( rc !=3D X86EMUL_OKAY ) - goto done; - base +=3D sizeof(zero); - limit -=3D sizeof(zero); - } - break; - } - -#define _GRP7(mod, reg) \ - (((mod) << 6) | ((reg) << 3)) ... (((mod) << 6) | ((reg) << 3)= | 7) -#define GRP7_MEM(reg) _GRP7(0, reg): case _GRP7(1, reg): case _GRP7(2, reg) -#define GRP7_ALL(reg) GRP7_MEM(reg): case _GRP7(3, reg) - - case GRP7_MEM(0): /* sgdt */ - case GRP7_MEM(1): /* sidt */ - ASSERT(ea.type =3D=3D OP_MEM); - generate_exception_if(umip_active(ctxt, ops), EXC_GP, 0); - fail_if(!ops->read_segment || !ops->write); - if ( (rc =3D ops->read_segment(seg, &sreg, ctxt)) ) - goto done; - if ( mode_64bit() ) - op_bytes =3D 8; - else if ( op_bytes =3D=3D 2 ) - { - sreg.base &=3D 0xffffff; - op_bytes =3D 4; - } - if ( (rc =3D ops->write(ea.mem.seg, ea.mem.off, &sreg.limit, - 2, ctxt)) !=3D X86EMUL_OKAY || - (rc =3D ops->write(ea.mem.seg, truncate_ea(ea.mem.off + 2= ), - &sreg.base, op_bytes, ctxt)) !=3D X86EMU= L_OKAY ) - goto done; - break; - - case GRP7_MEM(2): /* lgdt */ - case GRP7_MEM(3): /* lidt */ - ASSERT(ea.type =3D=3D OP_MEM); - generate_exception_if(!mode_ring0(), EXC_GP, 0); - fail_if(ops->write_segment =3D=3D NULL); - memset(&sreg, 0, sizeof(sreg)); - if ( (rc =3D read_ulong(ea.mem.seg, ea.mem.off, - &limit, 2, ctxt, ops)) || - (rc =3D read_ulong(ea.mem.seg, truncate_ea(ea.mem.off + 2= ), - &base, mode_64bit() ? 8 : 4, ctxt, ops))= ) - goto done; - generate_exception_if(!is_canonical_address(base), EXC_GP, 0); - sreg.base =3D base; - sreg.limit =3D limit; - if ( !mode_64bit() && op_bytes =3D=3D 2 ) - sreg.base &=3D 0xffffff; - if ( (rc =3D ops->write_segment(seg, &sreg, ctxt)) ) - goto done; - break; - - case GRP7_ALL(4): /* smsw */ - generate_exception_if(umip_active(ctxt, ops), EXC_GP, 0); - if ( ea.type =3D=3D OP_MEM ) - { - fail_if(!ops->write); - d |=3D Mov; /* force writeback */ - ea.bytes =3D 2; - } - else - ea.bytes =3D op_bytes; - dst =3D ea; - fail_if(ops->read_cr =3D=3D NULL); - if ( (rc =3D ops->read_cr(0, &dst.val, ctxt)) ) - goto done; - break; - - case GRP7_ALL(6): /* lmsw */ - fail_if(ops->read_cr =3D=3D NULL); - fail_if(ops->write_cr =3D=3D NULL); - generate_exception_if(!mode_ring0(), EXC_GP, 0); - if ( (rc =3D ops->read_cr(0, &cr0, ctxt)) ) - goto done; - if ( ea.type =3D=3D OP_REG ) - cr0w =3D *ea.reg; - else if ( (rc =3D read_ulong(ea.mem.seg, ea.mem.off, - &cr0w, 2, ctxt, ops)) ) - goto done; - /* LMSW can: (1) set bits 0-3; (2) clear bits 1-3. */ - cr0 =3D (cr0 & ~0xe) | (cr0w & 0xf); - if ( (rc =3D ops->write_cr(0, cr0, ctxt)) ) - goto done; - break; - - case GRP7_MEM(7): /* invlpg */ - ASSERT(ea.type =3D=3D OP_MEM); - generate_exception_if(!mode_ring0(), EXC_GP, 0); - fail_if(!ops->tlb_op); - if ( (rc =3D ops->tlb_op(x86emul_invlpg, ea.mem.off, ea.mem.se= g, - ctxt)) !=3D X86EMUL_OKAY ) - goto done; - break; - -#undef GRP7_ALL -#undef GRP7_MEM -#undef _GRP7 - - default: - goto unimplemented_insn; - } - break; - } + rc =3D x86emul_0f01(state, &_regs, &dst, ctxt, ops); + goto dispatch_from_helper; =20 case X86EMUL_OPC(0x0f, 0x02): /* lar */ generate_exception_if(!in_protmode(ctxt, ops), EXC_UD); @@ -11309,6 +10522,24 @@ x86_emulate( unrecognized_insn: rc =3D X86EMUL_UNRECOGNIZED; goto done; + + dispatch_from_helper: + if ( rc =3D=3D X86EMUL_OKAY ) + break; + + switch ( rc ) + { + case X86EMUL_rdtsc: + goto rdtsc; + } + + /* Internally used state change indicators may not make it here. */ + if ( rc < 0 ) + { + ASSERT_UNREACHABLE(); + rc =3D X86EMUL_UNHANDLEABLE; + } + goto done; } =20 if ( state->rmw ) From nobody Thu May 2 08:52:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; arc=pass (i=1 dmarc=pass fromdomain=suse.com); dmarc=pass(p=quarantine dis=none) header.from=suse.com ARC-Seal: i=2; a=rsa-sha256; t=1628684634; cv=pass; d=zohomail.com; s=zohoarc; b=FNXnzMz8wrO1iWqwlcWlgEsHAp3SzavmtaMgdttvOPVyFYIGB8Jg1VwaVKJSfLsvlFm0NvMKdW4T0qv8Kp3SsAF1XrLRlzz7q2yPwkwEDbZjZxZtRTs4kBSwKK5KpwSIn7jMUK9CjlgGqNCGzpDuPM1aN1GFKg6WBtQnfKJfym4= ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1628684634; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=egYmm6Rdb6BBn3/2r9woL+JT7Fq3SyhFNINnv8zofDY=; b=SLn7cHRbEyhVrxT+ou807aJonq3ZYPwq4l7xIBUwkAkDD1/hDcuD7ut/zXFR+bMdSE96AkfAtPNnL4uVV3aAH/Hlento4h46nz6OjEa7Tp4r4WQcxXodohrWfJ/p4eZ4uAjjKVbJmk8E4KhSlpLkufseGsgPM1tUcsO26xywswo= ARC-Authentication-Results: i=2; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; arc=pass (i=1 dmarc=pass fromdomain=suse.com); dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1628684634418505.21404425215553; Wed, 11 Aug 2021 05:23:54 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.165979.303139 (Exim 4.92) (envelope-from ) id 1mDnGf-0006YW-MD; Wed, 11 Aug 2021 12:23:33 +0000 Received: by outflank-mailman (output) from mailman id 165979.303139; Wed, 11 Aug 2021 12:23:33 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1mDnGf-0006YP-JF; Wed, 11 Aug 2021 12:23:33 +0000 Received: by outflank-mailman (input) for mailman id 165979; Wed, 11 Aug 2021 12:23:32 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1mDnGe-0006Sk-5X for xen-devel@lists.xenproject.org; Wed, 11 Aug 2021 12:23:32 +0000 Received: from de-smtp-delivery-102.mimecast.com (unknown [194.104.109.102]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id ef5a70e6-fa9e-11eb-a06d-12813bfff9fa; Wed, 11 Aug 2021 12:23:30 +0000 (UTC) Received: from EUR05-AM6-obe.outbound.protection.outlook.com (mail-am6eur05lp2106.outbound.protection.outlook.com [104.47.18.106]) (Using TLS) by relay.mimecast.com with ESMTP id de-mta-17-4fawh-lRMiGodYJoj2iwAw-2; Wed, 11 Aug 2021 14:23:28 +0200 Received: from VI1PR04MB5600.eurprd04.prod.outlook.com (2603:10a6:803:e7::16) by VI1PR04MB4351.eurprd04.prod.outlook.com (2603:10a6:803:49::33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4415.14; Wed, 11 Aug 2021 12:23:26 +0000 Received: from VI1PR04MB5600.eurprd04.prod.outlook.com ([fe80::99d3:99cd:8adf:3eea]) by VI1PR04MB5600.eurprd04.prod.outlook.com ([fe80::99d3:99cd:8adf:3eea%5]) with mapi id 15.20.4394.025; Wed, 11 Aug 2021 12:23:26 +0000 Received: from [10.156.60.236] (37.24.206.209) by AM0P190CA0015.EURP190.PROD.OUTLOOK.COM (2603:10a6:208:190::25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4415.16 via Frontend Transport; Wed, 11 Aug 2021 12:23:26 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: ef5a70e6-fa9e-11eb-a06d-12813bfff9fa DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=mimecast20200619; t=1628684609; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=egYmm6Rdb6BBn3/2r9woL+JT7Fq3SyhFNINnv8zofDY=; b=YfeuTk8IMADE718jp5dweF7L/jl6PRbIjVY+6VVw/LQ7eulRvK9/vQuSxBR779/DPxXHi0 8Qo1PsEP/69iCR6JukvQnCHnauoYGfejmdCdX1yXsaLdLdkooCCO93DdKdlqxyaxB3Ajs2 Wwp+r5CY2h1u7bxkWxqbAJvoxXA3JLo= X-MC-Unique: 4fawh-lRMiGodYJoj2iwAw-2 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=TBE7zlGMZUnjglt8w/7ZpcMxoarQIhQlwbdaV1SEgCSFOQr8qQ70WMQdK1FA9CqJ/uoXpjui/kuf0dlI86DxWtkD9If4que/xoqcx6N9J6IstYX3duxnK/7sPAbhAc5A1b5d9g3NbaI8ZFVJ2OM7NdXrZScj/ErXcpQXj/DrkpfAS4u79zx87fovVC/Nlu2i20cM9IOz8ymlfc+BSBIL8Apa1bLBhRtyXdV9KfSC5/WmU1m6ORep+XJ1U1G9vxETiEJPnrrctSyHgf6JZQKcu3xuH1OhcZUcf4PgXduEIsZY/ofQ41D0svQM9v2W/gmhZ0aOVH/+Pp6pvLfFuMtl9g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=egYmm6Rdb6BBn3/2r9woL+JT7Fq3SyhFNINnv8zofDY=; b=j9rQqVizuh9mwtm4H1BOTOkthSrVEO6oNBWdonVKkkrpktoW4owgeGiJyMXl1paddLYxAs7TOlEFNq2SnQg1nXpZjLW26DHH3N3dLM2zjcProH2ha8j5JRM/wfgLwLy4g+zfM5tDkoC1PpJ4HD1YVVm3RAPenmN9WMBjaK3XxC1mEYFAclkB0g0EUiqGmlb05IJ/j6soYyMKJOqz31GZ3DKMWr+PJNuiu6vnWWxqDwBvVepCe9//XYIFVu2qaYcuNtZDezRdfmNB3WD5Dr6Z2n6gUZjIT87WmNBoriv9XvWyZ2NYNo3FqctyyhXb3vTyxUFt7uASbdWDJRuDX0ayFQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=suse.com; dmarc=pass action=none header.from=suse.com; dkim=pass header.d=suse.com; arc=none Authentication-Results: citrix.com; dkim=none (message not signed) header.d=none;citrix.com; dmarc=none action=none header.from=suse.com; Subject: [PATCH 2/7] x86emul: split off opcode 0fae handling From: Jan Beulich To: "xen-devel@lists.xenproject.org" Cc: Andrew Cooper , Wei Liu , =?UTF-8?Q?Roger_Pau_Monn=c3=a9?= References: Message-ID: <9f73d8a9-56a1-7004-7933-48597201565a@suse.com> Date: Wed, 11 Aug 2021 14:23:25 +0200 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Thunderbird/78.12.0 In-Reply-To: Content-Language: en-US Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: AM0P190CA0015.EURP190.PROD.OUTLOOK.COM (2603:10a6:208:190::25) To VI1PR04MB5600.eurprd04.prod.outlook.com (2603:10a6:803:e7::16) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: fa0363c0-6128-4339-bedb-08d95cc2d1cf X-MS-TrafficTypeDiagnostic: VI1PR04MB4351: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:5236; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: tvVCrCe7oCWp4dNOb/ipol3QRIv4VnyX2KSiY+U2/cexuwO+9TCe2x27AYnUTBsg2YJB19lktNk6TJ85u0dAHWLHbD7ffQ9R5LJI0oXfCgDU9P8Eu/lXyDmAuExMk5Iy5ZYzp7VxtaUaMuTZBcy5o+WLjaXOLVI9GV1GsgsVHMFTZJXFhxwVH+JCIwR5R/XiFJOnt5JcMbNFR3UzOufq2ngaTUvKFNiI1FwEFuWcrj8Xyq2RZQ/DmNLvWh5SwKl2lUJ+4C8LQLJ4KMvSPupn59XqOflwG5sm0GSy2uBJftLWtlQgNiqujTSJg1FN8p4OdMM7M5lS75kgZzaZDuCh7iXoHcsR06609iW8PpWbNZQEWN3xTs/TDrkG2wu0hpYaAJ2DlRqSLCV25EppjfOP/DlcenMLAhVlqwzlfNhHKtZggdtfD01286YTGqlisGmaHJiAf/GztBZ4xd3RE2uHrUjLjKO6RNVx2mLhE83g4v67kWOxcG3qFqjvLE/w+B8BL5MJ/829Sf4Gz1qjKDtGdyZPwAxA/oNf4TzwjJ5lHhIrF0fFIqjOReQ3JpIlzc7Zegfb7C2Qs/oq8mpUB4AmRTfA46iD97WDNwvfc8LlqiOER/ZAjZNeglPNzg/xsj8q/Zw2bFeGdK7+xcBFkkoUNeEsMWr1zphFvJcNuTQCTKfo5LfhfJVIpgU93KgNlg+5UMwE9Pqz4c2lSIznV6nVscakXXhUgyadED7saL3V4BFaX0FkzHhFwnZrtZbyCQTGy9JJHW0XA2bzLw+mqUClSA9FLE5Cr7VhxlG3wZQjG8Nq/z46gNcTXfCy4e5diLn41Wzl7HEYiS6COyu5bZJhCQ== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:VI1PR04MB5600.eurprd04.prod.outlook.com;PTR:;CAT:NONE;SFS:(366004)(6486002)(8936002)(316002)(16576012)(2616005)(956004)(8676002)(5660300002)(6916009)(66946007)(36756003)(30864003)(31686004)(2906002)(86362001)(31696002)(186003)(26005)(66556008)(83380400001)(54906003)(508600001)(4326008)(38100700002)(66476007)(2004002)(43740500002)(45980500001);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?WHRRUGZybDB4ZVpvN0wrTU43cngrMVI5SFhvNlNNRmkxUDIrV01yWWw4NW9l?= =?utf-8?B?K3hlR0F5RFk0WXJ6SUJ1cGhnQW5nUnFnMkZ4NWljOWY2ZStCRVdFNm1iWnZV?= =?utf-8?B?ZFJLN1dHazRCRit0elFwb2twSnhRSG1tNlUwMWE5bUlHZkZhWmJ0NzJRc0J6?= =?utf-8?B?bzRpdGpiWlJVZUNyeHkzdlFrWWRuYzhlZG9HNndIbjJYTTd5cUJrVnJBeldN?= =?utf-8?B?TTNwZzdkZkxoRnhvN1JnMktXOTdkQlNsTDVJWUVMUWZIVjVOUUFSSzJJc2Vk?= =?utf-8?B?OHdCbW9yZy9nZ1dtQUhudVVhc0tOTC90ZERQYXdnSUd5SWRRSzFoV2MvT3pt?= =?utf-8?B?MHhhdGtnS2hwQ2lsVkEvNmhydTBBVVg5dklFNVBrOU1LdDVndG85NkNDRktX?= =?utf-8?B?NVZObEJCQktEYmxyQ3BReW1aU1B3N0R0MUoxUVpaS1pBUi9veER0ZGplUjNZ?= =?utf-8?B?OU5SNDNsaDlEL0tsZE4zU2ova0RReE9yOU1Gb0kxejBkK1NUNEFZYXg5Z0tE?= =?utf-8?B?R3F4U0ljZ1hObXVuWTdNZjlFclZpNHE3d1pFNG5PY1M2TEIxSVRLT3Y4aW9K?= =?utf-8?B?d1RJQ2lhSVZXWloxWkVzSFQycElIdUl0TWp0Vy9PWUhOT21zcXhlRHJFNTJD?= =?utf-8?B?cU4vNkdMVXlwOS9nM2ZLUHZkVXNTdWxnaE5RZEJUWTdTeWRqZ1dWdy9sb3Ji?= =?utf-8?B?RUx1OVBmUnRXb0FTUllBUmk5M0phNXVYTTZ2Y2ZCMUtEUzZVSEs2eTFDYTFD?= =?utf-8?B?anE3TG1KWmJNbUVGeVhTYkczQmNpODYrSHlLYkhIZEU3V2tLc3lReHhya0U5?= =?utf-8?B?dGVBTVM3eldhRTJ6RG5Na2Y0MHRVQnRXTTRQSzB1eVo5MDhrbS8wRnN2Wnpr?= =?utf-8?B?UEtHZDQzVHRHMzhDZ3ZSRW5ad2JGTG9mWEFXYi8vR0RuRTN6cDBxUE0yd1R6?= =?utf-8?B?bjkxakdBRjZYQTlYam01TytVWmV5Vk9hNTFqeTBoRlBDRzdxR0xONGNlcFRw?= =?utf-8?B?aTNuZDRIendzS3hvaDZDbzlQMUl4T0tKMmtQN3YvdFErM21RWlBQUjlnNG1t?= =?utf-8?B?VUtidGlIc2YxaW0vZWE0ayswdGlFdnFkRVp2U1hTN0JpQTUvcU9CQVJGVlkx?= =?utf-8?B?QnBZN25KR2JnMWFiNGRvZ2dkbnIyOEp5UG5RWVlzUjJ6OXpwa2RlOUI2NUdL?= =?utf-8?B?d1VKWk9LcjdJMWg5akVBY2Q4aUZlRzNWd3o3aG1MTnkyWVVJVXIvRVRqUnlJ?= =?utf-8?B?QmpaU25oWjA4anB6MWdreVpxTEtWNlp6NENLS0NGb05Ka2U3dG5lMVpVOEFh?= =?utf-8?B?UDFZZitMZnFtbVFPb25iVDVIRXkxV0taYUJueDUwdG5IMDd3bGRMdmFOTkgw?= =?utf-8?B?eGs2NlBCbEh3cll4Ui9KR29kemdxSUs3Q1pqZUxZSU5JejAzRDZHdkZFNmk4?= =?utf-8?B?UGdTc3VVOElZRXNzYWk3TFFMV1ByVmw1V0doeUVxZTZVT2M4OTdvMlkxbWtB?= =?utf-8?B?VHBTV3k4cXNRTElrNFV6KzF6Y0Y5K0VwVmNScHZUeEovQy9IdXJrUVdxOTJD?= =?utf-8?B?WGt4cEtMNjVqRWRrN3ZIWDF0ZEM0VTk1dVVkbUJsUFR6Wlc1a21sV0JhQTZJ?= =?utf-8?B?QVg1YWFUR3FUZlRXZnRFUkVZVG9EMnVka1ZYRGVHaUdxeFN1YlFWY0VUbXo0?= =?utf-8?B?TFJOQklMWVI4RE1leEwrby9ON2dJN1BEcysxZFZNYktzTEtmMndkSjVGT0lq?= =?utf-8?Q?gmcGi+x5FmC0eu/8AKPICZVtRgTEq12fYmelvmK?= X-OriginatorOrg: suse.com X-MS-Exchange-CrossTenant-Network-Message-Id: fa0363c0-6128-4339-bedb-08d95cc2d1cf X-MS-Exchange-CrossTenant-AuthSource: VI1PR04MB5600.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 11 Aug 2021 12:23:26.4398 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: f7a17af6-1c5c-4a36-aa8b-f5be247aa4ba X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: CP/VIA5UByil8OkSAx5kJMGcznv6rPWcMrxIgrh4liARRerDnIRL91oLyekSF9F4kfogyugfRA8vJhemWp7O5g== X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR04MB4351 X-ZohoMail-DKIM: pass (identity @suse.com) X-ZM-MESSAGEID: 1628684635841100001 Content-Type: text/plain; charset="utf-8" There's a fair amount of sub-cases (with some yet to be implemented), so a separate function seems warranted. Code moved gets slightly adjusted in a few places, e.g. replacing EXC_* by X86_EXC_* (such that EXC_* don't need to move as well; we want these to be phased out anyway). Signed-off-by: Jan Beulich --- a/tools/fuzz/x86_instruction_emulator/Makefile +++ b/tools/fuzz/x86_instruction_emulator/Makefile @@ -35,7 +35,7 @@ x86.h :=3D $(addprefix $(XEN_ROOT)/tools/i x86_emulate.h :=3D x86-emulate.h x86_emulate/x86_emulate.h $(x86.h) =20 OBJS :=3D fuzz-emul.o x86-emulate.o -OBJS +=3D x86_emulate/0f01.o +OBJS +=3D x86_emulate/0f01.o x86_emulate/0fae.o =20 # x86-emulate.c will be implicit for both x86-emulate.o x86-emulate-cov.o: x86_emulate/x86_emulate.c $(x86_emulate.h= ) x86_emulate/private.h --- a/tools/tests/x86_emulator/Makefile +++ b/tools/tests/x86_emulator/Makefile @@ -251,7 +251,7 @@ xop.h avx512f.h: simd-fma.c endif # 32-bit override =20 OBJS :=3D x86-emulate.o cpuid.o test_x86_emulator.o evex-disp8.o predicate= s.o wrappers.o -OBJS +=3D x86_emulate/0f01.o +OBJS +=3D x86_emulate/0f01.o x86_emulate/0fae.o =20 $(TARGET): $(OBJS) $(HOSTCC) $(HOSTCFLAGS) -o $@ $^ --- /dev/null +++ b/xen/arch/x86/x86_emulate/0fae.c @@ -0,0 +1,222 @@ +/*************************************************************************= ***** + * 0fae.c - helper for x86_emulate.c + * + * Generic x86 (32-bit and 64-bit) instruction decoder and emulator. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; If not, see . + */ + +#include "private.h" + +#if defined(__XEN__) && \ + (!defined(X86EMUL_NO_FPU) || !defined(X86EMUL_NO_MMX) || \ + !defined(X86EMUL_NO_SIMD)) +# include +#endif + +int x86emul_0fae(struct x86_emulate_state *s, + struct cpu_user_regs *regs, + struct operand *dst, + const struct operand *src, + struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops, + enum x86_emulate_fpu_type *fpu_type) +#define fpu_type (*fpu_type) /* for get_fpu() */ +{ + unsigned long cr4; + int rc; + + if ( !s->vex.opcx && (!s->vex.pfx || s->vex.pfx =3D=3D vex_66) ) + { + switch ( s->modrm_reg & 7 ) + { +#if !defined(X86EMUL_NO_FPU) || !defined(X86EMUL_NO_MMX) || \ + !defined(X86EMUL_NO_SIMD) + case 0: /* fxsave */ + case 1: /* fxrstor */ + generate_exception_if(s->vex.pfx, X86_EXC_UD); + vcpu_must_have(fxsr); + generate_exception_if(s->ea.type !=3D OP_MEM, X86_EXC_UD); + generate_exception_if(!is_aligned(s->ea.mem.seg, s->ea.mem.off= , 16, + ctxt, ops), + X86_EXC_GP, 0); + fail_if(!ops->blk); + s->op_bytes =3D +#ifdef __x86_64__ + !mode_64bit() ? offsetof(struct x86_fxsr, xmm[8]) : +#endif + sizeof(struct x86_fxsr); + if ( amd_like(ctxt) ) + { + uint64_t msr_val; + + /* Assume "normal" operation in case of missing hooks. */ + if ( !ops->read_cr || + ops->read_cr(4, &cr4, ctxt) !=3D X86EMUL_OKAY ) + cr4 =3D X86_CR4_OSFXSR; + if ( !ops->read_msr || + ops->read_msr(MSR_EFER, &msr_val, ctxt) !=3D X86EMUL_= OKAY ) + msr_val =3D 0; + if ( !(cr4 & X86_CR4_OSFXSR) || + (mode_64bit() && mode_ring0() && (msr_val & EFER_FFXS= E)) ) + s->op_bytes =3D offsetof(struct x86_fxsr, xmm[0]); + } + /* + * This could also be X86EMUL_FPU_mmx, but it shouldn't be + * X86EMUL_FPU_xmm, as we don't want CR4.OSFXSR checked. + */ + get_fpu(X86EMUL_FPU_fpu); + s->fpu_ctrl =3D true; + s->blk =3D s->modrm_reg & 1 ? blk_fxrstor : blk_fxsave; + if ( (rc =3D ops->blk(s->ea.mem.seg, s->ea.mem.off, NULL, + sizeof(struct x86_fxsr), ®s->eflags, + s, ctxt)) !=3D X86EMUL_OKAY ) + goto done; + break; +#endif /* X86EMUL_NO_{FPU,MMX,SIMD} */ + +#ifndef X86EMUL_NO_SIMD + case 2: /* ldmxcsr */ + generate_exception_if(s->vex.pfx, X86_EXC_UD); + vcpu_must_have(sse); + ldmxcsr: + generate_exception_if(src->type !=3D OP_MEM, X86_EXC_UD); + get_fpu(s->vex.opcx ? X86EMUL_FPU_ymm : X86EMUL_FPU_xmm); + generate_exception_if(src->val & ~mxcsr_mask, X86_EXC_GP, 0); + asm volatile ( "ldmxcsr %0" :: "m" (src->val) ); + break; + + case 3: /* stmxcsr */ + generate_exception_if(s->vex.pfx, X86_EXC_UD); + vcpu_must_have(sse); + stmxcsr: + generate_exception_if(dst->type !=3D OP_MEM, X86_EXC_UD); + get_fpu(s->vex.opcx ? X86EMUL_FPU_ymm : X86EMUL_FPU_xmm); + asm volatile ( "stmxcsr %0" : "=3Dm" (dst->val) ); + break; +#endif /* X86EMUL_NO_SIMD */ + + case 5: /* lfence */ + fail_if(s->modrm_mod !=3D 3); + generate_exception_if(s->vex.pfx, X86_EXC_UD); + vcpu_must_have(sse2); + asm volatile ( "lfence" ::: "memory" ); + break; + case 6: + if ( s->modrm_mod =3D=3D 3 ) /* mfence */ + { + generate_exception_if(s->vex.pfx, X86_EXC_UD); + vcpu_must_have(sse2); + asm volatile ( "mfence" ::: "memory" ); + break; + } + /* else clwb */ + fail_if(!s->vex.pfx); + vcpu_must_have(clwb); + fail_if(!ops->cache_op); + if ( (rc =3D ops->cache_op(x86emul_clwb, s->ea.mem.seg, s->ea.= mem.off, + ctxt)) !=3D X86EMUL_OKAY ) + goto done; + break; + case 7: + if ( s->modrm_mod =3D=3D 3 ) /* sfence */ + { + generate_exception_if(s->vex.pfx, X86_EXC_UD); + vcpu_must_have(mmxext); + asm volatile ( "sfence" ::: "memory" ); + break; + } + /* else clflush{,opt} */ + if ( !s->vex.pfx ) + vcpu_must_have(clflush); + else + vcpu_must_have(clflushopt); + fail_if(!ops->cache_op); + if ( (rc =3D ops->cache_op(s->vex.pfx ? x86emul_clflushopt + : x86emul_clflush, + s->ea.mem.seg, s->ea.mem.off, + ctxt)) !=3D X86EMUL_OKAY ) + goto done; + break; + default: + return X86EMUL_UNIMPLEMENTED; + } + } +#ifndef X86EMUL_NO_SIMD + else if ( s->vex.opcx && !s->vex.pfx ) + { + switch ( s->modrm_reg & 7 ) + { + case 2: /* vldmxcsr */ + generate_exception_if(s->vex.l || s->vex.reg !=3D 0xf, X86_EXC= _UD); + vcpu_must_have(avx); + goto ldmxcsr; + case 3: /* vstmxcsr */ + generate_exception_if(s->vex.l || s->vex.reg !=3D 0xf, X86_EXC= _UD); + vcpu_must_have(avx); + goto stmxcsr; + } + return X86EMUL_UNRECOGNIZED; + } +#endif /* !X86EMUL_NO_SIMD */ + else if ( !s->vex.opcx && s->vex.pfx =3D=3D vex_f3 ) + { + enum x86_segment seg; + struct segment_register sreg; + + fail_if(s->modrm_mod !=3D 3); + generate_exception_if((s->modrm_reg & 4) || !mode_64bit(), X86_EXC= _UD); + fail_if(!ops->read_cr); + if ( (rc =3D ops->read_cr(4, &cr4, ctxt)) !=3D X86EMUL_OKAY ) + goto done; + generate_exception_if(!(cr4 & X86_CR4_FSGSBASE), X86_EXC_UD); + seg =3D s->modrm_reg & 1 ? x86_seg_gs : x86_seg_fs; + fail_if(!ops->read_segment); + if ( (rc =3D ops->read_segment(seg, &sreg, ctxt)) !=3D X86EMUL_OKA= Y ) + goto done; + dst->reg =3D decode_gpr(regs, s->modrm_rm); + if ( !(s->modrm_reg & 2) ) + { + /* rd{f,g}sbase */ + dst->type =3D OP_REG; + dst->bytes =3D (s->op_bytes =3D=3D 8) ? 8 : 4; + dst->val =3D sreg.base; + } + else + { + /* wr{f,g}sbase */ + if ( s->op_bytes =3D=3D 8 ) + { + sreg.base =3D *dst->reg; + generate_exception_if(!is_canonical_address(sreg.base), + X86_EXC_GP, 0); + } + else + sreg.base =3D (uint32_t)*dst->reg; + fail_if(!ops->write_segment); + if ( (rc =3D ops->write_segment(seg, &sreg, ctxt)) !=3D X86EMU= L_OKAY ) + goto done; + } + } + else + { + ASSERT_UNREACHABLE(); + return X86EMUL_UNRECOGNIZED; + } + + rc =3D X86EMUL_OKAY; + + done: + return rc; +} --- a/xen/arch/x86/x86_emulate/Makefile +++ b/xen/arch/x86/x86_emulate/Makefile @@ -1 +1,2 @@ obj-y +=3D 0f01.o +obj-y +=3D 0fae.o --- a/xen/arch/x86/x86_emulate/private.h +++ b/xen/arch/x86/x86_emulate/private.h @@ -308,6 +308,29 @@ struct x86_emulate_state { #endif }; =20 +struct x86_fxsr { + uint16_t fcw; + uint16_t fsw; + uint8_t ftw, :8; + uint16_t fop; + union { + struct { + uint32_t offs; + uint16_t sel, :16; + }; + uint64_t addr; + } fip, fdp; + uint32_t mxcsr; + uint32_t mxcsr_mask; + struct { + uint8_t data[10]; + uint16_t :16, :16, :16; + } fpreg[8]; + uint64_t __attribute__ ((aligned(16))) xmm[16][2]; + uint64_t rsvd[6]; + uint64_t avl[6]; +}; + /* * Externally visible return codes from x86_emulate() are non-negative. * Use negative values for internal state change indicators from helpers @@ -397,6 +420,18 @@ in_protmode( (_cpl =3D=3D 0); \ }) =20 +static inline bool +_amd_like(const struct cpuid_policy *cp) +{ + return cp->x86_vendor & (X86_VENDOR_AMD | X86_VENDOR_HYGON); +} + +static inline bool +amd_like(const struct x86_emulate_ctxt *ctxt) +{ + return _amd_like(ctxt->cpuid); +} + #define vcpu_has_fpu() (ctxt->cpuid->basic.fpu) #define vcpu_has_sep() (ctxt->cpuid->basic.sep) #define vcpu_has_cx8() (ctxt->cpuid->basic.cx8) @@ -501,11 +536,52 @@ in_protmode( int x86emul_get_cpl(struct x86_emulate_ctxt *ctxt, const struct x86_emulate_ops *ops); =20 +int x86emul_get_fpu(enum x86_emulate_fpu_type type, + struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops); + +#define get_fpu(type) \ +do { \ + rc =3D x86emul_get_fpu(fpu_type =3D (type), ctxt, ops); \ + if ( rc ) goto done; \ +} while (0) + int x86emul_0f01(struct x86_emulate_state *s, struct cpu_user_regs *regs, struct operand *dst, struct x86_emulate_ctxt *ctxt, const struct x86_emulate_ops *ops); +int x86emul_0fae(struct x86_emulate_state *s, + struct cpu_user_regs *regs, + struct operand *dst, + const struct operand *src, + struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops, + enum x86_emulate_fpu_type *fpu_type); + +static inline bool is_aligned(enum x86_segment seg, unsigned long offs, + unsigned int size, struct x86_emulate_ctxt *= ctxt, + const struct x86_emulate_ops *ops) +{ + struct segment_register reg; + + /* Expecting powers of two only. */ + ASSERT(!(size & (size - 1))); + + if ( mode_64bit() && seg < x86_seg_fs ) + memset(®, 0, sizeof(reg)); + else + { + /* No alignment checking when we have no way to read segment data.= */ + if ( !ops->read_segment ) + return true; + + if ( ops->read_segment(seg, ®, ctxt) !=3D X86EMUL_OKAY ) + return false; + } + + return !((reg.base + offs) & (size - 1)); +} =20 static inline bool umip_active(struct x86_emulate_ctxt *ctxt, const struct x86_emulate_ops *ops) --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -695,29 +695,6 @@ typedef union { uint32_t data32[16]; } mmval_t; =20 -struct x86_fxsr { - uint16_t fcw; - uint16_t fsw; - uint8_t ftw, :8; - uint16_t fop; - union { - struct { - uint32_t offs; - uint16_t sel, :16; - }; - uint64_t addr; - } fip, fdp; - uint32_t mxcsr; - uint32_t mxcsr_mask; - struct { - uint8_t data[10]; - uint16_t :16, :16, :16; - } fpreg[8]; - uint64_t __attribute__ ((aligned(16))) xmm[16][2]; - uint64_t rsvd[6]; - uint64_t avl[6]; -}; - /* * While proper alignment gets specified above, this doesn't get honored by * the compiler for automatic variables. Use this helper to instantiate a @@ -1063,7 +1040,7 @@ do { ops->write_segment(x86_seg_cs, cs, ctxt); \ }) =20 -static int _get_fpu( +int x86emul_get_fpu( enum x86_emulate_fpu_type type, struct x86_emulate_ctxt *ctxt, const struct x86_emulate_ops *ops) @@ -1102,7 +1079,7 @@ static int _get_fpu( break; } =20 - rc =3D ops->get_fpu(type, ctxt); + rc =3D (ops->get_fpu)(type, ctxt); =20 if ( rc =3D=3D X86EMUL_OKAY ) { @@ -1146,12 +1123,6 @@ static int _get_fpu( return rc; } =20 -#define get_fpu(type) \ -do { \ - rc =3D _get_fpu(fpu_type =3D (type), ctxt, ops); \ - if ( rc ) goto done; \ -} while (0) - static void put_fpu( enum x86_emulate_fpu_type type, bool failed_late, @@ -1556,18 +1527,6 @@ static int ioport_access_check( return rc; } =20 -static bool -_amd_like(const struct cpuid_policy *cp) -{ - return cp->x86_vendor & (X86_VENDOR_AMD | X86_VENDOR_HYGON); -} - -static bool -amd_like(const struct x86_emulate_ctxt *ctxt) -{ - return _amd_like(ctxt->cpuid); -} - /* Initialise output state in x86_emulate_ctxt */ static void init_context(struct x86_emulate_ctxt *ctxt) { @@ -1980,30 +1939,6 @@ static unsigned int decode_disp8scale(en } \ } while ( false ) =20 -static bool is_aligned(enum x86_segment seg, unsigned long offs, - unsigned int size, struct x86_emulate_ctxt *ctxt, - const struct x86_emulate_ops *ops) -{ - struct segment_register reg; - - /* Expecting powers of two only. */ - ASSERT(!(size & (size - 1))); - - if ( mode_64bit() && seg < x86_seg_fs ) - memset(®, 0, sizeof(reg)); - else - { - /* No alignment checking when we have no way to read segment data.= */ - if ( !ops->read_segment ) - return true; - - if ( ops->read_segment(seg, ®, ctxt) !=3D X86EMUL_OKAY ) - return false; - } - - return !((reg.base + offs) & (size - 1)); -} - static bool is_branch_step(struct x86_emulate_ctxt *ctxt, const struct x86_emulate_ops *ops) { @@ -3346,7 +3281,8 @@ x86_emulate( #ifndef X86EMUL_NO_SIMD /* With a memory operand, fetch the mask register in use (if any). */ if ( ea.type =3D=3D OP_MEM && evex.opmsk && - _get_fpu(fpu_type =3D X86EMUL_FPU_opmask, ctxt, ops) =3D=3D X86EM= UL_OKAY ) + x86emul_get_fpu(fpu_type =3D X86EMUL_FPU_opmask, + ctxt, ops) =3D=3D X86EMUL_OKAY ) { uint8_t *stb =3D get_stub(stub); =20 @@ -3369,7 +3305,7 @@ x86_emulate( =20 if ( fpu_type =3D=3D X86EMUL_FPU_opmask ) { - /* Squash (side) effects of the _get_fpu() above. */ + /* Squash (side) effects of the x86emul_get_fpu() above. */ x86_emul_reset_event(ctxt); put_fpu(X86EMUL_FPU_opmask, false, state, ctxt, ops); fpu_type =3D X86EMUL_FPU_none; @@ -7434,173 +7370,14 @@ x86_emulate( emulate_2op_SrcV_nobyte("bts", src, dst, _regs.eflags); break; =20 - case X86EMUL_OPC(0x0f, 0xae): case X86EMUL_OPC_66(0x0f, 0xae): /* Grp1= 5 */ - switch ( modrm_reg & 7 ) - { -#if !defined(X86EMUL_NO_FPU) || !defined(X86EMUL_NO_MMX) || \ - !defined(X86EMUL_NO_SIMD) - case 0: /* fxsave */ - case 1: /* fxrstor */ - generate_exception_if(vex.pfx, EXC_UD); - vcpu_must_have(fxsr); - generate_exception_if(ea.type !=3D OP_MEM, EXC_UD); - generate_exception_if(!is_aligned(ea.mem.seg, ea.mem.off, 16, - ctxt, ops), - EXC_GP, 0); - fail_if(!ops->blk); - op_bytes =3D -#ifdef __x86_64__ - !mode_64bit() ? offsetof(struct x86_fxsr, xmm[8]) : -#endif - sizeof(struct x86_fxsr); - if ( amd_like(ctxt) ) - { - /* Assume "normal" operation in case of missing hooks. */ - if ( !ops->read_cr || - ops->read_cr(4, &cr4, ctxt) !=3D X86EMUL_OKAY ) - cr4 =3D X86_CR4_OSFXSR; - if ( !ops->read_msr || - ops->read_msr(MSR_EFER, &msr_val, ctxt) !=3D X86EMUL_= OKAY ) - msr_val =3D 0; - if ( !(cr4 & X86_CR4_OSFXSR) || - (mode_64bit() && mode_ring0() && (msr_val & EFER_FFXS= E)) ) - op_bytes =3D offsetof(struct x86_fxsr, xmm[0]); - } - /* - * This could also be X86EMUL_FPU_mmx, but it shouldn't be - * X86EMUL_FPU_xmm, as we don't want CR4.OSFXSR checked. - */ - get_fpu(X86EMUL_FPU_fpu); - state->fpu_ctrl =3D true; - state->blk =3D modrm_reg & 1 ? blk_fxrstor : blk_fxsave; - if ( (rc =3D ops->blk(ea.mem.seg, ea.mem.off, NULL, - sizeof(struct x86_fxsr), &_regs.eflags, - state, ctxt)) !=3D X86EMUL_OKAY ) - goto done; - break; -#endif /* X86EMUL_NO_{FPU,MMX,SIMD} */ - -#ifndef X86EMUL_NO_SIMD - case 2: /* ldmxcsr */ - generate_exception_if(vex.pfx, EXC_UD); - vcpu_must_have(sse); - ldmxcsr: - generate_exception_if(src.type !=3D OP_MEM, EXC_UD); - get_fpu(vex.opcx ? X86EMUL_FPU_ymm : X86EMUL_FPU_xmm); - generate_exception_if(src.val & ~mxcsr_mask, EXC_GP, 0); - asm volatile ( "ldmxcsr %0" :: "m" (src.val) ); - break; - - case 3: /* stmxcsr */ - generate_exception_if(vex.pfx, EXC_UD); - vcpu_must_have(sse); - stmxcsr: - generate_exception_if(dst.type !=3D OP_MEM, EXC_UD); - get_fpu(vex.opcx ? X86EMUL_FPU_ymm : X86EMUL_FPU_xmm); - asm volatile ( "stmxcsr %0" : "=3Dm" (dst.val) ); - break; -#endif /* X86EMUL_NO_SIMD */ - - case 5: /* lfence */ - fail_if(modrm_mod !=3D 3); - generate_exception_if(vex.pfx, EXC_UD); - vcpu_must_have(sse2); - asm volatile ( "lfence" ::: "memory" ); - break; - case 6: - if ( modrm_mod =3D=3D 3 ) /* mfence */ - { - generate_exception_if(vex.pfx, EXC_UD); - vcpu_must_have(sse2); - asm volatile ( "mfence" ::: "memory" ); - break; - } - /* else clwb */ - fail_if(!vex.pfx); - vcpu_must_have(clwb); - fail_if(!ops->cache_op); - if ( (rc =3D ops->cache_op(x86emul_clwb, ea.mem.seg, ea.mem.of= f, - ctxt)) !=3D X86EMUL_OKAY ) - goto done; - break; - case 7: - if ( modrm_mod =3D=3D 3 ) /* sfence */ - { - generate_exception_if(vex.pfx, EXC_UD); - vcpu_must_have(mmxext); - asm volatile ( "sfence" ::: "memory" ); - break; - } - /* else clflush{,opt} */ - if ( !vex.pfx ) - vcpu_must_have(clflush); - else - vcpu_must_have(clflushopt); - fail_if(!ops->cache_op); - if ( (rc =3D ops->cache_op(vex.pfx ? x86emul_clflushopt - : x86emul_clflush, - ea.mem.seg, ea.mem.off, - ctxt)) !=3D X86EMUL_OKAY ) - goto done; - break; - default: - goto unimplemented_insn; - } - break; - + case X86EMUL_OPC(0x0f, 0xae): /* Grp15 */ + case X86EMUL_OPC_66(0x0f, 0xae): + case X86EMUL_OPC_F3(0x0f, 0xae): #ifndef X86EMUL_NO_SIMD - - case X86EMUL_OPC_VEX(0x0f, 0xae): /* Grp15 */ - switch ( modrm_reg & 7 ) - { - case 2: /* vldmxcsr */ - generate_exception_if(vex.l || vex.reg !=3D 0xf, EXC_UD); - vcpu_must_have(avx); - goto ldmxcsr; - case 3: /* vstmxcsr */ - generate_exception_if(vex.l || vex.reg !=3D 0xf, EXC_UD); - vcpu_must_have(avx); - goto stmxcsr; - } - goto unrecognized_insn; - -#endif /* !X86EMUL_NO_SIMD */ - - case X86EMUL_OPC_F3(0x0f, 0xae): /* Grp15 */ - fail_if(modrm_mod !=3D 3); - generate_exception_if((modrm_reg & 4) || !mode_64bit(), EXC_UD); - fail_if(!ops->read_cr); - if ( (rc =3D ops->read_cr(4, &cr4, ctxt)) !=3D X86EMUL_OKAY ) - goto done; - generate_exception_if(!(cr4 & X86_CR4_FSGSBASE), EXC_UD); - seg =3D modrm_reg & 1 ? x86_seg_gs : x86_seg_fs; - fail_if(!ops->read_segment); - if ( (rc =3D ops->read_segment(seg, &sreg, ctxt)) !=3D X86EMUL_OKA= Y ) - goto done; - dst.reg =3D decode_gpr(&_regs, modrm_rm); - if ( !(modrm_reg & 2) ) - { - /* rd{f,g}sbase */ - dst.type =3D OP_REG; - dst.bytes =3D (op_bytes =3D=3D 8) ? 8 : 4; - dst.val =3D sreg.base; - } - else - { - /* wr{f,g}sbase */ - if ( op_bytes =3D=3D 8 ) - { - sreg.base =3D *dst.reg; - generate_exception_if(!is_canonical_address(sreg.base), - EXC_GP, 0); - } - else - sreg.base =3D (uint32_t)*dst.reg; - fail_if(!ops->write_segment); - if ( (rc =3D ops->write_segment(seg, &sreg, ctxt)) !=3D X86EMU= L_OKAY ) - goto done; - } - break; + case X86EMUL_OPC_VEX(0x0f, 0xae): +#endif + rc =3D x86emul_0fae(state, &_regs, &dst, &src, ctxt, ops, &fpu_typ= e); + goto dispatch_from_helper; =20 case X86EMUL_OPC(0x0f, 0xaf): /* imul */ emulate_2op_SrcV_srcmem("imul", src, dst, _regs.eflags); @@ -10516,7 +10293,7 @@ x86_emulate( goto unrecognized_insn; =20 default: - unimplemented_insn: + unimplemented_insn: __maybe_unused; rc =3D X86EMUL_UNIMPLEMENTED; goto done; unrecognized_insn: From nobody Thu May 2 08:52:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; arc=pass (i=1 dmarc=pass fromdomain=suse.com); dmarc=pass(p=quarantine dis=none) header.from=suse.com ARC-Seal: i=2; a=rsa-sha256; t=1628684650; cv=pass; d=zohomail.com; s=zohoarc; b=Uzia9eHRH2r2OaoKf1ZN+4sAHa9xSY+L4OJ/YM84nphQ48j5EDhXZ/RzS8M552xQxsxFQ5KtaV4JIiOFrg40IcIwSqZrsuJnXfOD3O+I8Abc6qC8y1BvPgRfwUNrWxxwGntjYJw3T8+YVLaG7MKH4BUsnJVJouCgdUvhEdtt3qg= ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1628684650; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=SaQ/k4jYzi7swFYK8gZr5pavMGbFr3WAaLIuEQsIC24=; b=fZ67sBz/U2ULyAEYaxKJx1atkeu6rLwWBvE7WYKWYQwS4OEj8hV0AF93LUsC+28/5x35LCpZ8cl31/Khw8xHUk/ijMe7ZtiBoMtMYBfLqGGjDc1y2VzxuQeQXwh/3LUfwnsyQ3ZZqRS89cOZlisn54jr0DkL8r1t6SddFqllZSg= ARC-Authentication-Results: i=2; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; arc=pass (i=1 dmarc=pass fromdomain=suse.com); dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1628684650778296.40742819089337; Wed, 11 Aug 2021 05:24:10 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.165985.303151 (Exim 4.92) (envelope-from ) id 1mDnH0-0007BD-6K; Wed, 11 Aug 2021 12:23:54 +0000 Received: by outflank-mailman (output) from mailman id 165985.303151; Wed, 11 Aug 2021 12:23:54 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1mDnH0-0007B3-3C; Wed, 11 Aug 2021 12:23:54 +0000 Received: by outflank-mailman (input) for mailman id 165985; Wed, 11 Aug 2021 12:23:52 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1mDnGy-0006zb-9G for xen-devel@lists.xenproject.org; Wed, 11 Aug 2021 12:23:52 +0000 Received: from de-smtp-delivery-102.mimecast.com (unknown [194.104.109.102]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id fb735281-fa9e-11eb-a06d-12813bfff9fa; Wed, 11 Aug 2021 12:23:50 +0000 (UTC) Received: from EUR05-AM6-obe.outbound.protection.outlook.com (mail-am6eur05lp2109.outbound.protection.outlook.com [104.47.18.109]) (Using TLS) by relay.mimecast.com with ESMTP id de-mta-17-JjQl8DwbPcmtETWA6azgwA-1; Wed, 11 Aug 2021 14:23:48 +0200 Received: from VI1PR04MB5600.eurprd04.prod.outlook.com (2603:10a6:803:e7::16) by VI1PR04MB4351.eurprd04.prod.outlook.com (2603:10a6:803:49::33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4415.14; Wed, 11 Aug 2021 12:23:47 +0000 Received: from VI1PR04MB5600.eurprd04.prod.outlook.com ([fe80::99d3:99cd:8adf:3eea]) by VI1PR04MB5600.eurprd04.prod.outlook.com ([fe80::99d3:99cd:8adf:3eea%5]) with mapi id 15.20.4394.025; Wed, 11 Aug 2021 12:23:47 +0000 Received: from [10.156.60.236] (37.24.206.209) by AM3PR03CA0073.eurprd03.prod.outlook.com (2603:10a6:207:5::31) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4415.16 via Frontend Transport; Wed, 11 Aug 2021 12:23:46 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: fb735281-fa9e-11eb-a06d-12813bfff9fa DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=mimecast20200619; t=1628684629; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=SaQ/k4jYzi7swFYK8gZr5pavMGbFr3WAaLIuEQsIC24=; b=HXMcWEl93tut668JRv8PNyx0gmfg2wNEVwBb3JDPn2iYwehuWezWcPQuJFb3BoY8oeFIQQ FVe+VCrGW4pN/T3lqzwE66jkIUGWEi1mxIkCUk2n3rYzas1T+XHaMPx+VnMko5y/64ubh/ GR8NoKlkXTux+oZnqfGfHVXlZVsjroA= X-MC-Unique: JjQl8DwbPcmtETWA6azgwA-1 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=fYo1X8LMAyc/bZjnX0HaRb5KmMPkfcq/8KZfeWEc0a06sYVweRKmTgMK7ZlOQ/A8ROaeeVwJAVEREvPVs1fAHwe8MnUQVJV8PCIlntvvSx9IudslMXXERvZu5Yi8TOPT0jxFfsqLihiaszI3QUjAB4uLFaInr2nmipNmFgTMnphk+aTExDetwNsSPNQ0Nio/0hQPjxzSo6OaHjpQNaKo0ljgB0aUImzUrDLHPAYnbY8e8oijeLJJA0GmSWUe3xKcOJi9XVEhDR29Fef3vB3ubY7Ik7J0X9LUB3U3c++TQ3ki9/dO7QicC78queVohzmk5fBqw1hvl0Au+7l2p1btHw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=SaQ/k4jYzi7swFYK8gZr5pavMGbFr3WAaLIuEQsIC24=; b=FO9pWYv5xqruIRtLg4bQVu17t8r7H3hg9YjIJSvym6q3dbE2kMmH0kfAW4Fo2Xsgnu19gmXsliBbHRBCVIRka4nmHZcS62042XRpsPz1nr8sqoWQYrjnGbdjKNT32Cvo9jBV9t+aZFE9Pan3EAlyyBuQyLhREn0x61OMpPNAU63A3kvxeEMj0INJOfAWsBxPZ05YSuM1kxgEPbXTlaVNZz93naeq6SGSTRal0O4T0hRIQDpX4dBOZ8ttvi9b/NqifLfHoF67TxO3Foh6EPtj9lktAAtyUztAd54J7Yzqr34BMYDrNIS6QHkf504iDge+UanyALBJMIOfqJxokaLuGQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=suse.com; dmarc=pass action=none header.from=suse.com; dkim=pass header.d=suse.com; arc=none Authentication-Results: citrix.com; dkim=none (message not signed) header.d=none;citrix.com; dmarc=none action=none header.from=suse.com; Subject: [PATCH 3/7] x86emul: split off opcode 0fc7 handling From: Jan Beulich To: "xen-devel@lists.xenproject.org" Cc: Andrew Cooper , Wei Liu , =?UTF-8?Q?Roger_Pau_Monn=c3=a9?= References: Message-ID: Date: Wed, 11 Aug 2021 14:23:45 +0200 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Thunderbird/78.12.0 In-Reply-To: Content-Language: en-US Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: AM3PR03CA0073.eurprd03.prod.outlook.com (2603:10a6:207:5::31) To VI1PR04MB5600.eurprd04.prod.outlook.com (2603:10a6:803:e7::16) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 19aaafc8-6827-4304-7b59-08d95cc2de29 X-MS-TrafficTypeDiagnostic: VI1PR04MB4351: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:989; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: K6CuchdmD+nQxWNonTqd4dMgQr0hbEeCgT4HKtcg2185R6uYe4Pj1aX0VLoMuHG4aVK1VxHWHgEUz20ErTvAat9kt4dBJ3lNqG2HSAh5eXfsnYsmroO4kZ6VcMY0eEDWm1ndRWeaAKN7inB0Ez8ajoDigM/cMul4TX0ij3OZZnJxpKntGzvjQi7oFgkRzyz0uuzVxBuZMJ87TrLl9E2XLnXL6la4LSXw3i3XpxiNfIG8GnLRksFRvgXzgRZlx3MLK2cvM238U+m5bpMoV1ClTwrEpcFbB8F0cu0oB0nNX7EDBqVWDeHmnMhd5pBbELWLdLjJuv/IE8B6MMJ35bc7DnGcIo5Ebd8nHkmhyte7OKKy7LatVnFiws5F59Mpffa3phc5rVRiUTVGu0GgnIPRTT/kdsG4LPtvbn4vNJ1yGFaV/9ijAlBBNdeStVD/yQBgcruM/IKR/3N3c2RBGLlKr0f2LoUoeZXLalNgBjQBbBcaQYpUYFM+eQWf4dY/N3D0GcJ5fNuaKVE4XH4Cdj3116SC9dfqoDpPwZfggTdIRRBbHF/R+ml91Am9GuBLYoNeCwNvoYTMQtq3cTpIstUBLvMvVafYa956GlgTiqbNrMRmd0of8MopWyr7qzl2q59tDpUCxfjYc+9kwTklsV+GdHo1RHNcEmodKV9uWc62jwQhtuC0Mbcxt9rkQTXWTeB3wloOxhedH7zOHaZt3HdE8O/XQq6xjKSVKx87iEtaHx0/Gjt88zCRc+YFCc6KLZxsSKukhaiU81vZNCDG4wJyka0SZrb7iFY4MVMT7o3UJ4l8wb981s9ChCXBwnwFjyEaPz+pgSNrcVOyq2BW2PGANg== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:VI1PR04MB5600.eurprd04.prod.outlook.com;PTR:;CAT:NONE;SFS:(366004)(6486002)(8936002)(316002)(16576012)(2616005)(956004)(8676002)(5660300002)(6916009)(66946007)(36756003)(30864003)(31686004)(2906002)(86362001)(31696002)(186003)(26005)(66556008)(83380400001)(54906003)(508600001)(4326008)(38100700002)(66476007)(2004002)(43740500002)(45980500001);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?SlRzQzY3dlVYcVpsdkRGc1orQXE2R21ScCs3V1BQWnkyeURYQkVUNkoxbk51?= =?utf-8?B?dUFiMEszczdRcFBENXZoeTBnTzV4STdDdHlUR3J6bUw2dkFNZkU4UTFjaGFM?= =?utf-8?B?Q3Vza2JSQkk3YWw3b1cvMGZqUWVPd29yTGF0dWk4UkZIWmwwcWRQN0lyMkNZ?= =?utf-8?B?bC9wN2RUbW5RdTFTeTBZV1dRSFRPeFVxR1hYeDd5QzRhSlY3ZkNtdE93L2VI?= =?utf-8?B?Y1NtcDRJSm0wK3BLVHJWUG1KdGNuZkVGRGJUcVVsZmp3c3dUbGRZK0JsTlRK?= =?utf-8?B?UEdlRVdOVThzdjdzZjI1VTVMM0ZVUzMvdmVRUnp6bmFVcVNMOWp1UTBldkVu?= =?utf-8?B?NE1JczJrMzNtYnNEQjVCeURxYlREYURuNkcybEovV1FPbURrZkdjdTBWWXU1?= =?utf-8?B?amhIamloS1B1SEd1MEtCb2lwVVoxeklLSVp4RWJhcVdjY1RiUWhBRGZnSk1r?= =?utf-8?B?SXNYck9DWFhocUx3c3gxbkI4aS9FZS9TM0RtVUxtcEg0U0VHQndOUTBTOFZz?= =?utf-8?B?b0hLcC83TTJsUnZNazZwd1FPd2JFTzlsMjVTUlZFOHlQZEZXdEM3MGF4MVd6?= =?utf-8?B?Q0dOOWdDOStWaDFOQ0pzYUJpNHd1Q25QNkVWSCt6NVFCWTNqNVl5NGZLYXIz?= =?utf-8?B?ekFCMUdTcGh0dWE2dUdpck55WDdDZEQwUlROMUpMSElhczhyMlUrWTBjdWVY?= =?utf-8?B?dmVTSC9lcHgrMmcySDU0akdUQWthaW5WNTMzemRxM1dhNkMzU0dtR09yRUZO?= =?utf-8?B?Ti95ZXR6Ni8xa0RrOUdaSTByY0FMWXByUXZTczhZSDBGL0JHQ2k3VHhJYjJv?= =?utf-8?B?dlVBeEVCZ0tHK2hWVmt3YThVQWxZM1hnZ05zbmtLdWJJcGE4a0diVCtkWEc3?= =?utf-8?B?aDdyWVMyYjNyeXpMSEd5L1pzNld3Q2Q5MGpEbFVac1NWdU8zS3d1NSsvVjNR?= =?utf-8?B?cjFnRnYrVVZ3b0hOYVF1VkhrT0FpUFd3czlVa0lNZHVLV3RiYlVWeHIxUk0w?= =?utf-8?B?V3lsakV6ZEk2a01VanVPTEtxL2NmWThuZ0JJTU9XRGJXL3UyRXFpRmJteEls?= =?utf-8?B?cWdDQkVUNXJiSjBaQk5uSXFsMWpmZmpMcWF1a21GazV0ZXV1ZGRuUWFuK21H?= =?utf-8?B?NzJyMEthTnVnYXg3c2xTRzMzYlFQSm4zTjhacVdhWWZZSUc2UlhXODRBUHNz?= =?utf-8?B?Q3dreFNDc0x5MTU4SFBoTTFJSUJmVTFOREVlM2NDSXdaMTJzdWZKcm1Cdm5y?= =?utf-8?B?SzNkaEE2ZDc2VnFuRTlNTU5LWGZ6d3oyd1RWbCtVMU9lVmZ4Qis4Wm1DeUFD?= =?utf-8?B?WWI5ZVFoV09KU0ZVUXNWQ0o3bGp5OXh1VG5ybS84a285d0ZKcURHLzJuS0JS?= =?utf-8?B?WTlxMTgxREtpYU5KTThLWHd2QU4xRW5kZ0p3V3FNZGhCM01obEZ1TVJCUkEw?= =?utf-8?B?YU1KQVU5MUZIaHp6empyc3d5ZXNXakhLYWNpRjh6U3ZWTTIrSWVsMXptcWEv?= =?utf-8?B?am1pUjMvVy9JTGpESG9jbFN5alNxQmV3SW56bHduVGgvbS9Ud21TREsrcDRr?= =?utf-8?B?dEI5dThUMWxiR3Q5WmVDZmlxVHgvNW85UWlvZUNlSnZtNTdHL0pQTXh0L21i?= =?utf-8?B?SUtTUW9jRlFIeG5UQURyOGpQcUtkVDlGaGZUWEg1elYzbEo3ZFQ0WVhsV2lq?= =?utf-8?B?Q2tyL1ErSTdBM0N0aUJLa0VlQmZ5SU1kR1YwUDhMd3JNdXd0cXl3NWJUTHVM?= =?utf-8?Q?v+krhUPE8P574trivqliYWYn8FD0ND6SymO3Tnu?= X-OriginatorOrg: suse.com X-MS-Exchange-CrossTenant-Network-Message-Id: 19aaafc8-6827-4304-7b59-08d95cc2de29 X-MS-Exchange-CrossTenant-AuthSource: VI1PR04MB5600.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 11 Aug 2021 12:23:47.2566 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: f7a17af6-1c5c-4a36-aa8b-f5be247aa4ba X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: Si3MwN+hmv/pp73idfJMXX7Dxw8QaVu8XhF/ectFGXsNzMmy/rynNOblZ0ICdZnGtQaTSHSBlXIMrMd/c2L+Qw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR04MB4351 X-ZohoMail-DKIM: pass (identity @suse.com) X-ZM-MESSAGEID: 1628684652029100001 Content-Type: text/plain; charset="utf-8" There's a fair amount of sub-cases (with some yet to be implemented), so a separate function seems warranted. Code moved gets slightly adjusted in a few places, e.g. replacing EXC_* by X86_EXC_* (such that EXC_* don't need to move as well; we want these to be phased out anyway). Signed-off-by: Jan Beulich --- a/tools/fuzz/x86_instruction_emulator/Makefile +++ b/tools/fuzz/x86_instruction_emulator/Makefile @@ -35,7 +35,7 @@ x86.h :=3D $(addprefix $(XEN_ROOT)/tools/i x86_emulate.h :=3D x86-emulate.h x86_emulate/x86_emulate.h $(x86.h) =20 OBJS :=3D fuzz-emul.o x86-emulate.o -OBJS +=3D x86_emulate/0f01.o x86_emulate/0fae.o +OBJS +=3D x86_emulate/0f01.o x86_emulate/0fae.o x86_emulate/0fc7.o =20 # x86-emulate.c will be implicit for both x86-emulate.o x86-emulate-cov.o: x86_emulate/x86_emulate.c $(x86_emulate.h= ) x86_emulate/private.h --- a/tools/tests/x86_emulator/Makefile +++ b/tools/tests/x86_emulator/Makefile @@ -251,7 +251,7 @@ xop.h avx512f.h: simd-fma.c endif # 32-bit override =20 OBJS :=3D x86-emulate.o cpuid.o test_x86_emulator.o evex-disp8.o predicate= s.o wrappers.o -OBJS +=3D x86_emulate/0f01.o x86_emulate/0fae.o +OBJS +=3D x86_emulate/0f01.o x86_emulate/0fae.o x86_emulate/0fc7.o =20 $(TARGET): $(OBJS) $(HOSTCC) $(HOSTCFLAGS) -o $@ $^ --- /dev/null +++ b/xen/arch/x86/x86_emulate/0fc7.c @@ -0,0 +1,210 @@ +/*************************************************************************= ***** + * 0fc7.c - helper for x86_emulate.c + * + * Generic x86 (32-bit and 64-bit) instruction decoder and emulator. + * + * Copyright (c) 2005-2007 Keir Fraser + * Copyright (c) 2005-2007 XenSource Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; If not, see . + */ + +#include "private.h" + +/* Avoid namespace pollution. */ +#undef cmpxchg + +int x86emul_0fc7(struct x86_emulate_state *s, + struct cpu_user_regs *regs, + struct operand *dst, + struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops, + mmval_t *mmvalp) +{ + int rc; + + if ( s->ea.type =3D=3D OP_REG ) + { + bool __maybe_unused carry; + + switch ( s->modrm_reg & 7 ) + { + default: + return X86EMUL_UNRECOGNIZED; + + case 6: /* rdrand */ +#ifdef HAVE_AS_RDRAND + generate_exception_if(s->vex.pfx >=3D vex_f3, X86_EXC_UD); + host_and_vcpu_must_have(rdrand); + *dst =3D s->ea; + switch ( s->op_bytes ) + { + case 2: + asm ( "rdrand %w0" ASM_FLAG_OUT(, "; setc %1") + : "=3Dr" (dst->val), ASM_FLAG_OUT("=3D@ccc", "=3Dqm"= ) (carry) ); + break; + default: +# ifdef __x86_64__ + asm ( "rdrand %k0" ASM_FLAG_OUT(, "; setc %1") + : "=3Dr" (dst->val), ASM_FLAG_OUT("=3D@ccc", "=3Dqm"= ) (carry) ); + break; + case 8: +# endif + asm ( "rdrand %0" ASM_FLAG_OUT(, "; setc %1") + : "=3Dr" (dst->val), ASM_FLAG_OUT("=3D@ccc", "=3Dqm"= ) (carry) ); + break; + } + regs->eflags &=3D ~EFLAGS_MASK; + if ( carry ) + regs->eflags |=3D X86_EFLAGS_CF; + break; +#else + return X86EMUL_UNIMPLEMENTED; +#endif + + case 7: /* rdseed / rdpid */ + if ( s->vex.pfx =3D=3D vex_f3 ) /* rdpid */ + { + uint64_t msr_val; + + generate_exception_if(s->ea.type !=3D OP_REG, X86_EXC_UD); + vcpu_must_have(rdpid); + fail_if(!ops->read_msr); + if ( (rc =3D ops->read_msr(MSR_TSC_AUX, &msr_val, + ctxt)) !=3D X86EMUL_OKAY ) + goto done; + *dst =3D s->ea; + dst->val =3D msr_val; + dst->bytes =3D 4; + break; + } +#ifdef HAVE_AS_RDSEED + generate_exception_if(s->vex.pfx >=3D vex_f3, X86_EXC_UD); + host_and_vcpu_must_have(rdseed); + *dst =3D s->ea; + switch ( s->op_bytes ) + { + case 2: + asm ( "rdseed %w0" ASM_FLAG_OUT(, "; setc %1") + : "=3Dr" (dst->val), ASM_FLAG_OUT("=3D@ccc", "=3Dqm"= ) (carry) ); + break; + default: +# ifdef __x86_64__ + asm ( "rdseed %k0" ASM_FLAG_OUT(, "; setc %1") + : "=3Dr" (dst->val), ASM_FLAG_OUT("=3D@ccc", "=3Dqm"= ) (carry) ); + break; + case 8: +# endif + asm ( "rdseed %0" ASM_FLAG_OUT(, "; setc %1") + : "=3Dr" (dst->val), ASM_FLAG_OUT("=3D@ccc", "=3Dqm"= ) (carry) ); + break; + } + regs->eflags &=3D ~EFLAGS_MASK; + if ( carry ) + regs->eflags |=3D X86_EFLAGS_CF; + break; +#endif + } + } + else + { + union { + uint32_t u32[2]; + uint64_t u64[2]; + } *old, *aux; + + /* cmpxchg8b/cmpxchg16b */ + generate_exception_if((s->modrm_reg & 7) !=3D 1, X86_EXC_UD); + fail_if(!ops->cmpxchg); + if ( s->rex_prefix & REX_W ) + { + host_and_vcpu_must_have(cx16); + generate_exception_if(!is_aligned(s->ea.mem.seg, s->ea.mem.off= , 16, + ctxt, ops), + X86_EXC_GP, 0); + s->op_bytes =3D 16; + } + else + { + vcpu_must_have(cx8); + s->op_bytes =3D 8; + } + + old =3D container_of(&mmvalp->ymm[0], typeof(*old), u64[0]); + aux =3D container_of(&mmvalp->ymm[2], typeof(*aux), u64[0]); + + /* Get actual old value. */ + if ( (rc =3D ops->read(s->ea.mem.seg, s->ea.mem.off, old, s->op_by= tes, + ctxt)) !=3D X86EMUL_OKAY ) + goto done; + + /* Get expected value. */ + if ( s->op_bytes =3D=3D 8 ) + { + aux->u32[0] =3D regs->eax; + aux->u32[1] =3D regs->edx; + } + else + { + aux->u64[0] =3D regs->r(ax); + aux->u64[1] =3D regs->r(dx); + } + + if ( memcmp(old, aux, s->op_bytes) ) + { + cmpxchgNb_failed: + /* Expected !=3D actual: store actual to rDX:rAX and clear ZF.= */ + regs->r(ax) =3D s->op_bytes =3D=3D 8 ? old->u32[0] : old->u64[= 0]; + regs->r(dx) =3D s->op_bytes =3D=3D 8 ? old->u32[1] : old->u64[= 1]; + regs->eflags &=3D ~X86_EFLAGS_ZF; + } + else + { + /* + * Expected =3D=3D actual: Get proposed value, attempt atomic = cmpxchg + * and set ZF if successful. + */ + if ( s->op_bytes =3D=3D 8 ) + { + aux->u32[0] =3D regs->ebx; + aux->u32[1] =3D regs->ecx; + } + else + { + aux->u64[0] =3D regs->r(bx); + aux->u64[1] =3D regs->r(cx); + } + + switch ( rc =3D ops->cmpxchg(s->ea.mem.seg, s->ea.mem.off, old= , aux, + s->op_bytes, s->lock_prefix, ctxt) ) + { + case X86EMUL_OKAY: + regs->eflags |=3D X86_EFLAGS_ZF; + break; + + case X86EMUL_CMPXCHG_FAILED: + rc =3D X86EMUL_OKAY; + goto cmpxchgNb_failed; + + default: + goto done; + } + } + } + + rc =3D X86EMUL_OKAY; + + done: + return rc; +} --- a/xen/arch/x86/x86_emulate/Makefile +++ b/xen/arch/x86/x86_emulate/Makefile @@ -1,2 +1,3 @@ obj-y +=3D 0f01.o obj-y +=3D 0fae.o +obj-y +=3D 0fc7.o --- a/xen/arch/x86/x86_emulate/private.h +++ b/xen/arch/x86/x86_emulate/private.h @@ -308,6 +308,14 @@ struct x86_emulate_state { #endif }; =20 +typedef union { + uint64_t mmx; + uint64_t __attribute__ ((aligned(16))) xmm[2]; + uint64_t __attribute__ ((aligned(32))) ymm[4]; + uint64_t __attribute__ ((aligned(64))) zmm[8]; + uint32_t data32[16]; +} mmval_t; + struct x86_fxsr { uint16_t fcw; uint16_t fsw; @@ -558,6 +566,12 @@ int x86emul_0fae(struct x86_emulate_stat struct x86_emulate_ctxt *ctxt, const struct x86_emulate_ops *ops, enum x86_emulate_fpu_type *fpu_type); +int x86emul_0fc7(struct x86_emulate_state *s, + struct cpu_user_regs *regs, + struct operand *dst, + struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops, + mmval_t *mmvalp); =20 static inline bool is_aligned(enum x86_segment seg, unsigned long offs, unsigned int size, struct x86_emulate_ctxt *= ctxt, --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -687,17 +687,9 @@ struct x87_env32 { }; #endif =20 -typedef union { - uint64_t mmx; - uint64_t __attribute__ ((aligned(16))) xmm[2]; - uint64_t __attribute__ ((aligned(32))) ymm[4]; - uint64_t __attribute__ ((aligned(64))) zmm[8]; - uint32_t data32[16]; -} mmval_t; - /* - * While proper alignment gets specified above, this doesn't get honored by - * the compiler for automatic variables. Use this helper to instantiate a + * While proper alignment gets specified in mmval_t, this doesn't get hono= red + * by the compiler for automatic variables. Use this helper to instantiate= a * suitably aligned variable, producing a pointer to access it. */ #define DECLARE_ALIGNED(type, var) \ @@ -7681,174 +7673,8 @@ x86_emulate( #endif /* X86EMUL_NO_SIMD */ =20 case X86EMUL_OPC(0x0f, 0xc7): /* Grp9 */ - { - union { - uint32_t u32[2]; - uint64_t u64[2]; - } *old, *aux; - - if ( ea.type =3D=3D OP_REG ) - { - bool __maybe_unused carry; - - switch ( modrm_reg & 7 ) - { - default: - goto unrecognized_insn; - - case 6: /* rdrand */ -#ifdef HAVE_AS_RDRAND - generate_exception_if(rep_prefix(), EXC_UD); - host_and_vcpu_must_have(rdrand); - dst =3D ea; - switch ( op_bytes ) - { - case 2: - asm ( "rdrand %w0" ASM_FLAG_OUT(, "; setc %1") - : "=3Dr" (dst.val), ASM_FLAG_OUT("=3D@ccc", "=3D= qm") (carry) ); - break; - default: -# ifdef __x86_64__ - asm ( "rdrand %k0" ASM_FLAG_OUT(, "; setc %1") - : "=3Dr" (dst.val), ASM_FLAG_OUT("=3D@ccc", "=3D= qm") (carry) ); - break; - case 8: -# endif - asm ( "rdrand %0" ASM_FLAG_OUT(, "; setc %1") - : "=3Dr" (dst.val), ASM_FLAG_OUT("=3D@ccc", "=3D= qm") (carry) ); - break; - } - _regs.eflags &=3D ~EFLAGS_MASK; - if ( carry ) - _regs.eflags |=3D X86_EFLAGS_CF; - break; -#else - goto unimplemented_insn; -#endif - - case 7: /* rdseed / rdpid */ - if ( repe_prefix() ) /* rdpid */ - { - generate_exception_if(ea.type !=3D OP_REG, EXC_UD); - vcpu_must_have(rdpid); - fail_if(!ops->read_msr); - if ( (rc =3D ops->read_msr(MSR_TSC_AUX, &msr_val, - ctxt)) !=3D X86EMUL_OKAY ) - goto done; - dst =3D ea; - dst.val =3D msr_val; - dst.bytes =3D 4; - break; - } -#ifdef HAVE_AS_RDSEED - generate_exception_if(rep_prefix(), EXC_UD); - host_and_vcpu_must_have(rdseed); - dst =3D ea; - switch ( op_bytes ) - { - case 2: - asm ( "rdseed %w0" ASM_FLAG_OUT(, "; setc %1") - : "=3Dr" (dst.val), ASM_FLAG_OUT("=3D@ccc", "=3D= qm") (carry) ); - break; - default: -# ifdef __x86_64__ - asm ( "rdseed %k0" ASM_FLAG_OUT(, "; setc %1") - : "=3Dr" (dst.val), ASM_FLAG_OUT("=3D@ccc", "=3D= qm") (carry) ); - break; - case 8: -# endif - asm ( "rdseed %0" ASM_FLAG_OUT(, "; setc %1") - : "=3Dr" (dst.val), ASM_FLAG_OUT("=3D@ccc", "=3D= qm") (carry) ); - break; - } - _regs.eflags &=3D ~EFLAGS_MASK; - if ( carry ) - _regs.eflags |=3D X86_EFLAGS_CF; - break; -#endif - } - break; - } - - /* cmpxchg8b/cmpxchg16b */ - generate_exception_if((modrm_reg & 7) !=3D 1, EXC_UD); - fail_if(!ops->cmpxchg); - if ( rex_prefix & REX_W ) - { - host_and_vcpu_must_have(cx16); - generate_exception_if(!is_aligned(ea.mem.seg, ea.mem.off, 16, - ctxt, ops), - EXC_GP, 0); - op_bytes =3D 16; - } - else - { - vcpu_must_have(cx8); - op_bytes =3D 8; - } - - old =3D container_of(&mmvalp->ymm[0], typeof(*old), u64[0]); - aux =3D container_of(&mmvalp->ymm[2], typeof(*aux), u64[0]); - - /* Get actual old value. */ - if ( (rc =3D ops->read(ea.mem.seg, ea.mem.off, old, op_bytes, - ctxt)) !=3D X86EMUL_OKAY ) - goto done; - - /* Get expected value. */ - if ( !(rex_prefix & REX_W) ) - { - aux->u32[0] =3D _regs.eax; - aux->u32[1] =3D _regs.edx; - } - else - { - aux->u64[0] =3D _regs.r(ax); - aux->u64[1] =3D _regs.r(dx); - } - - if ( memcmp(old, aux, op_bytes) ) - { - cmpxchgNb_failed: - /* Expected !=3D actual: store actual to rDX:rAX and clear ZF.= */ - _regs.r(ax) =3D !(rex_prefix & REX_W) ? old->u32[0] : old->u64= [0]; - _regs.r(dx) =3D !(rex_prefix & REX_W) ? old->u32[1] : old->u64= [1]; - _regs.eflags &=3D ~X86_EFLAGS_ZF; - } - else - { - /* - * Expected =3D=3D actual: Get proposed value, attempt atomic = cmpxchg - * and set ZF if successful. - */ - if ( !(rex_prefix & REX_W) ) - { - aux->u32[0] =3D _regs.ebx; - aux->u32[1] =3D _regs.ecx; - } - else - { - aux->u64[0] =3D _regs.r(bx); - aux->u64[1] =3D _regs.r(cx); - } - - switch ( rc =3D ops->cmpxchg(ea.mem.seg, ea.mem.off, old, aux, - op_bytes, lock_prefix, ctxt) ) - { - case X86EMUL_OKAY: - _regs.eflags |=3D X86_EFLAGS_ZF; - break; - - case X86EMUL_CMPXCHG_FAILED: - rc =3D X86EMUL_OKAY; - goto cmpxchgNb_failed; - - default: - goto done; - } - } - break; - } + rc =3D x86emul_0fc7(state, &_regs, &dst, ctxt, ops, mmvalp); + goto dispatch_from_helper; =20 case X86EMUL_OPC(0x0f, 0xc8) ... X86EMUL_OPC(0x0f, 0xcf): /* bswap */ dst.type =3D OP_REG; From nobody Thu May 2 08:52:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; arc=pass (i=1 dmarc=pass fromdomain=suse.com); dmarc=pass(p=quarantine dis=none) header.from=suse.com ARC-Seal: i=2; a=rsa-sha256; t=1628684680; cv=pass; d=zohomail.com; s=zohoarc; b=hSvaqKHQSEUqR3XN57iexiuSdhF9N1Q5A91DrBb/H+7/xDs96b5AdMOKxXARp+Dd5t5LtmKjFsGHqhmxC2Jgh5KaEJzoYufgeBiVQoKQr0kn7E4R1o7xgbrzd3aPnPw5as+W5NZXzV3yQ/KnreUNS3lFS8B36hEmz/NluDQCXE0= ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1628684680; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=jGpfVZXELTSVn15kpuMDgT5b/YsWYsiBqFOcD7LjBHw=; b=cdH3WRDsF2SSQ4RfzRLhPU8udWGRBHmMpgcfjtMEspqFMharck5sSH4G9iKw/4ADmvKWv2GvRibR1P1PED36qFsfO6xJeR8aYc3ZMsLUaq8sF/aGUo1utB8XEUdJ2tnkxDR2yu4Sagzhrx+8qQMLo5rnvqq+YV4LNfF+R4JGjg4= ARC-Authentication-Results: i=2; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; arc=pass (i=1 dmarc=pass fromdomain=suse.com); dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 162868468011033.6438278289512; Wed, 11 Aug 2021 05:24:40 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.165993.303162 (Exim 4.92) (envelope-from ) id 1mDnHP-0007ld-H9; Wed, 11 Aug 2021 12:24:19 +0000 Received: by outflank-mailman (output) from mailman id 165993.303162; Wed, 11 Aug 2021 12:24:19 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1mDnHP-0007lW-E1; Wed, 11 Aug 2021 12:24:19 +0000 Received: by outflank-mailman (input) for mailman id 165993; Wed, 11 Aug 2021 12:24:18 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1mDnHO-0007lG-NM for xen-devel@lists.xenproject.org; Wed, 11 Aug 2021 12:24:18 +0000 Received: from de-smtp-delivery-102.mimecast.com (unknown [194.104.111.102]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id a60dc70b-20ff-48e3-9e6f-73e34d250243; Wed, 11 Aug 2021 12:24:12 +0000 (UTC) Received: from EUR02-HE1-obe.outbound.protection.outlook.com (mail-he1eur02lp2057.outbound.protection.outlook.com [104.47.5.57]) (Using TLS) by relay.mimecast.com with ESMTP id de-mta-16-XK7VwbYfN7WEqhNEI6A-kg-1; Wed, 11 Aug 2021 14:24:09 +0200 Received: from VI1PR04MB5600.eurprd04.prod.outlook.com (2603:10a6:803:e7::16) by VI1PR0402MB3390.eurprd04.prod.outlook.com (2603:10a6:803:9::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4394.19; Wed, 11 Aug 2021 12:24:07 +0000 Received: from VI1PR04MB5600.eurprd04.prod.outlook.com ([fe80::99d3:99cd:8adf:3eea]) by VI1PR04MB5600.eurprd04.prod.outlook.com ([fe80::99d3:99cd:8adf:3eea%5]) with mapi id 15.20.4394.025; Wed, 11 Aug 2021 12:24:07 +0000 Received: from [10.156.60.236] (37.24.206.209) by PR3PR09CA0008.eurprd09.prod.outlook.com (2603:10a6:102:b7::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4415.13 via Frontend Transport; Wed, 11 Aug 2021 12:24:07 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: a60dc70b-20ff-48e3-9e6f-73e34d250243 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=mimecast20200619; t=1628684651; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=jGpfVZXELTSVn15kpuMDgT5b/YsWYsiBqFOcD7LjBHw=; b=EnQF0uT8MPn7c+9u9vgirhoeEmEFoz20SN29FO1W9L2cQrQXWiddhA5JMe+3x2vn/hoLps wj/8Ngj3BhiCMCpjB9m/x5c+DJdXLUpGzUi5El4HebmcNmkkmBmcxK5UC2Y4Hof/eSRuqP bZi324EtI4xdPT2JCFl2f0QpiPFncY4= X-MC-Unique: XK7VwbYfN7WEqhNEI6A-kg-1 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=RbNzVlPckRs9d79VdFsmbDfGs/g4IfA3LQ1B414trk4sjEUwZYWuOiXak0EHhrN+ZTw76hkJmhotMxzWgmvyj85nFtPnKhti640LGH+56Tys5318tKU8d6VF2yZZuEM4RIdKk9dS9hKO2M0RrrVbCmzXFhRupYt4kdEXT5kcmww/Q2svBnc34si5DNI4PfQgP81cYSLU4oLQbx5LhxgFd2ZZaZtOBb7QclQLzvIdhpets9442iN0foHmIXlJmXnd9JwyH2Lb6/Z+32zFJxmNpCi2Me33JDMmyrEcpaMFJjuzpZlMDaJqwB7umj78Mr25ZMj5hga+TA3ASXZZBjMM3g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=jGpfVZXELTSVn15kpuMDgT5b/YsWYsiBqFOcD7LjBHw=; b=nGDqP7y4E8fvGlChPMl52mRq43C98p4ByCqx93TeI3uVRYzlu9q851knQgcfiZQv4tigT7bgQywA/7s4iAjxbqycgUu30qh0/Ub9JV4h3va/n0u/m9S+axZd4WnKbMOCIi9JDP/pW+gnP+52mjiYDQLCzvmVM1ht7iC3rSwbNhpoZ6DNvDa/ALtBupsv9Qy7yqbp68RkP/yg+mjRYcPOLeSS2rWUI4t2fpANtNGaBJ8Hw1EWBA4grjgVo3ZyaLT8z7FYQscqdfKw9GgFrH2k9zMqaZogKaRtfLEI3f2XvNSI9YauR8uRT5kL3a2R3uPzr9sQk2VFfCRDdkBxXwciOA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=suse.com; dmarc=pass action=none header.from=suse.com; dkim=pass header.d=suse.com; arc=none Authentication-Results: citrix.com; dkim=none (message not signed) header.d=none;citrix.com; dmarc=none action=none header.from=suse.com; Subject: [PATCH 4/7] x86emul: split off FPU opcode handling From: Jan Beulich To: "xen-devel@lists.xenproject.org" Cc: Andrew Cooper , Wei Liu , =?UTF-8?Q?Roger_Pau_Monn=c3=a9?= References: Message-ID: <12b26ef4-540c-f453-c17d-d50dbdcef210@suse.com> Date: Wed, 11 Aug 2021 14:24:04 +0200 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Thunderbird/78.12.0 In-Reply-To: Content-Language: en-US Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: PR3PR09CA0008.eurprd09.prod.outlook.com (2603:10a6:102:b7::13) To VI1PR04MB5600.eurprd04.prod.outlook.com (2603:10a6:803:e7::16) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: f188e2ef-0ff9-4a7b-7c48-08d95cc2ea3f X-MS-TrafficTypeDiagnostic: VI1PR0402MB3390: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:5797; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: g2JMQ4RSe7/RbNY2E8hsYBe31KQo1IilzAPlwYNAwkTTKwWz6f/ts2FGziQ8xCsvh+BN5PSE/VCVWXi2CROMePZrUEvmayPy9XjSZ63D90YgQ8nAXLHa7Dd4reGyeO6UhuSVle2AE63Y9CuXmRgQ/tcTqctoOiGX1VMCSUt4klFQmcLA2iEMmqyepWvfn9zXXosZWGwGvA5EC//7Csh4+5/IHWjuCM1/bwMoH5SR1xU3fa/cE34KhBYSDSkeIRewhvMcYSI4Hp/UTkc5RHJIeM6gMwFoxz+T7NcQO5Vus47sc8NI2tN88EeBSmwPr3nrTCWZm27oVeigwvX3OFOGbb4XO6srL+ABjpLBaqPSiz2DcuduyTxBm8VmMVJk1RAbA8uYcPVt2gKYK6wu37jBinMDo5FjTRD/nX18O0JbQh+HM1TuyoOh1zjMVucSCP1/NodoFUXOoQBljvSGPsy8DoH5Uso/72Oe7bggU+jgKg9SbcgeyZju6NsC5qRF7Sx76hQ03qI2SCI8ZiAbYdHcaOf2+GLkrjZuinNsDeotUCdEZd3wPSyfd4wRK0YK1il8gOpC36WBZ8fo3wAXvg5PLBKiTeRjfMV5XM8W4DNQ2AA1aCkB1c6fOS1CqVnesJxPR2p+wJNabWhhaVJ/xdSYWVIpxDfKCwsIxsiSCAdRA2mmbg20aH3+MYB0aBA6DOKmCj5Uhpc2aDOpB8MzE/AxJXsI/I1y+tU3PnYucMNxpWSYtDiBE46GxLCqSyo6f6Orw7A2YYLuvc8pXor37GVcyTSQCkKpQ1+iepl8misxY/wxycr6Fb/2pOgAf+YPGwXj6ZNgrFFuboGYbAVt1GgE9VmD44Y5zqp0RP2BOGybCLE= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:VI1PR04MB5600.eurprd04.prod.outlook.com;PTR:;CAT:NONE;SFS:(376002)(366004)(396003)(39860400002)(136003)(346002)(30864003)(31686004)(83380400001)(8936002)(2616005)(6486002)(956004)(16576012)(31696002)(36756003)(316002)(6666004)(86362001)(66946007)(478600001)(38100700002)(66556008)(4326008)(54906003)(5660300002)(26005)(2906002)(6916009)(186003)(8676002)(66476007)(2004002)(45980500001)(43740500002)(559001)(579004)(127564004);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?cEdpcDZ6SnFtNG5yN3ZLdkNYOE1pZFdRcGFXUnhVMjhJMlI1VjlIMTB5d01F?= =?utf-8?B?ZTgrMXZoWSt3OUUwSkpOWTdVOGpLVXF4RTNnNlNjWjlBUTEwTHlXMDduZWpG?= =?utf-8?B?LzA1YkpKSXdDTGdud0FNd0llNzB3UHl3blREMlZaai9yNWJzUFBQMENVYUlJ?= =?utf-8?B?dGFGN3JUQXM0OEsrM2lEZnM1UGdXeHZTdW9reGdtQ244T2IrVVR5NC92b0xw?= =?utf-8?B?QllDMm1ISjdvaTJNRkIwSXBwVGcrd3BOK2hhMXRHb25MRHliTnA2R3pSYWN4?= =?utf-8?B?TjlxYStCcGxYQUVhS1daUkYyNWM5b2dIMm01VHZIbmhVbk1yWGwxQXNqaGNM?= =?utf-8?B?aVJxTzNKZmhISElkR28ySG5YT2pBeEZoUjNoZTVndzIrWFNmZUFBWFBoZXpR?= =?utf-8?B?M0F0cDhWOG9sbktsd2NaQjJlVE5xdTBmcDlVZUEwQUZrWHJQdmg1UkhzNThz?= =?utf-8?B?VHVoajQ0WnU3WDhJR1loRzJ3OXl6YUplK0JlN0JqMzFaS2RXTWhxdkdDSDZs?= =?utf-8?B?Q25VQ0xtOVcyUHhaaUtCaXZiS25YRzJPZU11M0NEVEJYb2NrY0RWZjM4elZO?= =?utf-8?B?Y3FKaFVwbjE1Q0I5dFpIRkM1bVE4b2l1WGxjdk9LeWpiZEFjL0xlZy9SZWpK?= =?utf-8?B?L3pMYit4ZUVOVzFoYmpnanJoak9Xb1QrUlZuT1pJVmtWL0RoUTUyb3lQWjZJ?= =?utf-8?B?RU5JYkRBTFh3cFdYSU9KQm5LajUxb2FHSGZJSFA2WDEvM0pvRk91VG9kMFRE?= =?utf-8?B?eFJBREl3ZEk0MjNoaHN5WW05Nk1xSms1b04rTVlEakNaVittSE56Q0QrSEZN?= =?utf-8?B?dDk0N1V4Q1YvQUlTMEtVMnU2d0JIN2VGWDZnOGtnVThVU0UwaFcza3JGMk16?= =?utf-8?B?M2FoY0g2aEFIWjJkUzlKVUxGTEIweFpNTUJVWW5nWW5Gb2ptYnhJSFJUNFNZ?= =?utf-8?B?dXYyS0E5NWpaVFp5MXZ2SlBsM0tXTzVmQWtUTkpJMksvWUEyOHdheTVQTThu?= =?utf-8?B?b3JPZ3lFUW5ZUWdOczAwSnpsbkZDcVd5U2U0SnBsL2swY3lXY29TMFpUYml0?= =?utf-8?B?bWxIazBYQ3ZqN2ZQQzE2VElsT1NqcFp6NFRlNXFPalB4RFJXb1RpdEVNT3lt?= =?utf-8?B?d0J3REJPalhaaUIxcWFoaG5wVlEwNGZJaUU1elByQnNvYmtoanYvcmFYWTJu?= =?utf-8?B?VVFCczV3Q2hDNHJwek1NaWxHRE5KdUpkS2VnRE1SQWcwN1RQT0N4ajRVbTFo?= =?utf-8?B?eWthTUVxL3ZKSW05TTdSL0JEU0M3ZDFLVDQvNUQzYTBoc2loT0dTMGRKdHFo?= =?utf-8?B?TTRBT2pBZm5VS05uY1ZwSldJckJzME10UGJKWUFQQWI4dTN1dzJWM1NFc0lC?= =?utf-8?B?cmJKZHUrRnFzQjdkc001NWFSd2w0V1F2YWtwcWltYkc3QVk3K3d5Qm5jZmhi?= =?utf-8?B?b253TWdpK2pHTmErVkxSdlozSElUbjZLdnRmejBiWGppVDNFQ2dRUEwrdklj?= =?utf-8?B?VmdHdlRLWlpXajJaaWJwZW1SYUE5UEkxZGZxbG8ybWNGOWoyQ0s5Wks1dnlP?= =?utf-8?B?bThBMFJNQWZpS2xKL3EwUXVlbHZwVlFuVDFFZ1RBNEVUeFA3UFRJWEQxdlMz?= =?utf-8?B?WTYwMStzeExOWUdidVFDZlIxSm4rZFIvYmZzb3hMODk4VVdFVjJNd2tNbkNv?= =?utf-8?B?VEh2L1VINHB0Sk1jZmtqVWNQZVdUTitQS2Z2N0dHVFVxTU9tQlhUbEgzclpi?= =?utf-8?Q?vKZ3m0hzC37P/VNT+S5g7rSsx01n499BqSnX2ZE?= X-OriginatorOrg: suse.com X-MS-Exchange-CrossTenant-Network-Message-Id: f188e2ef-0ff9-4a7b-7c48-08d95cc2ea3f X-MS-Exchange-CrossTenant-AuthSource: VI1PR04MB5600.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 11 Aug 2021 12:24:07.4724 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: f7a17af6-1c5c-4a36-aa8b-f5be247aa4ba X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: z2cJ2yXyDH6uljseKKgcoz3NcPKnzeccaTedPhhhoJzLXvF+K71E9sykIiYg3ArsKugxzifc/z3lv4N3tQYL6w== X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR0402MB3390 X-ZohoMail-DKIM: pass (identity @suse.com) X-ZM-MESSAGEID: 1628684681719100003 Content-Type: text/plain; charset="utf-8" Some of the helper functions/macros are needed only for this, and the code is otherwise relatively independent of other parts of the emulator. Code moved gets slightly adjusted in a few places, e.g. replacing EXC_* by X86_EXC_* (such that EXC_* don't need to move as well; we want these to be phased out anyway). Signed-off-by: Jan Beulich --- a/tools/fuzz/x86_instruction_emulator/Makefile +++ b/tools/fuzz/x86_instruction_emulator/Makefile @@ -36,6 +36,7 @@ x86_emulate.h :=3D x86-emulate.h x86_emula =20 OBJS :=3D fuzz-emul.o x86-emulate.o OBJS +=3D x86_emulate/0f01.o x86_emulate/0fae.o x86_emulate/0fc7.o +OBJS +=3D x86_emulate/fpu.o =20 # x86-emulate.c will be implicit for both x86-emulate.o x86-emulate-cov.o: x86_emulate/x86_emulate.c $(x86_emulate.h= ) x86_emulate/private.h --- a/tools/tests/x86_emulator/Makefile +++ b/tools/tests/x86_emulator/Makefile @@ -252,6 +252,7 @@ endif # 32-bit override =20 OBJS :=3D x86-emulate.o cpuid.o test_x86_emulator.o evex-disp8.o predicate= s.o wrappers.o OBJS +=3D x86_emulate/0f01.o x86_emulate/0fae.o x86_emulate/0fc7.o +OBJS +=3D x86_emulate/fpu.o =20 $(TARGET): $(OBJS) $(HOSTCC) $(HOSTCFLAGS) -o $@ $^ --- a/tools/tests/x86_emulator/x86-emulate.c +++ b/tools/tests/x86_emulator/x86-emulate.c @@ -29,12 +29,6 @@ # define __OP "r" /* Operand Prefix */ #endif =20 -#define get_stub(stb) ({ \ - assert(!(stb).addr); \ - (void *)((stb).addr =3D (uintptr_t)(stb).buf); \ -}) -#define put_stub(stb) ((stb).addr =3D 0) - uint32_t mxcsr_mask =3D 0x0000ffbf; struct cpuid_policy cp; =20 --- a/xen/arch/x86/x86_emulate.c +++ b/xen/arch/x86/x86_emulate.c @@ -9,7 +9,6 @@ * Keir Fraser */ =20 -#include #include #include #include @@ -26,21 +25,6 @@ #define cpu_has_amd_erratum(nr) \ cpu_has_amd_erratum(¤t_cpu_data, AMD_ERRATUM_##nr) =20 -#define get_stub(stb) ({ \ - BUILD_BUG_ON(STUB_BUF_SIZE / 2 < MAX_INST_LEN + 1); \ - ASSERT(!(stb).ptr); \ - (stb).addr =3D this_cpu(stubs.addr) + STUB_BUF_SIZE / 2; \ - memset(((stb).ptr =3D map_domain_page(_mfn(this_cpu(stubs.mfn)))) + \ - ((stb).addr & ~PAGE_MASK), 0xcc, STUB_BUF_SIZE / 2); \ -}) -#define put_stub(stb) ({ \ - if ( (stb).ptr ) \ - { \ - unmap_domain_page((stb).ptr); \ - (stb).ptr =3D NULL; \ - } \ -}) - #define FXSAVE_AREA current->arch.fpu_ctxt =20 #include "x86_emulate/x86_emulate.c" --- a/xen/arch/x86/x86_emulate/Makefile +++ b/xen/arch/x86/x86_emulate/Makefile @@ -1,3 +1,4 @@ obj-y +=3D 0f01.o obj-y +=3D 0fae.o obj-y +=3D 0fc7.o +obj-$(CONFIG_HVM) +=3D fpu.o --- /dev/null +++ b/xen/arch/x86/x86_emulate/fpu.c @@ -0,0 +1,491 @@ +/*************************************************************************= ***** + * x86_emulate.c + * + * Generic x86 (32-bit and 64-bit) instruction decoder and emulator. + * + * Copyright (c) 2005-2007 Keir Fraser + * Copyright (c) 2005-2007 XenSource Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; If not, see . + */ + +#include "private.h" + +#ifdef __XEN__ +# include +# define cpu_has_amd_erratum(nr) \ + cpu_has_amd_erratum(¤t_cpu_data, AMD_ERRATUM_##nr) +#else +# define cpu_has_amd_erratum(nr) 0 +#endif + +/* Floating point status word definitions. */ +#define FSW_ES (1U << 7) + +static inline bool fpu_check_write(void) +{ + uint16_t fsw; + + asm ( "fnstsw %0" : "=3Dam" (fsw) ); + + return !(fsw & FSW_ES); +} + +#define emulate_fpu_insn_memdst(opc, ext, arg) \ +do { \ + /* ModRM: mod=3D0, reg=3Dext, rm=3D0, i.e. a (%rax) operand */ = \ + *insn_bytes =3D 2; \ + memcpy(get_stub(stub), \ + ((uint8_t[]){ opc, ((ext) & 7) << 3, 0xc3 }), 3); \ + invoke_stub("", "", "+m" (arg) : "a" (&(arg))); \ + put_stub(stub); \ +} while (0) + +#define emulate_fpu_insn_memsrc(opc, ext, arg) \ +do { \ + /* ModRM: mod=3D0, reg=3Dext, rm=3D0, i.e. a (%rax) operand */ = \ + memcpy(get_stub(stub), \ + ((uint8_t[]){ opc, ((ext) & 7) << 3, 0xc3 }), 3); \ + invoke_stub("", "", "=3Dm" (dummy) : "m" (arg), "a" (&(arg))); \ + put_stub(stub); \ +} while (0) + +#define emulate_fpu_insn_stub(bytes...) \ +do { \ + unsigned int nr_ =3D sizeof((uint8_t[]){ bytes }); \ + memcpy(get_stub(stub), ((uint8_t[]){ bytes, 0xc3 }), nr_ + 1); \ + invoke_stub("", "", "=3Dm" (dummy) : "i" (0)); \ + put_stub(stub); \ +} while (0) + +#define emulate_fpu_insn_stub_eflags(bytes...) \ +do { \ + unsigned int nr_ =3D sizeof((uint8_t[]){ bytes }); \ + unsigned long tmp_; \ + memcpy(get_stub(stub), ((uint8_t[]){ bytes, 0xc3 }), nr_ + 1); \ + invoke_stub(_PRE_EFLAGS("[eflags]", "[mask]", "[tmp]"), \ + _POST_EFLAGS("[eflags]", "[mask]", "[tmp]"), \ + [eflags] "+g" (regs->eflags), [tmp] "=3D&r" (tmp_) \ + : [mask] "i" (X86_EFLAGS_ZF|X86_EFLAGS_PF|X86_EFLAGS_CF));= \ + put_stub(stub); \ +} while (0) + +int x86emul_fpu(struct x86_emulate_state *s, + struct cpu_user_regs *regs, + struct operand *dst, + struct operand *src, + struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops, + unsigned int *insn_bytes, + enum x86_emulate_fpu_type *fpu_type, +#define fpu_type (*fpu_type) /* for get_fpu() */ + struct stub_exn *stub_exn, +#define stub_exn (*stub_exn) /* for invoke_stub() */ + mmval_t *mmvalp) +{ + uint8_t b; + int rc; + struct x86_emulate_stub stub =3D {}; + + switch ( b =3D ctxt->opcode ) + { + unsigned long dummy; + + case 0x9b: /* wait/fwait */ + host_and_vcpu_must_have(fpu); + get_fpu(X86EMUL_FPU_wait); + emulate_fpu_insn_stub(b); + break; + + case 0xd8: /* FPU 0xd8 */ + host_and_vcpu_must_have(fpu); + get_fpu(X86EMUL_FPU_fpu); + switch ( s->modrm ) + { + case 0xc0 ... 0xc7: /* fadd %stN,%st */ + case 0xc8 ... 0xcf: /* fmul %stN,%st */ + case 0xd0 ... 0xd7: /* fcom %stN,%st */ + case 0xd8 ... 0xdf: /* fcomp %stN,%st */ + case 0xe0 ... 0xe7: /* fsub %stN,%st */ + case 0xe8 ... 0xef: /* fsubr %stN,%st */ + case 0xf0 ... 0xf7: /* fdiv %stN,%st */ + case 0xf8 ... 0xff: /* fdivr %stN,%st */ + emulate_fpu_insn_stub(0xd8, s->modrm); + break; + default: + fpu_memsrc32: + ASSERT(s->ea.type =3D=3D OP_MEM); + if ( (rc =3D ops->read(s->ea.mem.seg, s->ea.mem.off, &src->val, + 4, ctxt)) !=3D X86EMUL_OKAY ) + goto done; + emulate_fpu_insn_memsrc(b, s->modrm_reg & 7, src->val); + break; + } + break; + + case 0xd9: /* FPU 0xd9 */ + host_and_vcpu_must_have(fpu); + get_fpu(X86EMUL_FPU_fpu); + switch ( s->modrm ) + { + case 0xfb: /* fsincos */ + fail_if(cpu_has_amd_erratum(573)); + /* fall through */ + case 0xc0 ... 0xc7: /* fld %stN */ + case 0xc8 ... 0xcf: /* fxch %stN */ + case 0xd0: /* fnop */ + case 0xd8 ... 0xdf: /* fstp %stN (alternative encoding) */ + case 0xe0: /* fchs */ + case 0xe1: /* fabs */ + case 0xe4: /* ftst */ + case 0xe5: /* fxam */ + case 0xe8: /* fld1 */ + case 0xe9: /* fldl2t */ + case 0xea: /* fldl2e */ + case 0xeb: /* fldpi */ + case 0xec: /* fldlg2 */ + case 0xed: /* fldln2 */ + case 0xee: /* fldz */ + case 0xf0: /* f2xm1 */ + case 0xf1: /* fyl2x */ + case 0xf2: /* fptan */ + case 0xf3: /* fpatan */ + case 0xf4: /* fxtract */ + case 0xf5: /* fprem1 */ + case 0xf6: /* fdecstp */ + case 0xf7: /* fincstp */ + case 0xf8: /* fprem */ + case 0xf9: /* fyl2xp1 */ + case 0xfa: /* fsqrt */ + case 0xfc: /* frndint */ + case 0xfd: /* fscale */ + case 0xfe: /* fsin */ + case 0xff: /* fcos */ + emulate_fpu_insn_stub(0xd9, s->modrm); + break; + default: + generate_exception_if(s->ea.type !=3D OP_MEM, X86_EXC_UD); + switch ( s->modrm_reg & 7 ) + { + case 0: /* fld m32fp */ + goto fpu_memsrc32; + case 2: /* fst m32fp */ + case 3: /* fstp m32fp */ + fpu_memdst32: + *dst =3D s->ea; + dst->bytes =3D 4; + emulate_fpu_insn_memdst(b, s->modrm_reg & 7, dst->val); + break; + case 4: /* fldenv */ + /* Raise #MF now if there are pending unmasked exceptions.= */ + emulate_fpu_insn_stub(0xd9, 0xd0 /* fnop */); + /* fall through */ + case 6: /* fnstenv */ + fail_if(!ops->blk); + s->blk =3D s->modrm_reg & 2 ? blk_fst : blk_fld; + /* + * REX is meaningless for these insns by this point - (ab)= use + * the field to communicate real vs protected mode to ->bl= k(). + */ + s->rex_prefix =3D in_protmode(ctxt, ops); + if ( (rc =3D ops->blk(s->ea.mem.seg, s->ea.mem.off, NULL, + s->op_bytes > 2 ? sizeof(struct x87_en= v32) + : sizeof(struct x87_en= v16), + ®s->eflags, + s, ctxt)) !=3D X86EMUL_OKAY ) + goto done; + s->fpu_ctrl =3D true; + break; + case 5: /* fldcw m2byte */ + s->fpu_ctrl =3D true; + fpu_memsrc16: + if ( (rc =3D ops->read(s->ea.mem.seg, s->ea.mem.off, &src-= >val, + 2, ctxt)) !=3D X86EMUL_OKAY ) + goto done; + emulate_fpu_insn_memsrc(b, s->modrm_reg & 7, src->val); + break; + case 7: /* fnstcw m2byte */ + s->fpu_ctrl =3D true; + fpu_memdst16: + *dst =3D s->ea; + dst->bytes =3D 2; + emulate_fpu_insn_memdst(b, s->modrm_reg & 7, dst->val); + break; + default: + generate_exception(X86_EXC_UD); + } + /* + * Control instructions can't raise FPU exceptions, so we need + * to consider suppressing writes only for non-control ones. + */ + if ( dst->type =3D=3D OP_MEM && !s->fpu_ctrl && !fpu_check_wri= te() ) + dst->type =3D OP_NONE; + } + break; + + case 0xda: /* FPU 0xda */ + host_and_vcpu_must_have(fpu); + get_fpu(X86EMUL_FPU_fpu); + switch ( s->modrm ) + { + case 0xc0 ... 0xc7: /* fcmovb %stN */ + case 0xc8 ... 0xcf: /* fcmove %stN */ + case 0xd0 ... 0xd7: /* fcmovbe %stN */ + case 0xd8 ... 0xdf: /* fcmovu %stN */ + vcpu_must_have(cmov); + emulate_fpu_insn_stub_eflags(0xda, s->modrm); + break; + case 0xe9: /* fucompp */ + emulate_fpu_insn_stub(0xda, s->modrm); + break; + default: + generate_exception_if(s->ea.type !=3D OP_MEM, X86_EXC_UD); + goto fpu_memsrc32; + } + break; + + case 0xdb: /* FPU 0xdb */ + host_and_vcpu_must_have(fpu); + get_fpu(X86EMUL_FPU_fpu); + switch ( s->modrm ) + { + case 0xc0 ... 0xc7: /* fcmovnb %stN */ + case 0xc8 ... 0xcf: /* fcmovne %stN */ + case 0xd0 ... 0xd7: /* fcmovnbe %stN */ + case 0xd8 ... 0xdf: /* fcmovnu %stN */ + case 0xe8 ... 0xef: /* fucomi %stN */ + case 0xf0 ... 0xf7: /* fcomi %stN */ + vcpu_must_have(cmov); + emulate_fpu_insn_stub_eflags(0xdb, s->modrm); + break; + case 0xe0: /* fneni - 8087 only, ignored by 287 */ + case 0xe1: /* fndisi - 8087 only, ignored by 287 */ + case 0xe2: /* fnclex */ + case 0xe3: /* fninit */ + case 0xe4: /* fnsetpm - 287 only, ignored by 387 */ + /* case 0xe5: frstpm - 287 only, #UD on 387 */ + s->fpu_ctrl =3D true; + emulate_fpu_insn_stub(0xdb, s->modrm); + break; + default: + generate_exception_if(s->ea.type !=3D OP_MEM, X86_EXC_UD); + switch ( s->modrm_reg & 7 ) + { + case 0: /* fild m32i */ + goto fpu_memsrc32; + case 1: /* fisttp m32i */ + host_and_vcpu_must_have(sse3); + /* fall through */ + case 2: /* fist m32i */ + case 3: /* fistp m32i */ + goto fpu_memdst32; + case 5: /* fld m80fp */ + fpu_memsrc80: + if ( (rc =3D ops->read(s->ea.mem.seg, s->ea.mem.off, mmval= p, + 10, ctxt)) !=3D X86EMUL_OKAY ) + goto done; + emulate_fpu_insn_memsrc(b, s->modrm_reg & 7, *mmvalp); + break; + case 7: /* fstp m80fp */ + fpu_memdst80: + fail_if(!ops->write); + emulate_fpu_insn_memdst(b, s->modrm_reg & 7, *mmvalp); + if ( fpu_check_write() && + (rc =3D ops->write(s->ea.mem.seg, s->ea.mem.off, mmva= lp, + 10, ctxt)) !=3D X86EMUL_OKAY ) + goto done; + break; + default: + generate_exception(X86_EXC_UD); + } + } + break; + + case 0xdc: /* FPU 0xdc */ + host_and_vcpu_must_have(fpu); + get_fpu(X86EMUL_FPU_fpu); + switch ( s->modrm ) + { + case 0xc0 ... 0xc7: /* fadd %st,%stN */ + case 0xc8 ... 0xcf: /* fmul %st,%stN */ + case 0xd0 ... 0xd7: /* fcom %stN,%st (alternative encoding) */ + case 0xd8 ... 0xdf: /* fcomp %stN,%st (alternative encoding) */ + case 0xe0 ... 0xe7: /* fsubr %st,%stN */ + case 0xe8 ... 0xef: /* fsub %st,%stN */ + case 0xf0 ... 0xf7: /* fdivr %st,%stN */ + case 0xf8 ... 0xff: /* fdiv %st,%stN */ + emulate_fpu_insn_stub(0xdc, s->modrm); + break; + default: + fpu_memsrc64: + ASSERT(s->ea.type =3D=3D OP_MEM); + if ( (rc =3D ops->read(s->ea.mem.seg, s->ea.mem.off, &src->val, + 8, ctxt)) !=3D X86EMUL_OKAY ) + goto done; + emulate_fpu_insn_memsrc(b, s->modrm_reg & 7, src->val); + break; + } + break; + + case 0xdd: /* FPU 0xdd */ + host_and_vcpu_must_have(fpu); + get_fpu(X86EMUL_FPU_fpu); + switch ( s->modrm ) + { + case 0xc0 ... 0xc7: /* ffree %stN */ + case 0xc8 ... 0xcf: /* fxch %stN (alternative encoding) */ + case 0xd0 ... 0xd7: /* fst %stN */ + case 0xd8 ... 0xdf: /* fstp %stN */ + case 0xe0 ... 0xe7: /* fucom %stN */ + case 0xe8 ... 0xef: /* fucomp %stN */ + emulate_fpu_insn_stub(0xdd, s->modrm); + break; + default: + generate_exception_if(s->ea.type !=3D OP_MEM, X86_EXC_UD); + switch ( s->modrm_reg & 7 ) + { + case 0: /* fld m64fp */; + goto fpu_memsrc64; + case 1: /* fisttp m64i */ + host_and_vcpu_must_have(sse3); + /* fall through */ + case 2: /* fst m64fp */ + case 3: /* fstp m64fp */ + fpu_memdst64: + *dst =3D s->ea; + dst->bytes =3D 8; + emulate_fpu_insn_memdst(b, s->modrm_reg & 7, dst->val); + break; + case 4: /* frstor */ + /* Raise #MF now if there are pending unmasked exceptions.= */ + emulate_fpu_insn_stub(0xd9, 0xd0 /* fnop */); + /* fall through */ + case 6: /* fnsave */ + fail_if(!ops->blk); + s->blk =3D s->modrm_reg & 2 ? blk_fst : blk_fld; + /* + * REX is meaningless for these insns by this point - (ab)= use + * the field to communicate real vs protected mode to ->bl= k(). + */ + s->rex_prefix =3D in_protmode(ctxt, ops); + if ( (rc =3D ops->blk(s->ea.mem.seg, s->ea.mem.off, NULL, + s->op_bytes > 2 ? sizeof(struct x87_en= v32) + 80 + : sizeof(struct x87_en= v16) + 80, + ®s->eflags, + s, ctxt)) !=3D X86EMUL_OKAY ) + goto done; + s->fpu_ctrl =3D true; + break; + case 7: /* fnstsw m2byte */ + s->fpu_ctrl =3D true; + goto fpu_memdst16; + default: + generate_exception(X86_EXC_UD); + } + /* + * Control instructions can't raise FPU exceptions, so we need + * to consider suppressing writes only for non-control ones. + */ + if ( dst->type =3D=3D OP_MEM && !s->fpu_ctrl && !fpu_check_wri= te() ) + dst->type =3D OP_NONE; + } + break; + + case 0xde: /* FPU 0xde */ + host_and_vcpu_must_have(fpu); + get_fpu(X86EMUL_FPU_fpu); + switch ( s->modrm ) + { + case 0xc0 ... 0xc7: /* faddp %stN */ + case 0xc8 ... 0xcf: /* fmulp %stN */ + case 0xd0 ... 0xd7: /* fcomp %stN (alternative encoding) */ + case 0xd9: /* fcompp */ + case 0xe0 ... 0xe7: /* fsubrp %stN */ + case 0xe8 ... 0xef: /* fsubp %stN */ + case 0xf0 ... 0xf7: /* fdivrp %stN */ + case 0xf8 ... 0xff: /* fdivp %stN */ + emulate_fpu_insn_stub(0xde, s->modrm); + break; + default: + generate_exception_if(s->ea.type !=3D OP_MEM, X86_EXC_UD); + emulate_fpu_insn_memsrc(b, s->modrm_reg & 7, src->val); + break; + } + break; + + case 0xdf: /* FPU 0xdf */ + host_and_vcpu_must_have(fpu); + get_fpu(X86EMUL_FPU_fpu); + switch ( s->modrm ) + { + case 0xe0: + /* fnstsw %ax */ + s->fpu_ctrl =3D true; + dst->bytes =3D 2; + dst->type =3D OP_REG; + dst->reg =3D (void *)®s->ax; + emulate_fpu_insn_memdst(b, s->modrm_reg & 7, dst->val); + break; + case 0xe8 ... 0xef: /* fucomip %stN */ + case 0xf0 ... 0xf7: /* fcomip %stN */ + vcpu_must_have(cmov); + emulate_fpu_insn_stub_eflags(0xdf, s->modrm); + break; + case 0xc0 ... 0xc7: /* ffreep %stN */ + case 0xc8 ... 0xcf: /* fxch %stN (alternative encoding) */ + case 0xd0 ... 0xd7: /* fstp %stN (alternative encoding) */ + case 0xd8 ... 0xdf: /* fstp %stN (alternative encoding) */ + emulate_fpu_insn_stub(0xdf, s->modrm); + break; + default: + generate_exception_if(s->ea.type !=3D OP_MEM, X86_EXC_UD); + switch ( s->modrm_reg & 7 ) + { + case 0: /* fild m16i */ + goto fpu_memsrc16; + case 1: /* fisttp m16i */ + host_and_vcpu_must_have(sse3); + /* fall through */ + case 2: /* fist m16i */ + case 3: /* fistp m16i */ + goto fpu_memdst16; + case 4: /* fbld m80dec */ + goto fpu_memsrc80; + case 5: /* fild m64i */ + dst->type =3D OP_NONE; + goto fpu_memsrc64; + case 6: /* fbstp packed bcd */ + goto fpu_memdst80; + case 7: /* fistp m64i */ + goto fpu_memdst64; + } + } + break; + + default: + ASSERT_UNREACHABLE(); + return X86EMUL_UNHANDLEABLE; + } + + rc =3D X86EMUL_OKAY; + + done: + put_stub(stub); + return rc; + +#ifdef __XEN__ + emulation_stub_failure: + return X86EMUL_stub_failure; +#endif +} --- a/xen/arch/x86/x86_emulate/private.h +++ b/xen/arch/x86/x86_emulate/private.h @@ -339,12 +339,57 @@ struct x86_fxsr { uint64_t avl[6]; }; =20 +#ifndef X86EMUL_NO_FPU +struct x87_env16 { + uint16_t fcw; + uint16_t fsw; + uint16_t ftw; + union { + struct { + uint16_t fip_lo; + uint16_t fop:11, :1, fip_hi:4; + uint16_t fdp_lo; + uint16_t :12, fdp_hi:4; + } real; + struct { + uint16_t fip; + uint16_t fcs; + uint16_t fdp; + uint16_t fds; + } prot; + } mode; +}; + +struct x87_env32 { + uint32_t fcw:16, :16; + uint32_t fsw:16, :16; + uint32_t ftw:16, :16; + union { + struct { + /* some CPUs/FPUs also store the full FIP here */ + uint32_t fip_lo:16, :16; + uint32_t fop:11, :1, fip_hi:16, :4; + /* some CPUs/FPUs also store the full FDP here */ + uint32_t fdp_lo:16, :16; + uint32_t :12, fdp_hi:16, :4; + } real; + struct { + uint32_t fip; + uint32_t fcs:16, fop:11, :5; + uint32_t fdp; + uint32_t fds:16, :16; + } prot; + } mode; +}; +#endif + /* * Externally visible return codes from x86_emulate() are non-negative. * Use negative values for internal state change indicators from helpers * to the main function. */ #define X86EMUL_rdtsc (-1) +#define X86EMUL_stub_failure (-2) =20 /* * These EFLAGS bits are restored from saved value during emulation, and @@ -541,6 +586,113 @@ amd_like(const struct x86_emulate_ctxt * # define host_and_vcpu_must_have(feat) vcpu_must_have(feat) #endif =20 +/* + * Instruction emulation: + * Most instructions are emulated directly via a fragment of inline assemb= ly + * code. This allows us to save/restore EFLAGS and thus very easily pick up + * any modified flags. + */ + +#if defined(__x86_64__) +#define _LO32 "k" /* force 32-bit operand */ +#define _STK "%%rsp" /* stack pointer */ +#define _BYTES_PER_LONG "8" +#elif defined(__i386__) +#define _LO32 "" /* force 32-bit operand */ +#define _STK "%%esp" /* stack pointer */ +#define _BYTES_PER_LONG "4" +#endif + +/* Before executing instruction: restore necessary bits in EFLAGS. */ +#define _PRE_EFLAGS(_sav, _msk, _tmp) \ +/* EFLAGS =3D (_sav & _msk) | (EFLAGS & ~_msk); _sav &=3D ~_msk; */ \ +"movl %"_LO32 _sav",%"_LO32 _tmp"; " \ +"push %"_tmp"; " \ +"push %"_tmp"; " \ +"movl %"_msk",%"_LO32 _tmp"; " \ +"andl %"_LO32 _tmp",("_STK"); " \ +"pushf; " \ +"notl %"_LO32 _tmp"; " \ +"andl %"_LO32 _tmp",("_STK"); " \ +"andl %"_LO32 _tmp",2*"_BYTES_PER_LONG"("_STK"); " \ +"pop %"_tmp"; " \ +"orl %"_LO32 _tmp",("_STK"); " \ +"popf; " \ +"pop %"_tmp"; " \ +"movl %"_LO32 _tmp",%"_LO32 _sav"; " + +/* After executing instruction: write-back necessary bits in EFLAGS. */ +#define _POST_EFLAGS(_sav, _msk, _tmp) \ +/* _sav |=3D EFLAGS & _msk; */ \ +"pushf; " \ +"pop %"_tmp"; " \ +"andl %"_msk",%"_LO32 _tmp"; " \ +"orl %"_LO32 _tmp",%"_LO32 _sav"; " + +#ifdef __XEN__ + +# include +# include + +# define get_stub(stb) ({ \ + BUILD_BUG_ON(STUB_BUF_SIZE / 2 < MAX_INST_LEN + 1); \ + ASSERT(!(stb).ptr); \ + (stb).addr =3D this_cpu(stubs.addr) + STUB_BUF_SIZE / 2; \ + memset(((stb).ptr =3D map_domain_page(_mfn(this_cpu(stubs.mfn)))) + \ + ((stb).addr & ~PAGE_MASK), 0xcc, STUB_BUF_SIZE / 2); \ +}) + +# define put_stub(stb) ({ \ + if ( (stb).ptr ) \ + { \ + unmap_domain_page((stb).ptr); \ + (stb).ptr =3D NULL; \ + } \ +}) + +struct stub_exn { + union stub_exception_token info; + unsigned int line; +}; + +# define invoke_stub(pre, post, constraints...) do { \ + stub_exn.info =3D (union stub_exception_token) { .raw =3D ~0 }; = \ + stub_exn.line =3D __LINE__; /* Utility outweighs livepatching cost */ \ + block_speculation(); /* SCSB */ \ + asm volatile ( pre "\n\tINDIRECT_CALL %[stub]\n\t" post "\n" \ + ".Lret%=3D:\n\t" \ + ".pushsection .fixup,\"ax\"\n" \ + ".Lfix%=3D:\n\t" \ + "pop %[exn]\n\t" \ + "jmp .Lret%=3D\n\t" \ + ".popsection\n\t" \ + _ASM_EXTABLE(.Lret%=3D, .Lfix%=3D) = \ + : [exn] "+g" (stub_exn.info) ASM_CALL_CONSTRAINT, \ + constraints, \ + [stub] "r" (stub.func), \ + "m" (*(uint8_t(*)[MAX_INST_LEN + 1])stub.ptr) ); \ + if ( unlikely(~stub_exn.info.raw) ) \ + goto emulation_stub_failure; \ +} while (0) + +#else /* !__XEN__ */ + +# define get_stub(stb) ({ \ + assert(!(stb).addr); \ + (void *)((stb).addr =3D (uintptr_t)(stb).buf); \ +}) + +# define put_stub(stb) ((stb).addr =3D 0) + +struct stub_exn {}; + +# define invoke_stub(pre, post, constraints...) \ + asm volatile ( pre "\n\tcall *%[stub]\n\t" post \ + : constraints, [stub] "rm" (stub.func), \ + "m" (*(typeof(stub.buf) *)stub.addr) ) + +#endif /* __XEN__ */ + int x86emul_get_cpl(struct x86_emulate_ctxt *ctxt, const struct x86_emulate_ops *ops); =20 @@ -554,6 +706,16 @@ do { if ( rc ) goto done; \ } while (0) =20 +int x86emul_fpu(struct x86_emulate_state *s, + struct cpu_user_regs *regs, + struct operand *dst, + struct operand *src, + struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops, + unsigned int *insn_bytes, + enum x86_emulate_fpu_type *fpu_type, + struct stub_exn *stub_exn, + mmval_t *mmvalp); int x86emul_0f01(struct x86_emulate_state *s, struct cpu_user_regs *regs, struct operand *dst, --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -643,50 +643,6 @@ static const uint8_t sse_prefix[] =3D { 0x #define PTR_POISON NULL /* 32-bit builds are for user-space, so NULL is OK= . */ #endif =20 -#ifndef X86EMUL_NO_FPU -struct x87_env16 { - uint16_t fcw; - uint16_t fsw; - uint16_t ftw; - union { - struct { - uint16_t fip_lo; - uint16_t fop:11, :1, fip_hi:4; - uint16_t fdp_lo; - uint16_t :12, fdp_hi:4; - } real; - struct { - uint16_t fip; - uint16_t fcs; - uint16_t fdp; - uint16_t fds; - } prot; - } mode; -}; - -struct x87_env32 { - uint32_t fcw:16, :16; - uint32_t fsw:16, :16; - uint32_t ftw:16, :16; - union { - struct { - /* some CPUs/FPUs also store the full FIP here */ - uint32_t fip_lo:16, :16; - uint32_t fop:11, :1, fip_hi:16, :4; - /* some CPUs/FPUs also store the full FDP here */ - uint32_t fdp_lo:16, :16; - uint32_t :12, fdp_hi:16, :4; - } real; - struct { - uint32_t fip; - uint32_t fcs:16, fop:11, :5; - uint32_t fdp; - uint32_t fds:16, :16; - } prot; - } mode; -}; -#endif - /* * While proper alignment gets specified in mmval_t, this doesn't get hono= red * by the compiler for automatic variables. Use this helper to instantiate= a @@ -704,9 +660,6 @@ struct x87_env32 { # define ASM_FLAG_OUT(yes, no) no #endif =20 -/* Floating point status word definitions. */ -#define FSW_ES (1U << 7) - /* MXCSR bit definitions. */ #define MXCSR_MM (1U << 17) =20 @@ -737,49 +690,6 @@ struct x87_env32 { #define ECODE_IDT (1 << 1) #define ECODE_TI (1 << 2) =20 -/* - * Instruction emulation: - * Most instructions are emulated directly via a fragment of inline assemb= ly - * code. This allows us to save/restore EFLAGS and thus very easily pick up - * any modified flags. - */ - -#if defined(__x86_64__) -#define _LO32 "k" /* force 32-bit operand */ -#define _STK "%%rsp" /* stack pointer */ -#define _BYTES_PER_LONG "8" -#elif defined(__i386__) -#define _LO32 "" /* force 32-bit operand */ -#define _STK "%%esp" /* stack pointer */ -#define _BYTES_PER_LONG "4" -#endif - -/* Before executing instruction: restore necessary bits in EFLAGS. */ -#define _PRE_EFLAGS(_sav, _msk, _tmp) \ -/* EFLAGS =3D (_sav & _msk) | (EFLAGS & ~_msk); _sav &=3D ~_msk; */ \ -"movl %"_LO32 _sav",%"_LO32 _tmp"; " \ -"push %"_tmp"; " \ -"push %"_tmp"; " \ -"movl %"_msk",%"_LO32 _tmp"; " \ -"andl %"_LO32 _tmp",("_STK"); " \ -"pushf; " \ -"notl %"_LO32 _tmp"; " \ -"andl %"_LO32 _tmp",("_STK"); " \ -"andl %"_LO32 _tmp",2*"_BYTES_PER_LONG"("_STK"); " \ -"pop %"_tmp"; " \ -"orl %"_LO32 _tmp",("_STK"); " \ -"popf; " \ -"pop %"_tmp"; " \ -"movl %"_LO32 _tmp",%"_LO32 _sav"; " - -/* After executing instruction: write-back necessary bits in EFLAGS. */ -#define _POST_EFLAGS(_sav, _msk, _tmp) \ -/* _sav |=3D EFLAGS & _msk; */ \ -"pushf; " \ -"pop %"_tmp"; " \ -"andl %"_msk",%"_LO32 _tmp"; " \ -"orl %"_LO32 _tmp",%"_LO32 _sav"; " - /* Raw emulation: instruction has two explicit operands. */ #define __emulate_2op_nobyte(_op, src, dst, sz, eflags, wsx,wsy,wdx,wdy, = \ lsx,lsy,ldx,ldy, qsx,qsy,qdx,qdy, extra...) = \ @@ -913,33 +823,6 @@ do{ asm volatile ( #define __emulate_1op_8byte(op, dst, eflags, extra...) #endif /* __i386__ */ =20 -#ifdef __XEN__ -# define invoke_stub(pre, post, constraints...) do { \ - stub_exn.info =3D (union stub_exception_token) { .raw =3D ~0 }; = \ - stub_exn.line =3D __LINE__; /* Utility outweighs livepatching cost */ \ - block_speculation(); /* SCSB */ \ - asm volatile ( pre "\n\tINDIRECT_CALL %[stub]\n\t" post "\n" \ - ".Lret%=3D:\n\t" \ - ".pushsection .fixup,\"ax\"\n" \ - ".Lfix%=3D:\n\t" \ - "pop %[exn]\n\t" \ - "jmp .Lret%=3D\n\t" \ - ".popsection\n\t" \ - _ASM_EXTABLE(.Lret%=3D, .Lfix%=3D) = \ - : [exn] "+g" (stub_exn.info) ASM_CALL_CONSTRAINT, \ - constraints, \ - [stub] "r" (stub.func), \ - "m" (*(uint8_t(*)[MAX_INST_LEN + 1])stub.ptr) ); \ - if ( unlikely(~stub_exn.info.raw) ) \ - goto emulation_stub_failure; \ -} while (0) -#else -# define invoke_stub(pre, post, constraints...) \ - asm volatile ( pre "\n\tcall *%[stub]\n\t" post \ - : constraints, [stub] "rm" (stub.func), \ - "m" (*(typeof(stub.buf) *)stub.addr) ) -#endif - #define emulate_stub(dst, src...) do { \ unsigned long tmp; \ invoke_stub(_PRE_EFLAGS("[efl]", "[msk]", "[tmp]"), \ @@ -1162,54 +1045,6 @@ static void put_fpu( ops->put_fpu(ctxt, X86EMUL_FPU_none, NULL); } =20 -static inline bool fpu_check_write(void) -{ - uint16_t fsw; - - asm ( "fnstsw %0" : "=3Dam" (fsw) ); - - return !(fsw & FSW_ES); -} - -#define emulate_fpu_insn_memdst(opc, ext, arg) \ -do { \ - /* ModRM: mod=3D0, reg=3Dext, rm=3D0, i.e. a (%rax) operand */ = \ - insn_bytes =3D 2; \ - memcpy(get_stub(stub), \ - ((uint8_t[]){ opc, ((ext) & 7) << 3, 0xc3 }), 3); \ - invoke_stub("", "", "+m" (arg) : "a" (&(arg))); \ - put_stub(stub); \ -} while (0) - -#define emulate_fpu_insn_memsrc(opc, ext, arg) \ -do { \ - /* ModRM: mod=3D0, reg=3Dext, rm=3D0, i.e. a (%rax) operand */ = \ - memcpy(get_stub(stub), \ - ((uint8_t[]){ opc, ((ext) & 7) << 3, 0xc3 }), 3); \ - invoke_stub("", "", "=3Dm" (dummy) : "m" (arg), "a" (&(arg))); \ - put_stub(stub); \ -} while (0) - -#define emulate_fpu_insn_stub(bytes...) \ -do { \ - unsigned int nr_ =3D sizeof((uint8_t[]){ bytes }); \ - memcpy(get_stub(stub), ((uint8_t[]){ bytes, 0xc3 }), nr_ + 1); \ - invoke_stub("", "", "=3Dm" (dummy) : "i" (0)); \ - put_stub(stub); \ -} while (0) - -#define emulate_fpu_insn_stub_eflags(bytes...) \ -do { \ - unsigned int nr_ =3D sizeof((uint8_t[]){ bytes }); \ - unsigned long tmp_; \ - memcpy(get_stub(stub), ((uint8_t[]){ bytes, 0xc3 }), nr_ + 1); \ - invoke_stub(_PRE_EFLAGS("[eflags]", "[mask]", "[tmp]"), \ - _POST_EFLAGS("[eflags]", "[mask]", "[tmp]"), \ - [eflags] "+g" (_regs.eflags), [tmp] "=3D&r" (tmp_) \ - : [mask] "i" (X86_EFLAGS_ZF|X86_EFLAGS_PF|X86_EFLAGS_CF));= \ - put_stub(stub); \ -} while (0) - static inline unsigned long get_loop_count( const struct cpu_user_regs *regs, int ad_bytes) @@ -3154,12 +2989,7 @@ x86_emulate( enum x86_emulate_fpu_type fpu_type =3D X86EMUL_FPU_none; struct x86_emulate_stub stub =3D {}; DECLARE_ALIGNED(mmval_t, mmval); -#ifdef __XEN__ - struct { - union stub_exception_token info; - unsigned int line; - } stub_exn; -#endif + struct stub_exn stub_exn =3D {}; =20 ASSERT(ops->read); =20 @@ -3950,10 +3780,10 @@ x86_emulate( =20 #ifndef X86EMUL_NO_FPU case 0x9b: /* wait/fwait */ - host_and_vcpu_must_have(fpu); - get_fpu(X86EMUL_FPU_wait); - emulate_fpu_insn_stub(b); - break; + case 0xd8 ... 0xdf: /* FPU */ + rc =3D x86emul_fpu(state, &_regs, &dst, &src, ctxt, ops, + &insn_bytes, &fpu_type, &stub_exn, mmvalp); + goto dispatch_from_helper; #endif =20 case 0x9c: /* pushf */ @@ -4364,373 +4194,6 @@ x86_emulate( break; } =20 -#ifndef X86EMUL_NO_FPU - case 0xd8: /* FPU 0xd8 */ - host_and_vcpu_must_have(fpu); - get_fpu(X86EMUL_FPU_fpu); - switch ( modrm ) - { - case 0xc0 ... 0xc7: /* fadd %stN,%st */ - case 0xc8 ... 0xcf: /* fmul %stN,%st */ - case 0xd0 ... 0xd7: /* fcom %stN,%st */ - case 0xd8 ... 0xdf: /* fcomp %stN,%st */ - case 0xe0 ... 0xe7: /* fsub %stN,%st */ - case 0xe8 ... 0xef: /* fsubr %stN,%st */ - case 0xf0 ... 0xf7: /* fdiv %stN,%st */ - case 0xf8 ... 0xff: /* fdivr %stN,%st */ - emulate_fpu_insn_stub(0xd8, modrm); - break; - default: - fpu_memsrc32: - ASSERT(ea.type =3D=3D OP_MEM); - if ( (rc =3D ops->read(ea.mem.seg, ea.mem.off, &src.val, - 4, ctxt)) !=3D X86EMUL_OKAY ) - goto done; - emulate_fpu_insn_memsrc(b, modrm_reg & 7, src.val); - break; - } - break; - - case 0xd9: /* FPU 0xd9 */ - host_and_vcpu_must_have(fpu); - get_fpu(X86EMUL_FPU_fpu); - switch ( modrm ) - { - case 0xfb: /* fsincos */ - fail_if(cpu_has_amd_erratum(573)); - /* fall through */ - case 0xc0 ... 0xc7: /* fld %stN */ - case 0xc8 ... 0xcf: /* fxch %stN */ - case 0xd0: /* fnop */ - case 0xd8 ... 0xdf: /* fstp %stN (alternative encoding) */ - case 0xe0: /* fchs */ - case 0xe1: /* fabs */ - case 0xe4: /* ftst */ - case 0xe5: /* fxam */ - case 0xe8: /* fld1 */ - case 0xe9: /* fldl2t */ - case 0xea: /* fldl2e */ - case 0xeb: /* fldpi */ - case 0xec: /* fldlg2 */ - case 0xed: /* fldln2 */ - case 0xee: /* fldz */ - case 0xf0: /* f2xm1 */ - case 0xf1: /* fyl2x */ - case 0xf2: /* fptan */ - case 0xf3: /* fpatan */ - case 0xf4: /* fxtract */ - case 0xf5: /* fprem1 */ - case 0xf6: /* fdecstp */ - case 0xf7: /* fincstp */ - case 0xf8: /* fprem */ - case 0xf9: /* fyl2xp1 */ - case 0xfa: /* fsqrt */ - case 0xfc: /* frndint */ - case 0xfd: /* fscale */ - case 0xfe: /* fsin */ - case 0xff: /* fcos */ - emulate_fpu_insn_stub(0xd9, modrm); - break; - default: - generate_exception_if(ea.type !=3D OP_MEM, EXC_UD); - switch ( modrm_reg & 7 ) - { - case 0: /* fld m32fp */ - goto fpu_memsrc32; - case 2: /* fst m32fp */ - case 3: /* fstp m32fp */ - fpu_memdst32: - dst =3D ea; - dst.bytes =3D 4; - emulate_fpu_insn_memdst(b, modrm_reg & 7, dst.val); - break; - case 4: /* fldenv */ - /* Raise #MF now if there are pending unmasked exceptions.= */ - emulate_fpu_insn_stub(0xd9, 0xd0 /* fnop */); - /* fall through */ - case 6: /* fnstenv */ - fail_if(!ops->blk); - state->blk =3D modrm_reg & 2 ? blk_fst : blk_fld; - /* - * REX is meaningless for these insns by this point - (ab)= use - * the field to communicate real vs protected mode to ->bl= k(). - */ - /*state->*/rex_prefix =3D in_protmode(ctxt, ops); - if ( (rc =3D ops->blk(ea.mem.seg, ea.mem.off, NULL, - op_bytes > 2 ? sizeof(struct x87_env32) - : sizeof(struct x87_env16= ), - &_regs.eflags, - state, ctxt)) !=3D X86EMUL_OKAY ) - goto done; - state->fpu_ctrl =3D true; - break; - case 5: /* fldcw m2byte */ - state->fpu_ctrl =3D true; - fpu_memsrc16: - if ( (rc =3D ops->read(ea.mem.seg, ea.mem.off, &src.val, - 2, ctxt)) !=3D X86EMUL_OKAY ) - goto done; - emulate_fpu_insn_memsrc(b, modrm_reg & 7, src.val); - break; - case 7: /* fnstcw m2byte */ - state->fpu_ctrl =3D true; - fpu_memdst16: - dst =3D ea; - dst.bytes =3D 2; - emulate_fpu_insn_memdst(b, modrm_reg & 7, dst.val); - break; - default: - generate_exception(EXC_UD); - } - /* - * Control instructions can't raise FPU exceptions, so we need - * to consider suppressing writes only for non-control ones. - */ - if ( dst.type =3D=3D OP_MEM && !state->fpu_ctrl && !fpu_check_= write() ) - dst.type =3D OP_NONE; - } - break; - - case 0xda: /* FPU 0xda */ - host_and_vcpu_must_have(fpu); - get_fpu(X86EMUL_FPU_fpu); - switch ( modrm ) - { - case 0xc0 ... 0xc7: /* fcmovb %stN */ - case 0xc8 ... 0xcf: /* fcmove %stN */ - case 0xd0 ... 0xd7: /* fcmovbe %stN */ - case 0xd8 ... 0xdf: /* fcmovu %stN */ - vcpu_must_have(cmov); - emulate_fpu_insn_stub_eflags(0xda, modrm); - break; - case 0xe9: /* fucompp */ - emulate_fpu_insn_stub(0xda, modrm); - break; - default: - generate_exception_if(ea.type !=3D OP_MEM, EXC_UD); - goto fpu_memsrc32; - } - break; - - case 0xdb: /* FPU 0xdb */ - host_and_vcpu_must_have(fpu); - get_fpu(X86EMUL_FPU_fpu); - switch ( modrm ) - { - case 0xc0 ... 0xc7: /* fcmovnb %stN */ - case 0xc8 ... 0xcf: /* fcmovne %stN */ - case 0xd0 ... 0xd7: /* fcmovnbe %stN */ - case 0xd8 ... 0xdf: /* fcmovnu %stN */ - case 0xe8 ... 0xef: /* fucomi %stN */ - case 0xf0 ... 0xf7: /* fcomi %stN */ - vcpu_must_have(cmov); - emulate_fpu_insn_stub_eflags(0xdb, modrm); - break; - case 0xe0: /* fneni - 8087 only, ignored by 287 */ - case 0xe1: /* fndisi - 8087 only, ignored by 287 */ - case 0xe2: /* fnclex */ - case 0xe3: /* fninit */ - case 0xe4: /* fnsetpm - 287 only, ignored by 387 */ - /* case 0xe5: frstpm - 287 only, #UD on 387 */ - state->fpu_ctrl =3D true; - emulate_fpu_insn_stub(0xdb, modrm); - break; - default: - generate_exception_if(ea.type !=3D OP_MEM, EXC_UD); - switch ( modrm_reg & 7 ) - { - case 0: /* fild m32i */ - goto fpu_memsrc32; - case 1: /* fisttp m32i */ - host_and_vcpu_must_have(sse3); - /* fall through */ - case 2: /* fist m32i */ - case 3: /* fistp m32i */ - goto fpu_memdst32; - case 5: /* fld m80fp */ - fpu_memsrc80: - if ( (rc =3D ops->read(ea.mem.seg, ea.mem.off, mmvalp, - 10, ctxt)) !=3D X86EMUL_OKAY ) - goto done; - emulate_fpu_insn_memsrc(b, modrm_reg & 7, *mmvalp); - break; - case 7: /* fstp m80fp */ - fpu_memdst80: - fail_if(!ops->write); - emulate_fpu_insn_memdst(b, modrm_reg & 7, *mmvalp); - if ( fpu_check_write() && - (rc =3D ops->write(ea.mem.seg, ea.mem.off, mmvalp, - 10, ctxt)) !=3D X86EMUL_OKAY ) - goto done; - break; - default: - generate_exception(EXC_UD); - } - } - break; - - case 0xdc: /* FPU 0xdc */ - host_and_vcpu_must_have(fpu); - get_fpu(X86EMUL_FPU_fpu); - switch ( modrm ) - { - case 0xc0 ... 0xc7: /* fadd %st,%stN */ - case 0xc8 ... 0xcf: /* fmul %st,%stN */ - case 0xd0 ... 0xd7: /* fcom %stN,%st (alternative encoding) */ - case 0xd8 ... 0xdf: /* fcomp %stN,%st (alternative encoding) */ - case 0xe0 ... 0xe7: /* fsubr %st,%stN */ - case 0xe8 ... 0xef: /* fsub %st,%stN */ - case 0xf0 ... 0xf7: /* fdivr %st,%stN */ - case 0xf8 ... 0xff: /* fdiv %st,%stN */ - emulate_fpu_insn_stub(0xdc, modrm); - break; - default: - fpu_memsrc64: - ASSERT(ea.type =3D=3D OP_MEM); - if ( (rc =3D ops->read(ea.mem.seg, ea.mem.off, &src.val, - 8, ctxt)) !=3D X86EMUL_OKAY ) - goto done; - emulate_fpu_insn_memsrc(b, modrm_reg & 7, src.val); - break; - } - break; - - case 0xdd: /* FPU 0xdd */ - host_and_vcpu_must_have(fpu); - get_fpu(X86EMUL_FPU_fpu); - switch ( modrm ) - { - case 0xc0 ... 0xc7: /* ffree %stN */ - case 0xc8 ... 0xcf: /* fxch %stN (alternative encoding) */ - case 0xd0 ... 0xd7: /* fst %stN */ - case 0xd8 ... 0xdf: /* fstp %stN */ - case 0xe0 ... 0xe7: /* fucom %stN */ - case 0xe8 ... 0xef: /* fucomp %stN */ - emulate_fpu_insn_stub(0xdd, modrm); - break; - default: - generate_exception_if(ea.type !=3D OP_MEM, EXC_UD); - switch ( modrm_reg & 7 ) - { - case 0: /* fld m64fp */; - goto fpu_memsrc64; - case 1: /* fisttp m64i */ - host_and_vcpu_must_have(sse3); - /* fall through */ - case 2: /* fst m64fp */ - case 3: /* fstp m64fp */ - fpu_memdst64: - dst =3D ea; - dst.bytes =3D 8; - emulate_fpu_insn_memdst(b, modrm_reg & 7, dst.val); - break; - case 4: /* frstor */ - /* Raise #MF now if there are pending unmasked exceptions.= */ - emulate_fpu_insn_stub(0xd9, 0xd0 /* fnop */); - /* fall through */ - case 6: /* fnsave */ - fail_if(!ops->blk); - state->blk =3D modrm_reg & 2 ? blk_fst : blk_fld; - /* - * REX is meaningless for these insns by this point - (ab)= use - * the field to communicate real vs protected mode to ->bl= k(). - */ - /*state->*/rex_prefix =3D in_protmode(ctxt, ops); - if ( (rc =3D ops->blk(ea.mem.seg, ea.mem.off, NULL, - op_bytes > 2 ? sizeof(struct x87_env32= ) + 80 - : sizeof(struct x87_env16= ) + 80, - &_regs.eflags, - state, ctxt)) !=3D X86EMUL_OKAY ) - goto done; - state->fpu_ctrl =3D true; - break; - case 7: /* fnstsw m2byte */ - state->fpu_ctrl =3D true; - goto fpu_memdst16; - default: - generate_exception(EXC_UD); - } - /* - * Control instructions can't raise FPU exceptions, so we need - * to consider suppressing writes only for non-control ones. - */ - if ( dst.type =3D=3D OP_MEM && !state->fpu_ctrl && !fpu_check_= write() ) - dst.type =3D OP_NONE; - } - break; - - case 0xde: /* FPU 0xde */ - host_and_vcpu_must_have(fpu); - get_fpu(X86EMUL_FPU_fpu); - switch ( modrm ) - { - case 0xc0 ... 0xc7: /* faddp %stN */ - case 0xc8 ... 0xcf: /* fmulp %stN */ - case 0xd0 ... 0xd7: /* fcomp %stN (alternative encoding) */ - case 0xd9: /* fcompp */ - case 0xe0 ... 0xe7: /* fsubrp %stN */ - case 0xe8 ... 0xef: /* fsubp %stN */ - case 0xf0 ... 0xf7: /* fdivrp %stN */ - case 0xf8 ... 0xff: /* fdivp %stN */ - emulate_fpu_insn_stub(0xde, modrm); - break; - default: - generate_exception_if(ea.type !=3D OP_MEM, EXC_UD); - emulate_fpu_insn_memsrc(b, modrm_reg & 7, src.val); - break; - } - break; - - case 0xdf: /* FPU 0xdf */ - host_and_vcpu_must_have(fpu); - get_fpu(X86EMUL_FPU_fpu); - switch ( modrm ) - { - case 0xe0: - /* fnstsw %ax */ - state->fpu_ctrl =3D true; - dst.bytes =3D 2; - dst.type =3D OP_REG; - dst.reg =3D (void *)&_regs.ax; - emulate_fpu_insn_memdst(b, modrm_reg & 7, dst.val); - break; - case 0xe8 ... 0xef: /* fucomip %stN */ - case 0xf0 ... 0xf7: /* fcomip %stN */ - vcpu_must_have(cmov); - emulate_fpu_insn_stub_eflags(0xdf, modrm); - break; - case 0xc0 ... 0xc7: /* ffreep %stN */ - case 0xc8 ... 0xcf: /* fxch %stN (alternative encoding) */ - case 0xd0 ... 0xd7: /* fstp %stN (alternative encoding) */ - case 0xd8 ... 0xdf: /* fstp %stN (alternative encoding) */ - emulate_fpu_insn_stub(0xdf, modrm); - break; - default: - generate_exception_if(ea.type !=3D OP_MEM, EXC_UD); - switch ( modrm_reg & 7 ) - { - case 0: /* fild m16i */ - goto fpu_memsrc16; - case 1: /* fisttp m16i */ - host_and_vcpu_must_have(sse3); - /* fall through */ - case 2: /* fist m16i */ - case 3: /* fistp m16i */ - goto fpu_memdst16; - case 4: /* fbld m80dec */ - goto fpu_memsrc80; - case 5: /* fild m64i */ - dst.type =3D OP_NONE; - goto fpu_memsrc64; - case 6: /* fbstp packed bcd */ - goto fpu_memdst80; - case 7: /* fistp m64i */ - goto fpu_memdst64; - } - } - break; -#endif /* !X86EMUL_NO_FPU */ - case 0xe0 ... 0xe2: /* loop{,z,nz} */ { unsigned long count =3D get_loop_count(&_regs, ad_bytes); int do_jmp =3D !(_regs.eflags & X86_EFLAGS_ZF); /* loopnz */ @@ -10134,6 +9597,11 @@ x86_emulate( { case X86EMUL_rdtsc: goto rdtsc; + +#ifdef __XEN__ + case X86EMUL_stub_failure: + goto emulation_stub_failure; +#endif } =20 /* Internally used state change indicators may not make it here. */ From nobody Thu May 2 08:52:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; arc=pass (i=1 dmarc=pass fromdomain=suse.com); dmarc=pass(p=quarantine dis=none) header.from=suse.com ARC-Seal: i=2; a=rsa-sha256; t=1628684720; cv=pass; d=zohomail.com; s=zohoarc; b=gLpYOLtJsV4BMr7XBIbBUI0GrWu/HzC6e16VQCpJWUIugQC8J0lpdnoQJ/zsWnExYVF3NZ9szQcxi9tSIrNaU0ViEgAsIqlc+4B5qNEImm7VXLjf4zSFm13tnifgBw8g/vmx27cYpDm9sB2CtzVqSoZHUe96xu2wkMimbSKnMRA= ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1628684720; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=s8DVOkHW2bPmch43Tk+h/2NJULu3EpE9aZm9uqLJKIY=; b=f6QKkul0dPur5ICSmeHqsQQaxX7t5I1GZUBnVvsVtZLd12u0DbT7fc8cByzuold++EWU7Alf9221feHnpunb1WqjNl7eyt6T45ZYxgQd0DC/gVVkYDnspPSKj5T3+wyFlGs5jOnrgV+YLuk8QpJUYsvk85iuO4t3rmUwHPaBLmI= ARC-Authentication-Results: i=2; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; arc=pass (i=1 dmarc=pass fromdomain=suse.com); dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1628684720029527.8324645892011; Wed, 11 Aug 2021 05:25:20 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.166002.303173 (Exim 4.92) (envelope-from ) id 1mDnI2-0008UF-0E; Wed, 11 Aug 2021 12:24:58 +0000 Received: by outflank-mailman (output) from mailman id 166002.303173; Wed, 11 Aug 2021 12:24:57 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1mDnI1-0008U6-Sz; Wed, 11 Aug 2021 12:24:57 +0000 Received: by outflank-mailman (input) for mailman id 166002; Wed, 11 Aug 2021 12:24:56 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1mDnI0-0008Tm-Ii for xen-devel@lists.xenproject.org; Wed, 11 Aug 2021 12:24:56 +0000 Received: from de-smtp-delivery-102.mimecast.com (unknown [194.104.111.102]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id b6abad94-e9b7-490f-8dd8-6e5abc4ba733; Wed, 11 Aug 2021 12:24:46 +0000 (UTC) Received: from EUR02-HE1-obe.outbound.protection.outlook.com (mail-he1eur02lp2050.outbound.protection.outlook.com [104.47.5.50]) (Using TLS) by relay.mimecast.com with ESMTP id de-mta-10-VFSt_QXfMeC6b4PDzQXlVw-1; Wed, 11 Aug 2021 14:24:43 +0200 Received: from VI1PR04MB5600.eurprd04.prod.outlook.com (2603:10a6:803:e7::16) by VI1PR0402MB3390.eurprd04.prod.outlook.com (2603:10a6:803:9::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4394.19; Wed, 11 Aug 2021 12:24:40 +0000 Received: from VI1PR04MB5600.eurprd04.prod.outlook.com ([fe80::99d3:99cd:8adf:3eea]) by VI1PR04MB5600.eurprd04.prod.outlook.com ([fe80::99d3:99cd:8adf:3eea%5]) with mapi id 15.20.4394.025; Wed, 11 Aug 2021 12:24:40 +0000 Received: from [10.156.60.236] (37.24.206.209) by PR3P251CA0026.EURP251.PROD.OUTLOOK.COM (2603:10a6:102:b5::30) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4394.17 via Frontend Transport; Wed, 11 Aug 2021 12:24:39 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: b6abad94-e9b7-490f-8dd8-6e5abc4ba733 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=mimecast20200619; t=1628684685; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=s8DVOkHW2bPmch43Tk+h/2NJULu3EpE9aZm9uqLJKIY=; b=IS6E7Qhk9xtJ4R7mZ708m4chOQxi0PzgGe9gXeYaqCJBdVBeXrjpME+xAlerLWomut+P7a gO3HVm3+OoFjMK67th5LrP7a4R0rowRhoc8IoFVqDpKlthstNHmsXTErOSB7Yy4hNAl4pJ +0oQ+FusNf76cKSXeqEIDghALIJPkdk= X-MC-Unique: VFSt_QXfMeC6b4PDzQXlVw-1 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Xf3jG35FZ6nwxXNiVIAeSPvYpl4CpA9hpHg4eIcShSCRSXGtM6ydVrxBFcsCipCTFm2n+LMOUfYJT6PuEpqkNjgUBr/SmyRvz+j9ighcE0EpYDAcMEy/3vZFzQdj3sS5uvj6ItgveJb2oMlbFE7/4is8iusPw/HexkL1UHEhjgdo7jCjfQ9fhreOhDrQU+5EZAIKmGwy8mwL53uhxJVmGWPiS8vFnt2jGplfWM94WJezS1y8tQPjQcmzmHy5CppFtS7ZRSC8eTVc3k9Ol8Mp+mSy2dy5VlhVKVHb6ZOM0ebzs21uxQ47oaRMQBExdZph+pClq9T+Y0n9TDMloFhqVQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=s8DVOkHW2bPmch43Tk+h/2NJULu3EpE9aZm9uqLJKIY=; b=Y2aTC2637/MpenOa5qSvWBP4R+opjX3EFbe32iGyL2+Zc8z92gOprV97qiIhFaWPDBNDja9BAuUDM7IM9xYVffjprQFmcrkm8mFY2eMA8cv16ZEDOxN4PKauq2k7yx6eA2lYBAol9om07oXv8vooQ0KFf454hWIQr4oXp4H1otro9+5HS1FgShJ/GrwFaayNTg3Yh8E8QYMznqTLVzNF60FiE6IpMDK9WmNMo6IlFvyBs0P8yg5rzR06+euzzwUzUKHy0GI8razhCH7K43bTfrjjp3NeE4bD7s7mMgK16nIgg6yJKtsQ40gngn37BK+mcwR+CTaIqvDWZgmTeNYkTg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=suse.com; dmarc=pass action=none header.from=suse.com; dkim=pass header.d=suse.com; arc=none Authentication-Results: citrix.com; dkim=none (message not signed) header.d=none;citrix.com; dmarc=none action=none header.from=suse.com; Subject: [PATCH 5/7] x86emul: split off insn decoding From: Jan Beulich To: "xen-devel@lists.xenproject.org" Cc: Andrew Cooper , Wei Liu , =?UTF-8?Q?Roger_Pau_Monn=c3=a9?= References: Message-ID: <7f324493-6088-9147-4122-4691a86129cd@suse.com> Date: Wed, 11 Aug 2021 14:24:38 +0200 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Thunderbird/78.12.0 In-Reply-To: Content-Language: en-US Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: PR3P251CA0026.EURP251.PROD.OUTLOOK.COM (2603:10a6:102:b5::30) To VI1PR04MB5600.eurprd04.prod.outlook.com (2603:10a6:803:e7::16) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 5b074968-784d-4d63-baa0-08d95cc2fdde X-MS-TrafficTypeDiagnostic: VI1PR0402MB3390: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:5797; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: 1VR1VqZFrQx6AmPnSmGKDgayTi1FyiawkIGvN+q34DOdo4imrz+UV/xRknp/I7HtoYy2Wd9umwRbUY5utvWn7Z9SJx4E5pc9N1d6e4po/5y/9pO7dyIceY+GuzVu+sZ+44QWdEcM0JLxG/F1bO8c6x1ExURmmcvfwTaRfOhJusTZlxyb07CJo/NAsjxp6VBwGKvHArO/fNJUPZwQSHS4XL+pCdqnIc/BnlkCkDvHYN0JtSIabdOCgvdADZkNnuMV0sPVpEm44yxyDZU3t0oCRYZdFt4Ykbn95v6EcBQ+amIno1Gz9IBMs8EB9vYfDk9Sce4TDWtaZ68hH17jGTwfTQS1T9uap9wMqGgdnvvZbqDB3WggdZXNPy1+85z0BXmOVYxydGyBtYTC+8d/8TdRgf7KJ+6F7t3jciFjt9aV+Zh+Pl7h27/uPooPoBkZPxbOgbh4UQrSQCh64VdN4MEYCHu9zuWkJG2sKJZmhL0yWOQyyWTIMXs78wfRu+/DCCppzsY3nfjbkari5BaQMka80b8WjwKG0yGlLitRIGD1kuuIZnYjsq4/md7yWNcUoNH6tw85S9FcGEC7l7xy+P1DQW8NxYJkwEz2MWbV6jcUgWmO+0qP2YUOIygqfjOqmqRPTuzAmPvvT6pQZv9eIQ9AI/cfkRzFCbPss+PYVkzZlbVpZdrQUBp7ZT5wKezXsXASdDccG0Jeufvsh4XfK0xGqtoMzBODuIHI+90m+q5SXXft1GBZ5hNg6j/aGYtzKHvjuchm+fYo35h0Nn+Y0ho8dN9mR717AIgQZV05oPeTu9qDt4c72ASkrwh9K/G05036tPwt5XDIU6iePzup1xqGZw== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:VI1PR04MB5600.eurprd04.prod.outlook.com;PTR:;CAT:NONE;SFS:(376002)(366004)(396003)(39860400002)(136003)(346002)(30864003)(31686004)(83380400001)(8936002)(2616005)(6486002)(956004)(16576012)(31696002)(36756003)(316002)(86362001)(66946007)(478600001)(38100700002)(66556008)(4326008)(54906003)(5660300002)(26005)(2906002)(6916009)(186003)(8676002)(66476007)(2004002)(45980500001)(43740500002)(559001)(579004);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?Ny9uUTZ2ZkhsbTJJZm1vQnZ1MUlxNWpBOWhoaU9pQXVDdHJIVGkrMlBlKzVJ?= =?utf-8?B?RlN4YjMweXRERVZSUmJwcXNQbWN4VzQ1U21vZndpQTFESlVudytzeTA0c0Fw?= =?utf-8?B?alduUmJmSUJrbFUwSDhSUWQ3TVVINVpNdGRmTlJwckVHMDVvZmM3WFNDQVV6?= =?utf-8?B?T1F0dXpHKzlDeThzKzJZQmw1c05ONWxLODMrc1hNaGxOZWVFOXUzcEphaHRz?= =?utf-8?B?cUhkNmVMak9aQUJRT2IvRjVNbDFWZnNHbUZJdVRzWkZMRTlMUEg5WjhXRi9s?= =?utf-8?B?YmlESEpBWGVCaGNJY2ptbHVYblBiakZxZDdjbGs0UGxsRjFiK3p6UTE1ZWNO?= =?utf-8?B?MmRsUS82Z0hLNm9lT0l0SWQwMlg5enFEK3UwbGZUZndpaXU5OEJyOVFuREdu?= =?utf-8?B?S01QakxYZ24rNldBNGo4YlRmV3cwZHJYN0pibitDN3B5R013aXAzalJMK2Zh?= =?utf-8?B?THNBZ1dQVDY5N2VRWTlyZW1kakpUeEVDSnlFMi9ZSXVRVS9nWHVQUUVZdXhi?= =?utf-8?B?Rk1DcjlGZ0RNVUpaUUxrODVnelZDYzh2Zmh0UnlTcis5dERyaEI1K0pwekNK?= =?utf-8?B?QUJVRXQyZjE4M2Q0b3NhU1F4M1FDNjIvUEdPNUVsM3VjRFl0VTRza3JFNVBY?= =?utf-8?B?emRLTml1WGlubEc5OEY0THZZQlN3SFovSUNaOUc5SlBHUlVxanFtWUZSRlk0?= =?utf-8?B?MTZEWFMveVZBcHB3QzRIbTRSdHBBd3FhRXhlYjEwT09FSTU0cXF0N3VIVzlT?= =?utf-8?B?c2ZVbG9OaW5KaTFVcHhyZlRUTVJLU25ZQTFoNXNZcVpQR0htbmpjRklDM2RS?= =?utf-8?B?RXdseGppcVVjYkVTRTQzbWdKNWJlbUQraWVrTm9XWEJRZkltMVVqSkhFVmMx?= =?utf-8?B?M3N2NHVUbjRhRGRhK2hGNW9Hd2JKcys1RUNWTWJ6MGREamcvYXhJMFBGMFRq?= =?utf-8?B?TS9aS2RadUhKTDlKWWhyNFhrTkI5UXlKVzUwaW1BQnBZQm5lQ0pxVklwbjU2?= =?utf-8?B?ako4N3AwTFpHV204ZXZwd3NWV2VWZkhjTU5OTVdlNGMyYWRLZG5zaVZOQkZW?= =?utf-8?B?b2VTMWtQcVBWZWNtb2x1ZkZEeTlocW1JTDNWUVAxTDVRUEJvUFN3Uzh5NDlN?= =?utf-8?B?U2RlVWNhQS8zRUgvTW1rTXF2dVVFalNBanlTQ2pxcW11cGN2Mm91R1lQNG1C?= =?utf-8?B?UnFNaUF1N29uOVpycTM3dzBka2dIcm9PaDI5T3NEQVBlanRDVkVrZ0pZdUdS?= =?utf-8?B?STdiVHFtSWZUYjBPaThvVDI2bkxNSElXQXp3RXdyV1gxMU9aSTNTWHBuYVdH?= =?utf-8?B?eTdUNDFRRDFQMk1pRWgvWVB6MW1TRGxYN0pVQ200MTBKaFhzYStURVBrcTF5?= =?utf-8?B?YTlhaVE5blRCdXR6V1htcnVLaVpuOE02cm1ab093cW9Xbk5FbnFjN0VaR1Fp?= =?utf-8?B?ZGxzdGRMcWJRRXRNaTZGOFA1YnFvN2JOUWtRbnl5SGVncUtWYURCUkZ3clJT?= =?utf-8?B?RXE5alZwUXFNSnNHbUxEUmV2bEltWkVkVThweFZpZHNBeEhSeW9zMlhwUXU0?= =?utf-8?B?YkdicWwyaEl1THorcndGY1RpQUhEd01JUWdqYXBqSFdSZHdGL0dNYWxVcWJn?= =?utf-8?B?ZllVUGxzSVMxNThKSXM3TjZaa1NoOWFXaEk0bDNxNU1id3g1cmp0TzBVcFBh?= =?utf-8?B?R0hUVmN0ckZPdDB5UCtxSkhyNEF4bS9VclBnY01qWTgveExDWTRzZWltR3do?= =?utf-8?Q?XVuPSPVjRPYkWWBvXuxAPYnh6knzQ1da87JxGns?= X-OriginatorOrg: suse.com X-MS-Exchange-CrossTenant-Network-Message-Id: 5b074968-784d-4d63-baa0-08d95cc2fdde X-MS-Exchange-CrossTenant-AuthSource: VI1PR04MB5600.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 11 Aug 2021 12:24:40.4108 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: f7a17af6-1c5c-4a36-aa8b-f5be247aa4ba X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: bYOadVUTPsd/tPuSagqY2zJuj2sGmV8cUf+vOqF3vbxcLGo9e9y9akakKqHMcWARYT6lctpJpLyYehiacnwo7Q== X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR0402MB3390 X-ZohoMail-DKIM: pass (identity @suse.com) X-ZM-MESSAGEID: 1628684720552100003 Content-Type: text/plain; charset="utf-8" This is a fair chunk of code and data and can easily live separate from the main emulation function. Code moved gets slightly adjusted in a few places, e.g. replacing EXC_* by X86_EXC_* (such that EXC_* don't need to move as well; we want these to be phased out anyway). Signed-off-by: Jan Beulich --- a/tools/fuzz/x86_instruction_emulator/Makefile +++ b/tools/fuzz/x86_instruction_emulator/Makefile @@ -36,7 +36,7 @@ x86_emulate.h :=3D x86-emulate.h x86_emula =20 OBJS :=3D fuzz-emul.o x86-emulate.o OBJS +=3D x86_emulate/0f01.o x86_emulate/0fae.o x86_emulate/0fc7.o -OBJS +=3D x86_emulate/fpu.o +OBJS +=3D x86_emulate/decode.o x86_emulate/fpu.o =20 # x86-emulate.c will be implicit for both x86-emulate.o x86-emulate-cov.o: x86_emulate/x86_emulate.c $(x86_emulate.h= ) x86_emulate/private.h --- a/tools/tests/x86_emulator/Makefile +++ b/tools/tests/x86_emulator/Makefile @@ -252,7 +252,7 @@ endif # 32-bit override =20 OBJS :=3D x86-emulate.o cpuid.o test_x86_emulator.o evex-disp8.o predicate= s.o wrappers.o OBJS +=3D x86_emulate/0f01.o x86_emulate/0fae.o x86_emulate/0fc7.o -OBJS +=3D x86_emulate/fpu.o +OBJS +=3D x86_emulate/decode.o x86_emulate/fpu.o =20 $(TARGET): $(OBJS) $(HOSTCC) $(HOSTCFLAGS) -o $@ $^ --- a/tools/tests/x86_emulator/x86-emulate.c +++ b/tools/tests/x86_emulator/x86-emulate.c @@ -3,11 +3,6 @@ #include #include =20 -#define DEFINE_PER_CPU(type, var) type per_cpu_##var -#define this_cpu(var) per_cpu_##var - -#define ERR_PTR(val) NULL - /* See gcc bug 100680, but here don't bother making this version dependent= . */ #define gcc11_wrap(x) ({ \ unsigned long x_; \ --- a/tools/tests/x86_emulator/x86-emulate.h +++ b/tools/tests/x86_emulator/x86-emulate.h @@ -48,6 +48,9 @@ #define ASSERT assert #define ASSERT_UNREACHABLE() assert(!__LINE__) =20 +#define DEFINE_PER_CPU(type, var) type per_cpu_##var +#define this_cpu(var) per_cpu_##var + #define MASK_EXTR(v, m) (((v) & (m)) / ((m) & -(m))) #define MASK_INSR(v, m) (((v) * ((m) & -(m))) & (m)) =20 --- a/xen/arch/x86/x86_emulate.c +++ b/xen/arch/x86/x86_emulate.c @@ -9,7 +9,6 @@ * Keir Fraser */ =20 -#include #include #include #include /* current_cpu_info */ --- a/xen/arch/x86/x86_emulate/Makefile +++ b/xen/arch/x86/x86_emulate/Makefile @@ -1,4 +1,5 @@ obj-y +=3D 0f01.o obj-y +=3D 0fae.o obj-y +=3D 0fc7.o +obj-y +=3D decode.o obj-$(CONFIG_HVM) +=3D fpu.o --- /dev/null +++ b/xen/arch/x86/x86_emulate/decode.c @@ -0,0 +1,1750 @@ +/*************************************************************************= ***** + * decode.c - helper for x86_emulate.c + * + * Generic x86 (32-bit and 64-bit) instruction decoder and emulator. + * + * Copyright (c) 2005-2007 Keir Fraser + * Copyright (c) 2005-2007 XenSource Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; If not, see . + */ + +#include "private.h" + +#ifdef __XEN__ +# include +#else +# define ERR_PTR(val) NULL +#endif + +#define evex_encoded() (s->evex.mbs) + +struct x86_emulate_state * +x86_decode_insn( + struct x86_emulate_ctxt *ctxt, + int (*insn_fetch)( + enum x86_segment seg, unsigned long offset, + void *p_data, unsigned int bytes, + struct x86_emulate_ctxt *ctxt)) +{ + static DEFINE_PER_CPU(struct x86_emulate_state, state); + struct x86_emulate_state *s =3D &this_cpu(state); + const struct x86_emulate_ops ops =3D { + .insn_fetch =3D insn_fetch, + .read =3D x86emul_unhandleable_rw, + }; + int rc; + + init_context(ctxt); + + rc =3D x86emul_decode(s, ctxt, &ops); + if ( unlikely(rc !=3D X86EMUL_OKAY) ) + return ERR_PTR(-rc); + +#if defined(__XEN__) && !defined(NDEBUG) + /* + * While we avoid memory allocation (by use of per-CPU data) above, + * nevertheless make sure callers properly release the state structure + * for forward compatibility. + */ + if ( s->caller ) + { + printk(XENLOG_ERR "Unreleased emulation state acquired by %ps\n", + s->caller); + dump_execution_state(); + } + s->caller =3D __builtin_return_address(0); +#endif + + return s; +} + +static const opcode_desc_t opcode_table[256] =3D { + /* 0x00 - 0x07 */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + ByteOp|DstEax|SrcImm, DstEax|SrcImm, ImplicitOps|Mov, ImplicitOps|Mov, + /* 0x08 - 0x0F */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + ByteOp|DstEax|SrcImm, DstEax|SrcImm, ImplicitOps|Mov, 0, + /* 0x10 - 0x17 */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + ByteOp|DstEax|SrcImm, DstEax|SrcImm, ImplicitOps|Mov, ImplicitOps|Mov, + /* 0x18 - 0x1F */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + ByteOp|DstEax|SrcImm, DstEax|SrcImm, ImplicitOps|Mov, ImplicitOps|Mov, + /* 0x20 - 0x27 */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + ByteOp|DstEax|SrcImm, DstEax|SrcImm, 0, ImplicitOps, + /* 0x28 - 0x2F */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + ByteOp|DstEax|SrcImm, DstEax|SrcImm, 0, ImplicitOps, + /* 0x30 - 0x37 */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + ByteOp|DstEax|SrcImm, DstEax|SrcImm, 0, ImplicitOps, + /* 0x38 - 0x3F */ + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + ByteOp|DstEax|SrcImm, DstEax|SrcImm, 0, ImplicitOps, + /* 0x40 - 0x4F */ + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + /* 0x50 - 0x5F */ + ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, + ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, + ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, + ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, + /* 0x60 - 0x67 */ + ImplicitOps, ImplicitOps, DstReg|SrcMem|ModRM, DstReg|SrcNone|ModRM|Mo= v, + 0, 0, 0, 0, + /* 0x68 - 0x6F */ + DstImplicit|SrcImm|Mov, DstReg|SrcImm|ModRM|Mov, + DstImplicit|SrcImmByte|Mov, DstReg|SrcImmByte|ModRM|Mov, + ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, + /* 0x70 - 0x77 */ + DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, + DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, + DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, + DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, + /* 0x78 - 0x7F */ + DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, + DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, + DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, + DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, + /* 0x80 - 0x87 */ + ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImm|ModRM, + ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + /* 0x88 - 0x8F */ + ByteOp|DstMem|SrcReg|ModRM|Mov, DstMem|SrcReg|ModRM|Mov, + ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, + DstMem|SrcReg|ModRM|Mov, DstReg|SrcNone|ModRM, + DstReg|SrcMem16|ModRM|Mov, DstMem|SrcNone|ModRM|Mov, + /* 0x90 - 0x97 */ + DstImplicit|SrcEax, DstImplicit|SrcEax, + DstImplicit|SrcEax, DstImplicit|SrcEax, + DstImplicit|SrcEax, DstImplicit|SrcEax, + DstImplicit|SrcEax, DstImplicit|SrcEax, + /* 0x98 - 0x9F */ + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps, ImplicitOps, + /* 0xA0 - 0xA7 */ + ByteOp|DstEax|SrcMem|Mov, DstEax|SrcMem|Mov, + ByteOp|DstMem|SrcEax|Mov, DstMem|SrcEax|Mov, + ByteOp|ImplicitOps|Mov, ImplicitOps|Mov, + ByteOp|ImplicitOps, ImplicitOps, + /* 0xA8 - 0xAF */ + ByteOp|DstEax|SrcImm, DstEax|SrcImm, + ByteOp|DstImplicit|SrcEax|Mov, DstImplicit|SrcEax|Mov, + ByteOp|DstEax|SrcImplicit|Mov, DstEax|SrcImplicit|Mov, + ByteOp|DstImplicit|SrcEax, DstImplicit|SrcEax, + /* 0xB0 - 0xB7 */ + ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov, + ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov, + ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov, + ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov, + /* 0xB8 - 0xBF */ + DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm= |Mov, + DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm= |Mov, + /* 0xC0 - 0xC7 */ + ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM, + DstImplicit|SrcImm16, ImplicitOps, + DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, + ByteOp|DstMem|SrcImm|ModRM|Mov, DstMem|SrcImm|ModRM|Mov, + /* 0xC8 - 0xCF */ + DstImplicit|SrcImm16, ImplicitOps, DstImplicit|SrcImm16, ImplicitOps, + ImplicitOps, DstImplicit|SrcImmByte, ImplicitOps, ImplicitOps, + /* 0xD0 - 0xD7 */ + ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM, + ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM, + DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, ImplicitOps, ImplicitO= ps, + /* 0xD8 - 0xDF */ + ImplicitOps|ModRM, ImplicitOps|ModRM|Mov, + ImplicitOps|ModRM, ImplicitOps|ModRM|Mov, + ImplicitOps|ModRM, ImplicitOps|ModRM|Mov, + DstImplicit|SrcMem16|ModRM, ImplicitOps|ModRM|Mov, + /* 0xE0 - 0xE7 */ + DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, + DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, + DstEax|SrcImmByte, DstEax|SrcImmByte, + DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, + /* 0xE8 - 0xEF */ + DstImplicit|SrcImm|Mov, DstImplicit|SrcImm, + ImplicitOps, DstImplicit|SrcImmByte, + DstEax|SrcImplicit, DstEax|SrcImplicit, ImplicitOps, ImplicitOps, + /* 0xF0 - 0xF7 */ + 0, ImplicitOps, 0, 0, + ImplicitOps, ImplicitOps, ByteOp|ModRM, ModRM, + /* 0xF8 - 0xFF */ + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + ImplicitOps, ImplicitOps, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|= ModRM +}; + +static const struct twobyte_table { + opcode_desc_t desc; + simd_opsize_t size:4; + disp8scale_t d8s:4; +} twobyte_table[256] =3D { + [0x00] =3D { ModRM }, + [0x01] =3D { ImplicitOps|ModRM }, + [0x02] =3D { DstReg|SrcMem16|ModRM }, + [0x03] =3D { DstReg|SrcMem16|ModRM }, + [0x05] =3D { ImplicitOps }, + [0x06] =3D { ImplicitOps }, + [0x07] =3D { ImplicitOps }, + [0x08] =3D { ImplicitOps }, + [0x09] =3D { ImplicitOps }, + [0x0b] =3D { ImplicitOps }, + [0x0d] =3D { ImplicitOps|ModRM }, + [0x0e] =3D { ImplicitOps }, + [0x0f] =3D { ModRM|SrcImmByte }, + [0x10] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_any_fp, d8s_vl }, + [0x11] =3D { DstMem|SrcImplicit|ModRM|Mov, simd_any_fp, d8s_vl }, + [0x12] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_other, 3 }, + [0x13] =3D { DstMem|SrcImplicit|ModRM|Mov, simd_other, 3 }, + [0x14 ... 0x15] =3D { DstImplicit|SrcMem|ModRM, simd_packed_fp, d8s_vl= }, + [0x16] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_other, 3 }, + [0x17] =3D { DstMem|SrcImplicit|ModRM|Mov, simd_other, 3 }, + [0x18 ... 0x1f] =3D { ImplicitOps|ModRM }, + [0x20 ... 0x21] =3D { DstMem|SrcImplicit|ModRM }, + [0x22 ... 0x23] =3D { DstImplicit|SrcMem|ModRM }, + [0x28] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_packed_fp, d8s_vl }, + [0x29] =3D { DstMem|SrcImplicit|ModRM|Mov, simd_packed_fp, d8s_vl }, + [0x2a] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_other, d8s_dq64 }, + [0x2b] =3D { DstMem|SrcImplicit|ModRM|Mov, simd_any_fp, d8s_vl }, + [0x2c ... 0x2d] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_other }, + [0x2e ... 0x2f] =3D { ImplicitOps|ModRM|TwoOp, simd_none, d8s_dq }, + [0x30 ... 0x35] =3D { ImplicitOps }, + [0x37] =3D { ImplicitOps }, + [0x38] =3D { DstReg|SrcMem|ModRM }, + [0x3a] =3D { DstReg|SrcImmByte|ModRM }, + [0x40 ... 0x4f] =3D { DstReg|SrcMem|ModRM|Mov }, + [0x50] =3D { DstReg|SrcImplicit|ModRM|Mov }, + [0x51] =3D { DstImplicit|SrcMem|ModRM|TwoOp, simd_any_fp, d8s_vl }, + [0x52 ... 0x53] =3D { DstImplicit|SrcMem|ModRM|TwoOp, simd_single_fp }, + [0x54 ... 0x57] =3D { DstImplicit|SrcMem|ModRM, simd_packed_fp, d8s_vl= }, + [0x58 ... 0x59] =3D { DstImplicit|SrcMem|ModRM, simd_any_fp, d8s_vl }, + [0x5a] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_any_fp, d8s_vl }, + [0x5b] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_packed_fp, d8s_vl }, + [0x5c ... 0x5f] =3D { DstImplicit|SrcMem|ModRM, simd_any_fp, d8s_vl }, + [0x60 ... 0x62] =3D { DstImplicit|SrcMem|ModRM, simd_other, d8s_vl }, + [0x63 ... 0x67] =3D { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_v= l }, + [0x68 ... 0x6a] =3D { DstImplicit|SrcMem|ModRM, simd_other, d8s_vl }, + [0x6b ... 0x6d] =3D { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_v= l }, + [0x6e] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_none, d8s_dq64 }, + [0x6f] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_packed_int, d8s_vl }, + [0x70] =3D { SrcImmByte|ModRM|TwoOp, simd_other, d8s_vl }, + [0x71 ... 0x73] =3D { DstImplicit|SrcImmByte|ModRM, simd_none, d8s_vl = }, + [0x74 ... 0x76] =3D { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_v= l }, + [0x77] =3D { DstImplicit|SrcNone }, + [0x78 ... 0x79] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_other, d8s_vl= }, + [0x7a] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_packed_fp, d8s_vl }, + [0x7b] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_other, d8s_dq64 }, + [0x7c ... 0x7d] =3D { DstImplicit|SrcMem|ModRM, simd_other }, + [0x7e] =3D { DstMem|SrcImplicit|ModRM|Mov, simd_none, d8s_dq64 }, + [0x7f] =3D { DstMem|SrcImplicit|ModRM|Mov, simd_packed_int, d8s_vl }, + [0x80 ... 0x8f] =3D { DstImplicit|SrcImm }, + [0x90 ... 0x9f] =3D { ByteOp|DstMem|SrcNone|ModRM|Mov }, + [0xa0 ... 0xa1] =3D { ImplicitOps|Mov }, + [0xa2] =3D { ImplicitOps }, + [0xa3] =3D { DstBitBase|SrcReg|ModRM }, + [0xa4] =3D { DstMem|SrcImmByte|ModRM }, + [0xa5] =3D { DstMem|SrcReg|ModRM }, + [0xa6 ... 0xa7] =3D { ModRM }, + [0xa8 ... 0xa9] =3D { ImplicitOps|Mov }, + [0xaa] =3D { ImplicitOps }, + [0xab] =3D { DstBitBase|SrcReg|ModRM }, + [0xac] =3D { DstMem|SrcImmByte|ModRM }, + [0xad] =3D { DstMem|SrcReg|ModRM }, + [0xae] =3D { ImplicitOps|ModRM }, + [0xaf] =3D { DstReg|SrcMem|ModRM }, + [0xb0] =3D { ByteOp|DstMem|SrcReg|ModRM }, + [0xb1] =3D { DstMem|SrcReg|ModRM }, + [0xb2] =3D { DstReg|SrcMem|ModRM|Mov }, + [0xb3] =3D { DstBitBase|SrcReg|ModRM }, + [0xb4 ... 0xb5] =3D { DstReg|SrcMem|ModRM|Mov }, + [0xb6] =3D { ByteOp|DstReg|SrcMem|ModRM|Mov }, + [0xb7] =3D { DstReg|SrcMem16|ModRM|Mov }, + [0xb8] =3D { DstReg|SrcMem|ModRM }, + [0xb9] =3D { ModRM }, + [0xba] =3D { DstBitBase|SrcImmByte|ModRM }, + [0xbb] =3D { DstBitBase|SrcReg|ModRM }, + [0xbc ... 0xbd] =3D { DstReg|SrcMem|ModRM }, + [0xbe] =3D { ByteOp|DstReg|SrcMem|ModRM|Mov }, + [0xbf] =3D { DstReg|SrcMem16|ModRM|Mov }, + [0xc0] =3D { ByteOp|DstMem|SrcReg|ModRM }, + [0xc1] =3D { DstMem|SrcReg|ModRM }, + [0xc2] =3D { DstImplicit|SrcImmByte|ModRM, simd_any_fp, d8s_vl }, + [0xc3] =3D { DstMem|SrcReg|ModRM|Mov }, + [0xc4] =3D { DstImplicit|SrcImmByte|ModRM, simd_none, 1 }, + [0xc5] =3D { DstReg|SrcImmByte|ModRM|Mov }, + [0xc6] =3D { DstImplicit|SrcImmByte|ModRM, simd_packed_fp, d8s_vl }, + [0xc7] =3D { ImplicitOps|ModRM }, + [0xc8 ... 0xcf] =3D { ImplicitOps }, + [0xd0] =3D { DstImplicit|SrcMem|ModRM, simd_other }, + [0xd1 ... 0xd3] =3D { DstImplicit|SrcMem|ModRM, simd_128, 4 }, + [0xd4 ... 0xd5] =3D { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_v= l }, + [0xd6] =3D { DstMem|SrcImplicit|ModRM|Mov, simd_other, 3 }, + [0xd7] =3D { DstReg|SrcImplicit|ModRM|Mov }, + [0xd8 ... 0xdf] =3D { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_v= l }, + [0xe0] =3D { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl }, + [0xe1 ... 0xe2] =3D { DstImplicit|SrcMem|ModRM, simd_128, 4 }, + [0xe3 ... 0xe5] =3D { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_v= l }, + [0xe6] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_packed_fp, d8s_vl }, + [0xe7] =3D { DstMem|SrcImplicit|ModRM|Mov, simd_packed_int, d8s_vl }, + [0xe8 ... 0xef] =3D { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_v= l }, + [0xf0] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_other }, + [0xf1 ... 0xf3] =3D { DstImplicit|SrcMem|ModRM, simd_128, 4 }, + [0xf4 ... 0xf6] =3D { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_v= l }, + [0xf7] =3D { DstMem|SrcMem|ModRM|Mov, simd_packed_int }, + [0xf8 ... 0xfe] =3D { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_v= l }, + [0xff] =3D { ModRM } +}; + +/* + * "two_op" and "four_op" below refer to the number of register operands + * (one of which possibly also allowing to be a memory one). The named + * operand counts do not include any immediate operands. + */ +static const struct ext0f38_table { + uint8_t simd_size:5; + uint8_t to_mem:1; + uint8_t two_op:1; + uint8_t vsib:1; + disp8scale_t d8s:4; +} ext0f38_table[256] =3D { + [0x00] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, + [0x01 ... 0x03] =3D { .simd_size =3D simd_packed_int }, + [0x04] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, + [0x05 ... 0x0a] =3D { .simd_size =3D simd_packed_int }, + [0x0b] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, + [0x0c ... 0x0d] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, + [0x0e ... 0x0f] =3D { .simd_size =3D simd_packed_fp }, + [0x10 ... 0x12] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, + [0x13] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_2 }, + [0x14 ... 0x16] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, + [0x17] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, + [0x18] =3D { .simd_size =3D simd_scalar_opc, .two_op =3D 1, .d8s =3D 2= }, + [0x19] =3D { .simd_size =3D simd_scalar_opc, .two_op =3D 1, .d8s =3D 3= }, + [0x1a] =3D { .simd_size =3D simd_128, .two_op =3D 1, .d8s =3D 4 }, + [0x1b] =3D { .simd_size =3D simd_256, .two_op =3D 1, .d8s =3D d8s_vl_b= y_2 }, + [0x1c ... 0x1f] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1, .= d8s =3D d8s_vl }, + [0x20] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_2 }, + [0x21] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_4 }, + [0x22] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_8 }, + [0x23] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_2 }, + [0x24] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_4 }, + [0x25] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_2 }, + [0x26 ... 0x29] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, + [0x2a] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1, .d8s =3D d= 8s_vl }, + [0x2b] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, + [0x2c] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, + [0x2d] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_dq }, + [0x2e ... 0x2f] =3D { .simd_size =3D simd_packed_fp, .to_mem =3D 1 }, + [0x30] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_2 }, + [0x31] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_4 }, + [0x32] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_8 }, + [0x33] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_2 }, + [0x34] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_4 }, + [0x35] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_2 }, + [0x36 ... 0x3f] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, + [0x40] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, + [0x41] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, + [0x42] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d8s =3D d8= s_vl }, + [0x43] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, + [0x44] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1, .d8s =3D d= 8s_vl }, + [0x45 ... 0x47] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, + [0x4c] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d8s =3D d8= s_vl }, + [0x4d] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, + [0x4e] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d8s =3D d8= s_vl }, + [0x4f] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, + [0x50 ... 0x53] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, + [0x54 ... 0x55] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1, .= d8s =3D d8s_vl }, + [0x58] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D 2 }, + [0x59] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D 3 }, + [0x5a] =3D { .simd_size =3D simd_128, .two_op =3D 1, .d8s =3D 4 }, + [0x5b] =3D { .simd_size =3D simd_256, .two_op =3D 1, .d8s =3D d8s_vl_b= y_2 }, + [0x62] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1, .d8s =3D d= 8s_bw }, + [0x63] =3D { .simd_size =3D simd_packed_int, .to_mem =3D 1, .two_op = =3D 1, .d8s =3D d8s_bw }, + [0x64 ... 0x66] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, + [0x68] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, + [0x70 ... 0x73] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, + [0x75 ... 0x76] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, + [0x77] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, + [0x78] =3D { .simd_size =3D simd_other, .two_op =3D 1 }, + [0x79] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D 1 }, + [0x7a ... 0x7c] =3D { .simd_size =3D simd_none, .two_op =3D 1 }, + [0x7d ... 0x7e] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, + [0x7f] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, + [0x82] =3D { .simd_size =3D simd_other }, + [0x83] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, + [0x88] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d8s =3D d8= s_dq }, + [0x89] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1, .d8s =3D d= 8s_dq }, + [0x8a] =3D { .simd_size =3D simd_packed_fp, .to_mem =3D 1, .two_op =3D= 1, .d8s =3D d8s_dq }, + [0x8b] =3D { .simd_size =3D simd_packed_int, .to_mem =3D 1, .two_op = =3D 1, .d8s =3D d8s_dq }, + [0x8c] =3D { .simd_size =3D simd_packed_int }, + [0x8d] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, + [0x8e] =3D { .simd_size =3D simd_packed_int, .to_mem =3D 1 }, + [0x8f] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, + [0x90 ... 0x93] =3D { .simd_size =3D simd_other, .vsib =3D 1, .d8s =3D= d8s_dq }, + [0x96 ... 0x98] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, + [0x99] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, + [0x9a] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, + [0x9b] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, + [0x9c] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, + [0x9d] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, + [0x9e] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, + [0x9f] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, + [0xa0 ... 0xa3] =3D { .simd_size =3D simd_other, .to_mem =3D 1, .vsib = =3D 1, .d8s =3D d8s_dq }, + [0xa6 ... 0xa8] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, + [0xa9] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, + [0xaa] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, + [0xab] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, + [0xac] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, + [0xad] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, + [0xae] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, + [0xaf] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, + [0xb4 ... 0xb5] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, + [0xb6 ... 0xb8] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, + [0xb9] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, + [0xba] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, + [0xbb] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, + [0xbc] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, + [0xbd] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, + [0xbe] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, + [0xbf] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, + [0xc4] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1, .d8s =3D d= 8s_vl }, + [0xc6 ... 0xc7] =3D { .simd_size =3D simd_other, .vsib =3D 1, .d8s =3D= d8s_dq }, + [0xc8] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d8s =3D d8= s_vl }, + [0xc9] =3D { .simd_size =3D simd_other }, + [0xca] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d8s =3D d8= s_vl }, + [0xcb] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, + [0xcc] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d8s =3D d8= s_vl }, + [0xcd] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, + [0xcf] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, + [0xdb] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, + [0xdc ... 0xdf] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, + [0xf0] =3D { .two_op =3D 1 }, + [0xf1] =3D { .to_mem =3D 1, .two_op =3D 1 }, + [0xf2 ... 0xf3] =3D {}, + [0xf5 ... 0xf7] =3D {}, + [0xf8] =3D { .simd_size =3D simd_other }, + [0xf9] =3D { .to_mem =3D 1, .two_op =3D 1 /* Mov */ }, +}; + +static const struct ext0f3a_table { + uint8_t simd_size:5; + uint8_t to_mem:1; + uint8_t two_op:1; + uint8_t four_op:1; + disp8scale_t d8s:4; +} ext0f3a_table[256] =3D { + [0x00] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1, .d8s =3D d= 8s_vl }, + [0x01] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d8s =3D d8= s_vl }, + [0x02] =3D { .simd_size =3D simd_packed_int }, + [0x03] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, + [0x04 ... 0x05] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d= 8s =3D d8s_vl }, + [0x06] =3D { .simd_size =3D simd_packed_fp }, + [0x08 ... 0x09] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d= 8s =3D d8s_vl }, + [0x0a ... 0x0b] =3D { .simd_size =3D simd_scalar_opc, .d8s =3D d8s_dq = }, + [0x0c ... 0x0d] =3D { .simd_size =3D simd_packed_fp }, + [0x0e] =3D { .simd_size =3D simd_packed_int }, + [0x0f] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, + [0x14] =3D { .simd_size =3D simd_none, .to_mem =3D 1, .two_op =3D 1, .= d8s =3D 0 }, + [0x15] =3D { .simd_size =3D simd_none, .to_mem =3D 1, .two_op =3D 1, .= d8s =3D 1 }, + [0x16] =3D { .simd_size =3D simd_none, .to_mem =3D 1, .two_op =3D 1, .= d8s =3D d8s_dq64 }, + [0x17] =3D { .simd_size =3D simd_none, .to_mem =3D 1, .two_op =3D 1, .= d8s =3D 2 }, + [0x18] =3D { .simd_size =3D simd_128, .d8s =3D 4 }, + [0x19] =3D { .simd_size =3D simd_128, .to_mem =3D 1, .two_op =3D 1, .d= 8s =3D 4 }, + [0x1a] =3D { .simd_size =3D simd_256, .d8s =3D d8s_vl_by_2 }, + [0x1b] =3D { .simd_size =3D simd_256, .to_mem =3D 1, .two_op =3D 1, .d= 8s =3D d8s_vl_by_2 }, + [0x1d] =3D { .simd_size =3D simd_other, .to_mem =3D 1, .two_op =3D 1, = .d8s =3D d8s_vl_by_2 }, + [0x1e ... 0x1f] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, + [0x20] =3D { .simd_size =3D simd_none, .d8s =3D 0 }, + [0x21] =3D { .simd_size =3D simd_other, .d8s =3D 2 }, + [0x22] =3D { .simd_size =3D simd_none, .d8s =3D d8s_dq64 }, + [0x23] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, + [0x25] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, + [0x26] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d8s =3D d8= s_vl }, + [0x27] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, + [0x30 ... 0x33] =3D { .simd_size =3D simd_other, .two_op =3D 1 }, + [0x38] =3D { .simd_size =3D simd_128, .d8s =3D 4 }, + [0x3a] =3D { .simd_size =3D simd_256, .d8s =3D d8s_vl_by_2 }, + [0x39] =3D { .simd_size =3D simd_128, .to_mem =3D 1, .two_op =3D 1, .d= 8s =3D 4 }, + [0x3b] =3D { .simd_size =3D simd_256, .to_mem =3D 1, .two_op =3D 1, .d= 8s =3D d8s_vl_by_2 }, + [0x3e ... 0x3f] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, + [0x40 ... 0x41] =3D { .simd_size =3D simd_packed_fp }, + [0x42 ... 0x43] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, + [0x44] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, + [0x46] =3D { .simd_size =3D simd_packed_int }, + [0x48 ... 0x49] =3D { .simd_size =3D simd_packed_fp, .four_op =3D 1 }, + [0x4a ... 0x4b] =3D { .simd_size =3D simd_packed_fp, .four_op =3D 1 }, + [0x4c] =3D { .simd_size =3D simd_packed_int, .four_op =3D 1 }, + [0x50] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, + [0x51] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, + [0x54] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, + [0x55] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, + [0x56] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d8s =3D d8= s_vl }, + [0x57] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, + [0x5c ... 0x5f] =3D { .simd_size =3D simd_packed_fp, .four_op =3D 1 }, + [0x60 ... 0x63] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, + [0x66] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d8s =3D d8= s_vl }, + [0x67] =3D { .simd_size =3D simd_scalar_vexw, .two_op =3D 1, .d8s =3D = d8s_dq }, + [0x68 ... 0x69] =3D { .simd_size =3D simd_packed_fp, .four_op =3D 1 }, + [0x6a ... 0x6b] =3D { .simd_size =3D simd_scalar_opc, .four_op =3D 1 }, + [0x6c ... 0x6d] =3D { .simd_size =3D simd_packed_fp, .four_op =3D 1 }, + [0x6e ... 0x6f] =3D { .simd_size =3D simd_scalar_opc, .four_op =3D 1 }, + [0x70 ... 0x73] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, + [0x78 ... 0x79] =3D { .simd_size =3D simd_packed_fp, .four_op =3D 1 }, + [0x7a ... 0x7b] =3D { .simd_size =3D simd_scalar_opc, .four_op =3D 1 }, + [0x7c ... 0x7d] =3D { .simd_size =3D simd_packed_fp, .four_op =3D 1 }, + [0x7e ... 0x7f] =3D { .simd_size =3D simd_scalar_opc, .four_op =3D 1 }, + [0xcc] =3D { .simd_size =3D simd_other }, + [0xce ... 0xcf] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, + [0xdf] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, + [0xf0] =3D {}, +}; + +static const opcode_desc_t xop_table[] =3D { + DstReg|SrcImmByte|ModRM, + DstReg|SrcMem|ModRM, + DstReg|SrcImm|ModRM, +}; + +static const struct ext8f08_table { + uint8_t simd_size:5; + uint8_t two_op:1; + uint8_t four_op:1; +} ext8f08_table[256] =3D { + [0xa2] =3D { .simd_size =3D simd_packed_int, .four_op =3D 1 }, + [0x85 ... 0x87] =3D { .simd_size =3D simd_packed_int, .four_op =3D 1 }, + [0x8e ... 0x8f] =3D { .simd_size =3D simd_packed_int, .four_op =3D 1 }, + [0x95 ... 0x97] =3D { .simd_size =3D simd_packed_int, .four_op =3D 1 }, + [0x9e ... 0x9f] =3D { .simd_size =3D simd_packed_int, .four_op =3D 1 }, + [0xa3] =3D { .simd_size =3D simd_packed_int, .four_op =3D 1 }, + [0xa6] =3D { .simd_size =3D simd_packed_int, .four_op =3D 1 }, + [0xb6] =3D { .simd_size =3D simd_packed_int, .four_op =3D 1 }, + [0xc0 ... 0xc3] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, + [0xcc ... 0xcf] =3D { .simd_size =3D simd_packed_int }, + [0xec ... 0xef] =3D { .simd_size =3D simd_packed_int }, +}; + +static const struct ext8f09_table { + uint8_t simd_size:5; + uint8_t two_op:1; +} ext8f09_table[256] =3D { + [0x01 ... 0x02] =3D { .two_op =3D 1 }, + [0x80 ... 0x81] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1 }, + [0x82 ... 0x83] =3D { .simd_size =3D simd_scalar_opc, .two_op =3D 1 }, + [0x90 ... 0x9b] =3D { .simd_size =3D simd_packed_int }, + [0xc1 ... 0xc3] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, + [0xc6 ... 0xc7] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, + [0xcb] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, + [0xd1 ... 0xd3] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, + [0xd6 ... 0xd7] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, + [0xdb] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, + [0xe1 ... 0xe3] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, +}; + +static unsigned int decode_disp8scale(enum disp8scale scale, + const struct x86_emulate_state *s) +{ + switch ( scale ) + { + case d8s_bw: + return s->evex.w; + + default: + if ( scale < d8s_vl ) + return scale; + if ( s->evex.brs ) + { + case d8s_dq: + return 2 + s->evex.w; + } + break; + + case d8s_dq64: + return 2 + (s->op_bytes =3D=3D 8); + } + + switch ( s->simd_size ) + { + case simd_any_fp: + case simd_single_fp: + if ( !(s->evex.pfx & VEX_PREFIX_SCALAR_MASK) ) + break; + /* fall through */ + case simd_scalar_opc: + case simd_scalar_vexw: + return 2 + s->evex.w; + + case simd_128: + /* These should have an explicit size specified. */ + ASSERT_UNREACHABLE(); + return 4; + + default: + break; + } + + return 4 + s->evex.lr - (scale - d8s_vl); +} + +/* Fetch next part of the instruction being emulated. */ +#define insn_fetch_bytes(_size) ({ \ + unsigned long _x =3D 0, _ip =3D s->ip; \ + s->ip +=3D (_size); /* real hardware doesn't truncate */ \ + generate_exception_if((uint8_t)(s->ip - \ + ctxt->regs->r(ip)) > MAX_INST_LEN, \ + X86_EXC_GP, 0); \ + rc =3D ops->insn_fetch(x86_seg_cs, _ip, &_x, _size, ctxt); \ + if ( rc ) goto done; \ + _x; \ +}) +#define insn_fetch_type(type) ((type)insn_fetch_bytes(sizeof(type))) + +static int +decode_onebyte(struct x86_emulate_state *s, + struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops) +{ + int rc =3D X86EMUL_OKAY; + + switch ( ctxt->opcode ) + { + case 0x06: /* push %%es */ + case 0x07: /* pop %%es */ + case 0x0e: /* push %%cs */ + case 0x16: /* push %%ss */ + case 0x17: /* pop %%ss */ + case 0x1e: /* push %%ds */ + case 0x1f: /* pop %%ds */ + case 0x27: /* daa */ + case 0x2f: /* das */ + case 0x37: /* aaa */ + case 0x3f: /* aas */ + case 0x60: /* pusha */ + case 0x61: /* popa */ + case 0x62: /* bound */ + case 0xc4: /* les */ + case 0xc5: /* lds */ + case 0xce: /* into */ + case 0xd4: /* aam */ + case 0xd5: /* aad */ + case 0xd6: /* salc */ + s->not_64bit =3D true; + break; + + case 0x82: /* Grp1 (x86/32 only) */ + s->not_64bit =3D true; + /* fall through */ + case 0x80: case 0x81: case 0x83: /* Grp1 */ + if ( (s->modrm_reg & 7) =3D=3D 7 ) /* cmp */ + s->desc =3D (s->desc & ByteOp) | DstNone | SrcMem; + break; + + case 0x90: /* nop / pause */ + if ( s->vex.pfx =3D=3D vex_f3 ) + ctxt->opcode |=3D X86EMUL_OPC_F3(0, 0); + break; + + case 0x9a: /* call (far, absolute) */ + case 0xea: /* jmp (far, absolute) */ + generate_exception_if(mode_64bit(), X86_EXC_UD); + + s->imm1 =3D insn_fetch_bytes(s->op_bytes); + s->imm2 =3D insn_fetch_type(uint16_t); + break; + + case 0xa0: case 0xa1: /* mov mem.offs,{%al,%ax,%eax,%rax} */ + case 0xa2: case 0xa3: /* mov {%al,%ax,%eax,%rax},mem.offs */ + /* Source EA is not encoded via ModRM. */ + s->ea.type =3D OP_MEM; + s->ea.mem.off =3D insn_fetch_bytes(s->ad_bytes); + break; + + case 0xb8 ... 0xbf: /* mov imm{16,32,64},r{16,32,64} */ + if ( s->op_bytes =3D=3D 8 ) /* Fetch more bytes to obtain imm64. */ + s->imm1 =3D ((uint32_t)s->imm1 | + ((uint64_t)insn_fetch_type(uint32_t) << 32)); + break; + + case 0xc8: /* enter imm16,imm8 */ + s->imm2 =3D insn_fetch_type(uint8_t); + break; + + case 0xf6: case 0xf7: /* Grp3 */ + if ( !(s->modrm_reg & 6) ) /* test */ + s->desc =3D (s->desc & ByteOp) | DstNone | SrcMem; + break; + + case 0xff: /* Grp5 */ + switch ( s->modrm_reg & 7 ) + { + case 2: /* call (near) */ + case 4: /* jmp (near) */ + if ( mode_64bit() && (s->op_bytes =3D=3D 4 || !amd_like(ctxt))= ) + s->op_bytes =3D 8; + s->desc =3D DstNone | SrcMem | Mov; + break; + + case 3: /* call (far, absolute indirect) */ + case 5: /* jmp (far, absolute indirect) */ + /* REX.W ignored on a vendor-dependent basis. */ + if ( s->op_bytes =3D=3D 8 && amd_like(ctxt) ) + s->op_bytes =3D 4; + s->desc =3D DstNone | SrcMem | Mov; + break; + + case 6: /* push */ + if ( mode_64bit() && s->op_bytes =3D=3D 4 ) + s->op_bytes =3D 8; + s->desc =3D DstNone | SrcMem | Mov; + break; + } + break; + } + + done: + return rc; +} + +static int +decode_twobyte(struct x86_emulate_state *s, + struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops) +{ + int rc =3D X86EMUL_OKAY; + + switch ( ctxt->opcode & X86EMUL_OPC_MASK ) + { + case 0x00: /* Grp6 */ + switch ( s->modrm_reg & 6 ) + { + case 0: + s->desc |=3D DstMem | SrcImplicit | Mov; + break; + case 2: case 4: + s->desc |=3D SrcMem16; + break; + } + break; + + case 0x78: + s->desc =3D ImplicitOps; + s->simd_size =3D simd_none; + switch ( s->vex.pfx ) + { + case vex_66: /* extrq $imm8, $imm8, xmm */ + case vex_f2: /* insertq $imm8, $imm8, xmm, xmm */ + s->imm1 =3D insn_fetch_type(uint8_t); + s->imm2 =3D insn_fetch_type(uint8_t); + break; + } + /* fall through */ + case 0x10 ... 0x18: + case 0x28 ... 0x2f: + case 0x50 ... 0x77: + case 0x7a ... 0x7d: + case 0x7f: + case 0xc2 ... 0xc3: + case 0xc5 ... 0xc6: + case 0xd0 ... 0xef: + case 0xf1 ... 0xfe: + ctxt->opcode |=3D MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK); + break; + + case 0x20: case 0x22: /* mov to/from cr */ + if ( s->lock_prefix && vcpu_has_cr8_legacy() ) + { + s->modrm_reg +=3D 8; + s->lock_prefix =3D false; + } + /* fall through */ + case 0x21: case 0x23: /* mov to/from dr */ + ASSERT(s->ea.type =3D=3D OP_REG); /* Early operand adjustment ensu= res this. */ + generate_exception_if(s->lock_prefix, X86_EXC_UD); + s->op_bytes =3D mode_64bit() ? 8 : 4; + break; + + case 0x79: + s->desc =3D DstReg | SrcMem; + s->simd_size =3D simd_packed_int; + ctxt->opcode |=3D MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK); + break; + + case 0x7e: + ctxt->opcode |=3D MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK); + if ( s->vex.pfx =3D=3D vex_f3 ) /* movq xmm/m64,xmm */ + { + case X86EMUL_OPC_VEX_F3(0, 0x7e): /* vmovq xmm/m64,xmm */ + case X86EMUL_OPC_EVEX_F3(0, 0x7e): /* vmovq xmm/m64,xmm */ + s->desc =3D DstImplicit | SrcMem | TwoOp; + s->simd_size =3D simd_other; + /* Avoid the s->desc clobbering of TwoOp below. */ + return X86EMUL_OKAY; + } + break; + + case X86EMUL_OPC_VEX(0, 0x90): /* kmov{w,q} */ + case X86EMUL_OPC_VEX_66(0, 0x90): /* kmov{b,d} */ + s->desc =3D DstReg | SrcMem | Mov; + s->simd_size =3D simd_other; + break; + + case X86EMUL_OPC_VEX(0, 0x91): /* kmov{w,q} */ + case X86EMUL_OPC_VEX_66(0, 0x91): /* kmov{b,d} */ + s->desc =3D DstMem | SrcReg | Mov; + s->simd_size =3D simd_other; + break; + + case 0xae: + ctxt->opcode |=3D MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK); + /* fall through */ + case X86EMUL_OPC_VEX(0, 0xae): + switch ( s->modrm_reg & 7 ) + { + case 2: /* {,v}ldmxcsr */ + s->desc =3D DstImplicit | SrcMem | Mov; + s->op_bytes =3D 4; + break; + + case 3: /* {,v}stmxcsr */ + s->desc =3D DstMem | SrcImplicit | Mov; + s->op_bytes =3D 4; + break; + } + break; + + case 0xb2: /* lss */ + case 0xb4: /* lfs */ + case 0xb5: /* lgs */ + /* REX.W ignored on a vendor-dependent basis. */ + if ( s->op_bytes =3D=3D 8 && amd_like(ctxt) ) + s->op_bytes =3D 4; + break; + + case 0xb8: /* jmpe / popcnt */ + if ( s->vex.pfx >=3D vex_f3 ) + ctxt->opcode |=3D MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK); + break; + + /* Intentionally not handling here despite being modified by F3: + case 0xbc: bsf / tzcnt + case 0xbd: bsr / lzcnt + * They're being dealt with in the execution phase (if at all). + */ + + case 0xc4: /* pinsrw */ + ctxt->opcode |=3D MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK); + /* fall through */ + case X86EMUL_OPC_VEX_66(0, 0xc4): /* vpinsrw */ + case X86EMUL_OPC_EVEX_66(0, 0xc4): /* vpinsrw */ + s->desc =3D DstImplicit | SrcMem16; + break; + + case 0xf0: + ctxt->opcode |=3D MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK); + if ( s->vex.pfx =3D=3D vex_f2 ) /* lddqu mem,xmm */ + { + /* fall through */ + case X86EMUL_OPC_VEX_F2(0, 0xf0): /* vlddqu mem,{x,y}mm */ + s->desc =3D DstImplicit | SrcMem | TwoOp; + s->simd_size =3D simd_other; + /* Avoid the s->desc clobbering of TwoOp below. */ + return X86EMUL_OKAY; + } + break; + } + + /* + * Scalar forms of most VEX-/EVEX-encoded TwoOp instructions have + * three operands. Those which do really have two operands + * should have exited earlier. + */ + if ( s->simd_size && s->vex.opcx && + (s->vex.pfx & VEX_PREFIX_SCALAR_MASK) ) + s->desc &=3D ~TwoOp; + + done: + return rc; +} + +static int +decode_0f38(struct x86_emulate_state *s, + struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops) +{ + switch ( ctxt->opcode & X86EMUL_OPC_MASK ) + { + case 0x00 ... 0xef: + case 0xf2 ... 0xf5: + case 0xf7 ... 0xf8: + case 0xfa ... 0xff: + s->op_bytes =3D 0; + /* fall through */ + case 0xf6: /* adcx / adox */ + case 0xf9: /* movdiri */ + ctxt->opcode |=3D MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK); + break; + + case X86EMUL_OPC_EVEX_66(0, 0x2d): /* vscalefs{s,d} */ + s->simd_size =3D simd_scalar_vexw; + break; + + case X86EMUL_OPC_EVEX_66(0, 0x7a): /* vpbroadcastb */ + case X86EMUL_OPC_EVEX_66(0, 0x7b): /* vpbroadcastw */ + case X86EMUL_OPC_EVEX_66(0, 0x7c): /* vpbroadcast{d,q} */ + break; + + case 0xf0: /* movbe / crc32 */ + s->desc |=3D s->vex.pfx =3D=3D vex_f2 ? ByteOp : Mov; + if ( s->vex.pfx >=3D vex_f3 ) + ctxt->opcode |=3D MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK); + break; + + case 0xf1: /* movbe / crc32 */ + if ( s->vex.pfx =3D=3D vex_f2 ) + s->desc =3D DstReg | SrcMem; + if ( s->vex.pfx >=3D vex_f3 ) + ctxt->opcode |=3D MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK); + break; + + case X86EMUL_OPC_VEX(0, 0xf2): /* andn */ + case X86EMUL_OPC_VEX(0, 0xf3): /* Grp 17 */ + case X86EMUL_OPC_VEX(0, 0xf5): /* bzhi */ + case X86EMUL_OPC_VEX_F3(0, 0xf5): /* pext */ + case X86EMUL_OPC_VEX_F2(0, 0xf5): /* pdep */ + case X86EMUL_OPC_VEX_F2(0, 0xf6): /* mulx */ + case X86EMUL_OPC_VEX(0, 0xf7): /* bextr */ + case X86EMUL_OPC_VEX_66(0, 0xf7): /* shlx */ + case X86EMUL_OPC_VEX_F3(0, 0xf7): /* sarx */ + case X86EMUL_OPC_VEX_F2(0, 0xf7): /* shrx */ + break; + + default: + s->op_bytes =3D 0; + break; + } + + return X86EMUL_OKAY; +} + +static int +decode_0f3a(struct x86_emulate_state *s, + struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops) +{ + if ( !s->vex.opcx ) + ctxt->opcode |=3D MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK); + + switch ( ctxt->opcode & X86EMUL_OPC_MASK ) + { + case X86EMUL_OPC_66(0, 0x14) + ... X86EMUL_OPC_66(0, 0x17): /* pextr*, extractps */ + case X86EMUL_OPC_VEX_66(0, 0x14) + ... X86EMUL_OPC_VEX_66(0, 0x17): /* vpextr*, vextractps */ + case X86EMUL_OPC_EVEX_66(0, 0x14) + ... X86EMUL_OPC_EVEX_66(0, 0x17): /* vpextr*, vextractps */ + case X86EMUL_OPC_VEX_F2(0, 0xf0): /* rorx */ + break; + + case X86EMUL_OPC_66(0, 0x20): /* pinsrb */ + case X86EMUL_OPC_VEX_66(0, 0x20): /* vpinsrb */ + case X86EMUL_OPC_EVEX_66(0, 0x20): /* vpinsrb */ + s->desc =3D DstImplicit | SrcMem; + if ( s->modrm_mod !=3D 3 ) + s->desc |=3D ByteOp; + break; + + case X86EMUL_OPC_66(0, 0x22): /* pinsr{d,q} */ + case X86EMUL_OPC_VEX_66(0, 0x22): /* vpinsr{d,q} */ + case X86EMUL_OPC_EVEX_66(0, 0x22): /* vpinsr{d,q} */ + s->desc =3D DstImplicit | SrcMem; + break; + + default: + s->op_bytes =3D 0; + break; + } + + return X86EMUL_OKAY; +} + +#define ad_bytes (s->ad_bytes) /* for truncate_ea() */ + +int x86emul_decode(struct x86_emulate_state *s, + struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops) +{ + uint8_t b, d; + unsigned int def_op_bytes, def_ad_bytes, opcode; + enum x86_segment override_seg =3D x86_seg_none; + bool pc_rel =3D false; + int rc =3D X86EMUL_OKAY; + + ASSERT(ops->insn_fetch); + + memset(s, 0, sizeof(*s)); + s->ea.type =3D OP_NONE; + s->ea.mem.seg =3D x86_seg_ds; + s->ea.reg =3D PTR_POISON; + s->regs =3D ctxt->regs; + s->ip =3D ctxt->regs->r(ip); + + s->op_bytes =3D def_op_bytes =3D ad_bytes =3D def_ad_bytes =3D + ctxt->addr_size / 8; + if ( s->op_bytes =3D=3D 8 ) + { + s->op_bytes =3D def_op_bytes =3D 4; +#ifndef __x86_64__ + return X86EMUL_UNHANDLEABLE; +#endif + } + + /* Prefix bytes. */ + for ( ; ; ) + { + switch ( b =3D insn_fetch_type(uint8_t) ) + { + case 0x66: /* operand-size override */ + s->op_bytes =3D def_op_bytes ^ 6; + if ( !s->vex.pfx ) + s->vex.pfx =3D vex_66; + break; + case 0x67: /* address-size override */ + ad_bytes =3D def_ad_bytes ^ (mode_64bit() ? 12 : 6); + break; + case 0x2e: /* CS override / ignored in 64-bit mode */ + if ( !mode_64bit() ) + override_seg =3D x86_seg_cs; + break; + case 0x3e: /* DS override / ignored in 64-bit mode */ + if ( !mode_64bit() ) + override_seg =3D x86_seg_ds; + break; + case 0x26: /* ES override / ignored in 64-bit mode */ + if ( !mode_64bit() ) + override_seg =3D x86_seg_es; + break; + case 0x64: /* FS override */ + override_seg =3D x86_seg_fs; + break; + case 0x65: /* GS override */ + override_seg =3D x86_seg_gs; + break; + case 0x36: /* SS override / ignored in 64-bit mode */ + if ( !mode_64bit() ) + override_seg =3D x86_seg_ss; + break; + case 0xf0: /* LOCK */ + s->lock_prefix =3D true; + break; + case 0xf2: /* REPNE/REPNZ */ + s->vex.pfx =3D vex_f2; + break; + case 0xf3: /* REP/REPE/REPZ */ + s->vex.pfx =3D vex_f3; + break; + case 0x40 ... 0x4f: /* REX */ + if ( !mode_64bit() ) + goto done_prefixes; + s->rex_prefix =3D b; + continue; + default: + goto done_prefixes; + } + + /* Any legacy prefix after a REX prefix nullifies its effect. */ + s->rex_prefix =3D 0; + } + done_prefixes: + + if ( s->rex_prefix & REX_W ) + s->op_bytes =3D 8; + + /* Opcode byte(s). */ + d =3D opcode_table[b]; + if ( d =3D=3D 0 && b =3D=3D 0x0f ) + { + /* Two-byte opcode. */ + b =3D insn_fetch_type(uint8_t); + d =3D twobyte_table[b].desc; + switch ( b ) + { + default: + opcode =3D b | MASK_INSR(0x0f, X86EMUL_OPC_EXT_MASK); + s->ext =3D ext_0f; + s->simd_size =3D twobyte_table[b].size; + break; + case 0x38: + b =3D insn_fetch_type(uint8_t); + opcode =3D b | MASK_INSR(0x0f38, X86EMUL_OPC_EXT_MASK); + s->ext =3D ext_0f38; + break; + case 0x3a: + b =3D insn_fetch_type(uint8_t); + opcode =3D b | MASK_INSR(0x0f3a, X86EMUL_OPC_EXT_MASK); + s->ext =3D ext_0f3a; + break; + } + } + else + opcode =3D b; + + /* ModRM and SIB bytes. */ + if ( d & ModRM ) + { + s->modrm =3D insn_fetch_type(uint8_t); + s->modrm_mod =3D (s->modrm & 0xc0) >> 6; + + if ( !s->ext && ((b & ~1) =3D=3D 0xc4 || (b =3D=3D 0x8f && (s->mod= rm & 0x18)) || + b =3D=3D 0x62) ) + switch ( def_ad_bytes ) + { + default: + BUG(); /* Shouldn't be possible. */ + case 2: + if ( s->regs->eflags & X86_EFLAGS_VM ) + break; + /* fall through */ + case 4: + if ( s->modrm_mod !=3D 3 || in_realmode(ctxt, ops) ) + break; + /* fall through */ + case 8: + /* VEX / XOP / EVEX */ + generate_exception_if(s->rex_prefix || s->vex.pfx, X86_EXC= _UD); + /* + * With operand size override disallowed (see above), op_b= ytes + * should not have changed from its default. + */ + ASSERT(s->op_bytes =3D=3D def_op_bytes); + + s->vex.raw[0] =3D s->modrm; + if ( b =3D=3D 0xc5 ) + { + opcode =3D X86EMUL_OPC_VEX_; + s->vex.raw[1] =3D s->modrm; + s->vex.opcx =3D vex_0f; + s->vex.x =3D 1; + s->vex.b =3D 1; + s->vex.w =3D 0; + } + else + { + s->vex.raw[1] =3D insn_fetch_type(uint8_t); + if ( mode_64bit() ) + { + if ( !s->vex.b ) + s->rex_prefix |=3D REX_B; + if ( !s->vex.x ) + s->rex_prefix |=3D REX_X; + if ( s->vex.w ) + { + s->rex_prefix |=3D REX_W; + s->op_bytes =3D 8; + } + } + else + { + /* Operand size fixed at 4 (no override via W bit)= . */ + s->op_bytes =3D 4; + s->vex.b =3D 1; + } + switch ( b ) + { + case 0x62: + opcode =3D X86EMUL_OPC_EVEX_; + s->evex.raw[0] =3D s->vex.raw[0]; + s->evex.raw[1] =3D s->vex.raw[1]; + s->evex.raw[2] =3D insn_fetch_type(uint8_t); + + generate_exception_if(!s->evex.mbs || s->evex.mbz,= X86_EXC_UD); + generate_exception_if(!s->evex.opmsk && s->evex.z,= X86_EXC_UD); + + if ( !mode_64bit() ) + s->evex.R =3D 1; + + s->vex.opcx =3D s->evex.opcx; + break; + case 0xc4: + opcode =3D X86EMUL_OPC_VEX_; + break; + default: + opcode =3D 0; + break; + } + } + if ( !s->vex.r ) + s->rex_prefix |=3D REX_R; + + s->ext =3D s->vex.opcx; + if ( b !=3D 0x8f ) + { + b =3D insn_fetch_type(uint8_t); + switch ( s->ext ) + { + case vex_0f: + opcode |=3D MASK_INSR(0x0f, X86EMUL_OPC_EXT_MASK); + d =3D twobyte_table[b].desc; + s->simd_size =3D twobyte_table[b].size; + break; + case vex_0f38: + opcode |=3D MASK_INSR(0x0f38, X86EMUL_OPC_EXT_MASK= ); + d =3D twobyte_table[0x38].desc; + break; + case vex_0f3a: + opcode |=3D MASK_INSR(0x0f3a, X86EMUL_OPC_EXT_MASK= ); + d =3D twobyte_table[0x3a].desc; + break; + default: + rc =3D X86EMUL_UNRECOGNIZED; + goto done; + } + } + else if ( s->ext < ext_8f08 + ARRAY_SIZE(xop_table) ) + { + b =3D insn_fetch_type(uint8_t); + opcode |=3D MASK_INSR(0x8f08 + s->ext - ext_8f08, + X86EMUL_OPC_EXT_MASK); + d =3D array_access_nospec(xop_table, s->ext - ext_8f08= ); + } + else + { + rc =3D X86EMUL_UNRECOGNIZED; + goto done; + } + + opcode |=3D b | MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK= ); + + if ( !evex_encoded() ) + s->evex.lr =3D s->vex.l; + + if ( !(d & ModRM) ) + break; + + s->modrm =3D insn_fetch_type(uint8_t); + s->modrm_mod =3D (s->modrm & 0xc0) >> 6; + + break; + } + } + + if ( d & ModRM ) + { + unsigned int disp8scale =3D 0; + + d &=3D ~ModRM; +#undef ModRM /* Only its aliases are valid to use from here on. */ + s->modrm_reg =3D ((s->rex_prefix & 4) << 1) | ((s->modrm & 0x38) >= > 3) | + ((evex_encoded() && !s->evex.R) << 4); + s->modrm_rm =3D s->modrm & 0x07; + + /* + * Early operand adjustments. Only ones affecting further processi= ng + * prior to the x86_decode_*() calls really belong here. That would + * normally be only addition/removal of SrcImm/SrcImm16, so their + * fetching can be taken care of by the common code below. + */ + switch ( s->ext ) + { + case ext_none: + switch ( b ) + { + case 0xf6 ... 0xf7: /* Grp3 */ + switch ( s->modrm_reg & 7 ) + { + case 0 ... 1: /* test */ + d |=3D DstMem | SrcImm; + break; + case 2: /* not */ + case 3: /* neg */ + d |=3D DstMem; + break; + case 4: /* mul */ + case 5: /* imul */ + case 6: /* div */ + case 7: /* idiv */ + /* + * DstEax isn't really precise for all cases; updates = to + * rDX get handled in an open coded manner. + */ + d |=3D DstEax | SrcMem; + break; + } + break; + } + break; + + case ext_0f: + if ( evex_encoded() ) + disp8scale =3D decode_disp8scale(twobyte_table[b].d8s, s); + + switch ( b ) + { + case 0x12: /* vmovsldup / vmovddup */ + if ( s->evex.pfx =3D=3D vex_f2 ) + disp8scale =3D s->evex.lr ? 4 + s->evex.lr : 3; + /* fall through */ + case 0x16: /* vmovshdup */ + if ( s->evex.pfx =3D=3D vex_f3 ) + disp8scale =3D 4 + s->evex.lr; + break; + + case 0x20: /* mov cr,reg */ + case 0x21: /* mov dr,reg */ + case 0x22: /* mov reg,cr */ + case 0x23: /* mov reg,dr */ + /* + * Mov to/from cr/dr ignore the encoding of Mod, and behav= e as + * if they were encoded as reg/reg instructions. No furth= er + * disp/SIB bytes are fetched. + */ + s->modrm_mod =3D 3; + break; + + case 0x78: + case 0x79: + if ( !s->evex.pfx ) + break; + /* vcvt{,t}ps2uqq need special casing */ + if ( s->evex.pfx =3D=3D vex_66 ) + { + if ( !s->evex.w && !s->evex.brs ) + --disp8scale; + break; + } + /* vcvt{,t}s{s,d}2usi need special casing: fall through */ + case 0x2c: /* vcvtts{s,d}2si need special casing */ + case 0x2d: /* vcvts{s,d}2si need special casing */ + if ( evex_encoded() ) + disp8scale =3D 2 + (s->evex.pfx & VEX_PREFIX_DOUBLE_MA= SK); + break; + + case 0x5a: /* vcvtps2pd needs special casing */ + if ( disp8scale && !s->evex.pfx && !s->evex.brs ) + --disp8scale; + break; + + case 0x7a: /* vcvttps2qq and vcvtudq2pd need special casing */ + if ( disp8scale && s->evex.pfx !=3D vex_f2 && !s->evex.w &= & !s->evex.brs ) + --disp8scale; + break; + + case 0x7b: /* vcvtp{s,d}2qq need special casing */ + if ( disp8scale && s->evex.pfx =3D=3D vex_66 ) + disp8scale =3D (s->evex.brs ? 2 : 3 + s->evex.lr) + s-= >evex.w; + break; + + case 0x7e: /* vmovq xmm/m64,xmm needs special casing */ + if ( disp8scale =3D=3D 2 && s->evex.pfx =3D=3D vex_f3 ) + disp8scale =3D 3; + break; + + case 0xe6: /* vcvtdq2pd needs special casing */ + if ( disp8scale && s->evex.pfx =3D=3D vex_f3 && !s->evex.w= && !s->evex.brs ) + --disp8scale; + break; + } + break; + + case ext_0f38: + d =3D ext0f38_table[b].to_mem ? DstMem | SrcReg + : DstReg | SrcMem; + if ( ext0f38_table[b].two_op ) + d |=3D TwoOp; + if ( ext0f38_table[b].vsib ) + d |=3D vSIB; + s->simd_size =3D ext0f38_table[b].simd_size; + if ( evex_encoded() ) + { + /* + * VPMOVUS* are identical to VPMOVS* Disp8-scaling-wise, b= ut + * their attributes don't match those of the vex_66 encoded + * insns with the same base opcodes. Rather than adding new + * columns to the table, handle this here for now. + */ + if ( s->evex.pfx !=3D vex_f3 || (b & 0xf8) !=3D 0x10 ) + disp8scale =3D decode_disp8scale(ext0f38_table[b].d8s,= s); + else + { + disp8scale =3D decode_disp8scale(ext0f38_table[b ^ 0x3= 0].d8s, + s); + s->simd_size =3D simd_other; + } + + switch ( b ) + { + /* vp4dpwssd{,s} need special casing */ + case 0x52: case 0x53: + /* v4f{,n}madd{p,s}s need special casing */ + case 0x9a: case 0x9b: case 0xaa: case 0xab: + if ( s->evex.pfx =3D=3D vex_f2 ) + { + disp8scale =3D 4; + s->simd_size =3D simd_128; + } + break; + } + } + break; + + case ext_0f3a: + /* + * Cannot update d here yet, as the immediate operand still + * needs fetching. + */ + s->simd_size =3D ext0f3a_table[b].simd_size; + if ( evex_encoded() ) + disp8scale =3D decode_disp8scale(ext0f3a_table[b].d8s, s); + break; + + case ext_8f09: + if ( ext8f09_table[b].two_op ) + d |=3D TwoOp; + s->simd_size =3D ext8f09_table[b].simd_size; + break; + + case ext_8f08: + case ext_8f0a: + /* + * Cannot update d here yet, as the immediate operand still + * needs fetching. + */ + break; + + default: + ASSERT_UNREACHABLE(); + return X86EMUL_UNIMPLEMENTED; + } + + if ( s->modrm_mod =3D=3D 3 ) + { + generate_exception_if(d & vSIB, X86_EXC_UD); + s->modrm_rm |=3D ((s->rex_prefix & 1) << 3) | + ((evex_encoded() && !s->evex.x) << 4); + s->ea.type =3D OP_REG; + } + else if ( ad_bytes =3D=3D 2 ) + { + /* 16-bit ModR/M decode. */ + generate_exception_if(d & vSIB, X86_EXC_UD); + s->ea.type =3D OP_MEM; + switch ( s->modrm_rm ) + { + case 0: + s->ea.mem.off =3D s->regs->bx + s->regs->si; + break; + case 1: + s->ea.mem.off =3D s->regs->bx + s->regs->di; + break; + case 2: + s->ea.mem.seg =3D x86_seg_ss; + s->ea.mem.off =3D s->regs->bp + s->regs->si; + break; + case 3: + s->ea.mem.seg =3D x86_seg_ss; + s->ea.mem.off =3D s->regs->bp + s->regs->di; + break; + case 4: + s->ea.mem.off =3D s->regs->si; + break; + case 5: + s->ea.mem.off =3D s->regs->di; + break; + case 6: + if ( s->modrm_mod =3D=3D 0 ) + break; + s->ea.mem.seg =3D x86_seg_ss; + s->ea.mem.off =3D s->regs->bp; + break; + case 7: + s->ea.mem.off =3D s->regs->bx; + break; + } + switch ( s->modrm_mod ) + { + case 0: + if ( s->modrm_rm =3D=3D 6 ) + s->ea.mem.off =3D insn_fetch_type(int16_t); + break; + case 1: + s->ea.mem.off +=3D insn_fetch_type(int8_t) * (1 << disp8sc= ale); + break; + case 2: + s->ea.mem.off +=3D insn_fetch_type(int16_t); + break; + } + } + else + { + /* 32/64-bit ModR/M decode. */ + s->ea.type =3D OP_MEM; + if ( s->modrm_rm =3D=3D 4 ) + { + uint8_t sib =3D insn_fetch_type(uint8_t); + uint8_t sib_base =3D (sib & 7) | ((s->rex_prefix << 3) & 8= ); + + s->sib_index =3D ((sib >> 3) & 7) | ((s->rex_prefix << 2) = & 8); + s->sib_scale =3D (sib >> 6) & 3; + if ( unlikely(d & vSIB) ) + s->sib_index |=3D (mode_64bit() && evex_encoded() && + !s->evex.RX) << 4; + else if ( s->sib_index !=3D 4 ) + { + s->ea.mem.off =3D *decode_gpr(s->regs, s->sib_index); + s->ea.mem.off <<=3D s->sib_scale; + } + if ( (s->modrm_mod =3D=3D 0) && ((sib_base & 7) =3D=3D 5) ) + s->ea.mem.off +=3D insn_fetch_type(int32_t); + else if ( sib_base =3D=3D 4 ) + { + s->ea.mem.seg =3D x86_seg_ss; + s->ea.mem.off +=3D s->regs->r(sp); + if ( !s->ext && (b =3D=3D 0x8f) ) + /* POP computes its EA post increment. */ + s->ea.mem.off +=3D ((mode_64bit() && (s->op_bytes = =3D=3D 4)) + ? 8 : s->op_bytes); + } + else if ( sib_base =3D=3D 5 ) + { + s->ea.mem.seg =3D x86_seg_ss; + s->ea.mem.off +=3D s->regs->r(bp); + } + else + s->ea.mem.off +=3D *decode_gpr(s->regs, sib_base); + } + else + { + generate_exception_if(d & vSIB, X86_EXC_UD); + s->modrm_rm |=3D (s->rex_prefix & 1) << 3; + s->ea.mem.off =3D *decode_gpr(s->regs, s->modrm_rm); + if ( (s->modrm_rm =3D=3D 5) && (s->modrm_mod !=3D 0) ) + s->ea.mem.seg =3D x86_seg_ss; + } + switch ( s->modrm_mod ) + { + case 0: + if ( (s->modrm_rm & 7) !=3D 5 ) + break; + s->ea.mem.off =3D insn_fetch_type(int32_t); + pc_rel =3D mode_64bit(); + break; + case 1: + s->ea.mem.off +=3D insn_fetch_type(int8_t) * (1 << disp8sc= ale); + break; + case 2: + s->ea.mem.off +=3D insn_fetch_type(int32_t); + break; + } + } + } + else + { + s->modrm_mod =3D 0xff; + s->modrm_reg =3D s->modrm_rm =3D s->modrm =3D 0; + } + + if ( override_seg !=3D x86_seg_none ) + s->ea.mem.seg =3D override_seg; + + /* Fetch the immediate operand, if present. */ + switch ( d & SrcMask ) + { + unsigned int bytes; + + case SrcImm: + if ( !(d & ByteOp) ) + { + if ( mode_64bit() && !amd_like(ctxt) && + ((s->ext =3D=3D ext_none && (b | 1) =3D=3D 0xe9) /* call = / jmp */ || + (s->ext =3D=3D ext_0f && (b | 0xf) =3D=3D 0x8f) /* jcc *= / ) ) + s->op_bytes =3D 4; + bytes =3D s->op_bytes !=3D 8 ? s->op_bytes : 4; + } + else + { + case SrcImmByte: + bytes =3D 1; + } + /* NB. Immediates are sign-extended as necessary. */ + switch ( bytes ) + { + case 1: s->imm1 =3D insn_fetch_type(int8_t); break; + case 2: s->imm1 =3D insn_fetch_type(int16_t); break; + case 4: s->imm1 =3D insn_fetch_type(int32_t); break; + } + break; + case SrcImm16: + s->imm1 =3D insn_fetch_type(uint16_t); + break; + } + + ctxt->opcode =3D opcode; + s->desc =3D d; + + switch ( s->ext ) + { + case ext_none: + rc =3D decode_onebyte(s, ctxt, ops); + break; + + case ext_0f: + rc =3D decode_twobyte(s, ctxt, ops); + break; + + case ext_0f38: + rc =3D decode_0f38(s, ctxt, ops); + break; + + case ext_0f3a: + d =3D ext0f3a_table[b].to_mem ? DstMem | SrcReg : DstReg | SrcMem; + if ( ext0f3a_table[b].two_op ) + d |=3D TwoOp; + else if ( ext0f3a_table[b].four_op && !mode_64bit() && s->vex.opcx= ) + s->imm1 &=3D 0x7f; + s->desc =3D d; + rc =3D decode_0f3a(s, ctxt, ops); + break; + + case ext_8f08: + d =3D DstReg | SrcMem; + if ( ext8f08_table[b].two_op ) + d |=3D TwoOp; + else if ( ext8f08_table[b].four_op && !mode_64bit() ) + s->imm1 &=3D 0x7f; + s->desc =3D d; + s->simd_size =3D ext8f08_table[b].simd_size; + break; + + case ext_8f09: + case ext_8f0a: + break; + + default: + ASSERT_UNREACHABLE(); + return X86EMUL_UNIMPLEMENTED; + } + + if ( s->ea.type =3D=3D OP_MEM ) + { + if ( pc_rel ) + s->ea.mem.off +=3D s->ip; + + s->ea.mem.off =3D truncate_ea(s->ea.mem.off); + } + + /* + * Simple op_bytes calculations. More complicated cases produce 0 + * and are further handled during execute. + */ + switch ( s->simd_size ) + { + case simd_none: + /* + * When prefix 66 has a meaning different from operand-size overri= de, + * operand size defaults to 4 and can't be overridden to 2. + */ + if ( s->op_bytes =3D=3D 2 && + (ctxt->opcode & X86EMUL_OPC_PFX_MASK) =3D=3D X86EMUL_OPC_66(0= , 0) ) + s->op_bytes =3D 4; + break; + +#ifndef X86EMUL_NO_SIMD + case simd_packed_int: + switch ( s->vex.pfx ) + { + case vex_none: + if ( !s->vex.opcx ) + { + s->op_bytes =3D 8; + break; + } + /* fall through */ + case vex_66: + s->op_bytes =3D 16 << s->evex.lr; + break; + default: + s->op_bytes =3D 0; + break; + } + break; + + case simd_single_fp: + if ( s->vex.pfx & VEX_PREFIX_DOUBLE_MASK ) + { + s->op_bytes =3D 0; + break; + case simd_packed_fp: + if ( s->vex.pfx & VEX_PREFIX_SCALAR_MASK ) + { + s->op_bytes =3D 0; + break; + } + } + /* fall through */ + case simd_any_fp: + switch ( s->vex.pfx ) + { + default: + s->op_bytes =3D 16 << s->evex.lr; + break; + case vex_f3: + generate_exception_if(evex_encoded() && s->evex.w, X86_EXC_UD); + s->op_bytes =3D 4; + break; + case vex_f2: + generate_exception_if(evex_encoded() && !s->evex.w, X86_EXC_UD= ); + s->op_bytes =3D 8; + break; + } + break; + + case simd_scalar_opc: + s->op_bytes =3D 4 << (ctxt->opcode & 1); + break; + + case simd_scalar_vexw: + s->op_bytes =3D 4 << s->vex.w; + break; + + case simd_128: + /* The special cases here are MMX shift insns. */ + s->op_bytes =3D s->vex.opcx || s->vex.pfx ? 16 : 8; + break; + + case simd_256: + s->op_bytes =3D 32; + break; +#endif /* !X86EMUL_NO_SIMD */ + + default: + s->op_bytes =3D 0; + break; + } + + done: + return rc; +} --- a/xen/arch/x86/x86_emulate/private.h +++ b/xen/arch/x86/x86_emulate/private.h @@ -37,9 +37,11 @@ #ifdef __i386__ # define mode_64bit() false # define r(name) e ## name +# define PTR_POISON NULL /* 32-bit builds are for user-space, so NULL is O= K. */ #else # define mode_64bit() (ctxt->addr_size =3D=3D 64) # define r(name) r ## name +# define PTR_POISON ((void *)0x8086000000008086UL) /* non-canonical */ #endif =20 /* Operand sizes: 8-bit operands or specified/overridden size. */ @@ -76,6 +78,23 @@ =20 typedef uint8_t opcode_desc_t; =20 +enum disp8scale { + /* Values 0 ... 4 are explicit sizes. */ + d8s_bw =3D 5, + d8s_dq, + /* EVEX.W ignored outside of 64-bit mode */ + d8s_dq64, + /* + * All further values must strictly be last and in the order + * given so that arithmetic on the values works. + */ + d8s_vl, + d8s_vl_by_2, + d8s_vl_by_4, + d8s_vl_by_8, +}; +typedef uint8_t disp8scale_t; + /* Type, address-of, and value of an instruction's operand. */ struct operand { enum { OP_REG, OP_MEM, OP_IMM, OP_NONE } type; @@ -182,6 +201,9 @@ enum vex_pfx { vex_f2 }; =20 +#define VEX_PREFIX_DOUBLE_MASK 0x1 +#define VEX_PREFIX_SCALAR_MASK 0x2 + union vex { uint8_t raw[2]; struct { /* SDM names */ @@ -706,6 +728,10 @@ do { if ( rc ) goto done; \ } while (0) =20 +int x86emul_decode(struct x86_emulate_state *s, + struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops); + int x86emul_fpu(struct x86_emulate_state *s, struct cpu_user_regs *regs, struct operand *dst, @@ -735,6 +761,13 @@ int x86emul_0fc7(struct x86_emulate_stat const struct x86_emulate_ops *ops, mmval_t *mmvalp); =20 +/* Initialise output state in x86_emulate_ctxt */ +static inline void init_context(struct x86_emulate_ctxt *ctxt) +{ + ctxt->retire.raw =3D 0; + x86_emul_reset_event(ctxt); +} + static inline bool is_aligned(enum x86_segment seg, unsigned long offs, unsigned int size, struct x86_emulate_ctxt *= ctxt, const struct x86_emulate_ops *ops) --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -22,274 +22,6 @@ =20 #include "private.h" =20 -static const opcode_desc_t opcode_table[256] =3D { - /* 0x00 - 0x07 */ - ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, - ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, - ByteOp|DstEax|SrcImm, DstEax|SrcImm, ImplicitOps|Mov, ImplicitOps|Mov, - /* 0x08 - 0x0F */ - ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, - ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, - ByteOp|DstEax|SrcImm, DstEax|SrcImm, ImplicitOps|Mov, 0, - /* 0x10 - 0x17 */ - ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, - ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, - ByteOp|DstEax|SrcImm, DstEax|SrcImm, ImplicitOps|Mov, ImplicitOps|Mov, - /* 0x18 - 0x1F */ - ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, - ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, - ByteOp|DstEax|SrcImm, DstEax|SrcImm, ImplicitOps|Mov, ImplicitOps|Mov, - /* 0x20 - 0x27 */ - ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, - ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, - ByteOp|DstEax|SrcImm, DstEax|SrcImm, 0, ImplicitOps, - /* 0x28 - 0x2F */ - ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, - ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, - ByteOp|DstEax|SrcImm, DstEax|SrcImm, 0, ImplicitOps, - /* 0x30 - 0x37 */ - ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, - ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, - ByteOp|DstEax|SrcImm, DstEax|SrcImm, 0, ImplicitOps, - /* 0x38 - 0x3F */ - ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, - ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, - ByteOp|DstEax|SrcImm, DstEax|SrcImm, 0, ImplicitOps, - /* 0x40 - 0x4F */ - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - /* 0x50 - 0x5F */ - ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, - ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, - ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, - ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, - /* 0x60 - 0x67 */ - ImplicitOps, ImplicitOps, DstReg|SrcMem|ModRM, DstReg|SrcNone|ModRM|Mo= v, - 0, 0, 0, 0, - /* 0x68 - 0x6F */ - DstImplicit|SrcImm|Mov, DstReg|SrcImm|ModRM|Mov, - DstImplicit|SrcImmByte|Mov, DstReg|SrcImmByte|ModRM|Mov, - ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, - /* 0x70 - 0x77 */ - DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, - DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, - DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, - DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, - /* 0x78 - 0x7F */ - DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, - DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, - DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, - DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, - /* 0x80 - 0x87 */ - ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImm|ModRM, - ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM, - ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, - ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, - /* 0x88 - 0x8F */ - ByteOp|DstMem|SrcReg|ModRM|Mov, DstMem|SrcReg|ModRM|Mov, - ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, - DstMem|SrcReg|ModRM|Mov, DstReg|SrcNone|ModRM, - DstReg|SrcMem16|ModRM|Mov, DstMem|SrcNone|ModRM|Mov, - /* 0x90 - 0x97 */ - DstImplicit|SrcEax, DstImplicit|SrcEax, - DstImplicit|SrcEax, DstImplicit|SrcEax, - DstImplicit|SrcEax, DstImplicit|SrcEax, - DstImplicit|SrcEax, DstImplicit|SrcEax, - /* 0x98 - 0x9F */ - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps, ImplicitOps, - /* 0xA0 - 0xA7 */ - ByteOp|DstEax|SrcMem|Mov, DstEax|SrcMem|Mov, - ByteOp|DstMem|SrcEax|Mov, DstMem|SrcEax|Mov, - ByteOp|ImplicitOps|Mov, ImplicitOps|Mov, - ByteOp|ImplicitOps, ImplicitOps, - /* 0xA8 - 0xAF */ - ByteOp|DstEax|SrcImm, DstEax|SrcImm, - ByteOp|DstImplicit|SrcEax|Mov, DstImplicit|SrcEax|Mov, - ByteOp|DstEax|SrcImplicit|Mov, DstEax|SrcImplicit|Mov, - ByteOp|DstImplicit|SrcEax, DstImplicit|SrcEax, - /* 0xB0 - 0xB7 */ - ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov, - ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov, - ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov, - ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov, - /* 0xB8 - 0xBF */ - DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm= |Mov, - DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm= |Mov, - /* 0xC0 - 0xC7 */ - ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM, - DstImplicit|SrcImm16, ImplicitOps, - DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, - ByteOp|DstMem|SrcImm|ModRM|Mov, DstMem|SrcImm|ModRM|Mov, - /* 0xC8 - 0xCF */ - DstImplicit|SrcImm16, ImplicitOps, DstImplicit|SrcImm16, ImplicitOps, - ImplicitOps, DstImplicit|SrcImmByte, ImplicitOps, ImplicitOps, - /* 0xD0 - 0xD7 */ - ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM, - ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM, - DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, ImplicitOps, ImplicitO= ps, - /* 0xD8 - 0xDF */ - ImplicitOps|ModRM, ImplicitOps|ModRM|Mov, - ImplicitOps|ModRM, ImplicitOps|ModRM|Mov, - ImplicitOps|ModRM, ImplicitOps|ModRM|Mov, - DstImplicit|SrcMem16|ModRM, ImplicitOps|ModRM|Mov, - /* 0xE0 - 0xE7 */ - DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, - DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, - DstEax|SrcImmByte, DstEax|SrcImmByte, - DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, - /* 0xE8 - 0xEF */ - DstImplicit|SrcImm|Mov, DstImplicit|SrcImm, - ImplicitOps, DstImplicit|SrcImmByte, - DstEax|SrcImplicit, DstEax|SrcImplicit, ImplicitOps, ImplicitOps, - /* 0xF0 - 0xF7 */ - 0, ImplicitOps, 0, 0, - ImplicitOps, ImplicitOps, ByteOp|ModRM, ModRM, - /* 0xF8 - 0xFF */ - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - ImplicitOps, ImplicitOps, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|= ModRM -}; - -enum disp8scale { - /* Values 0 ... 4 are explicit sizes. */ - d8s_bw =3D 5, - d8s_dq, - /* EVEX.W ignored outside of 64-bit mode */ - d8s_dq64, - /* - * All further values must strictly be last and in the order - * given so that arithmetic on the values works. - */ - d8s_vl, - d8s_vl_by_2, - d8s_vl_by_4, - d8s_vl_by_8, -}; -typedef uint8_t disp8scale_t; - -static const struct twobyte_table { - opcode_desc_t desc; - simd_opsize_t size:4; - disp8scale_t d8s:4; -} twobyte_table[256] =3D { - [0x00] =3D { ModRM }, - [0x01] =3D { ImplicitOps|ModRM }, - [0x02] =3D { DstReg|SrcMem16|ModRM }, - [0x03] =3D { DstReg|SrcMem16|ModRM }, - [0x05] =3D { ImplicitOps }, - [0x06] =3D { ImplicitOps }, - [0x07] =3D { ImplicitOps }, - [0x08] =3D { ImplicitOps }, - [0x09] =3D { ImplicitOps }, - [0x0b] =3D { ImplicitOps }, - [0x0d] =3D { ImplicitOps|ModRM }, - [0x0e] =3D { ImplicitOps }, - [0x0f] =3D { ModRM|SrcImmByte }, - [0x10] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_any_fp, d8s_vl }, - [0x11] =3D { DstMem|SrcImplicit|ModRM|Mov, simd_any_fp, d8s_vl }, - [0x12] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_other, 3 }, - [0x13] =3D { DstMem|SrcImplicit|ModRM|Mov, simd_other, 3 }, - [0x14 ... 0x15] =3D { DstImplicit|SrcMem|ModRM, simd_packed_fp, d8s_vl= }, - [0x16] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_other, 3 }, - [0x17] =3D { DstMem|SrcImplicit|ModRM|Mov, simd_other, 3 }, - [0x18 ... 0x1f] =3D { ImplicitOps|ModRM }, - [0x20 ... 0x21] =3D { DstMem|SrcImplicit|ModRM }, - [0x22 ... 0x23] =3D { DstImplicit|SrcMem|ModRM }, - [0x28] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_packed_fp, d8s_vl }, - [0x29] =3D { DstMem|SrcImplicit|ModRM|Mov, simd_packed_fp, d8s_vl }, - [0x2a] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_other, d8s_dq64 }, - [0x2b] =3D { DstMem|SrcImplicit|ModRM|Mov, simd_any_fp, d8s_vl }, - [0x2c ... 0x2d] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_other }, - [0x2e ... 0x2f] =3D { ImplicitOps|ModRM|TwoOp, simd_none, d8s_dq }, - [0x30 ... 0x35] =3D { ImplicitOps }, - [0x37] =3D { ImplicitOps }, - [0x38] =3D { DstReg|SrcMem|ModRM }, - [0x3a] =3D { DstReg|SrcImmByte|ModRM }, - [0x40 ... 0x4f] =3D { DstReg|SrcMem|ModRM|Mov }, - [0x50] =3D { DstReg|SrcImplicit|ModRM|Mov }, - [0x51] =3D { DstImplicit|SrcMem|ModRM|TwoOp, simd_any_fp, d8s_vl }, - [0x52 ... 0x53] =3D { DstImplicit|SrcMem|ModRM|TwoOp, simd_single_fp }, - [0x54 ... 0x57] =3D { DstImplicit|SrcMem|ModRM, simd_packed_fp, d8s_vl= }, - [0x58 ... 0x59] =3D { DstImplicit|SrcMem|ModRM, simd_any_fp, d8s_vl }, - [0x5a] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_any_fp, d8s_vl }, - [0x5b] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_packed_fp, d8s_vl }, - [0x5c ... 0x5f] =3D { DstImplicit|SrcMem|ModRM, simd_any_fp, d8s_vl }, - [0x60 ... 0x62] =3D { DstImplicit|SrcMem|ModRM, simd_other, d8s_vl }, - [0x63 ... 0x67] =3D { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_v= l }, - [0x68 ... 0x6a] =3D { DstImplicit|SrcMem|ModRM, simd_other, d8s_vl }, - [0x6b ... 0x6d] =3D { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_v= l }, - [0x6e] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_none, d8s_dq64 }, - [0x6f] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_packed_int, d8s_vl }, - [0x70] =3D { SrcImmByte|ModRM|TwoOp, simd_other, d8s_vl }, - [0x71 ... 0x73] =3D { DstImplicit|SrcImmByte|ModRM, simd_none, d8s_vl = }, - [0x74 ... 0x76] =3D { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_v= l }, - [0x77] =3D { DstImplicit|SrcNone }, - [0x78 ... 0x79] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_other, d8s_vl= }, - [0x7a] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_packed_fp, d8s_vl }, - [0x7b] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_other, d8s_dq64 }, - [0x7c ... 0x7d] =3D { DstImplicit|SrcMem|ModRM, simd_other }, - [0x7e] =3D { DstMem|SrcImplicit|ModRM|Mov, simd_none, d8s_dq64 }, - [0x7f] =3D { DstMem|SrcImplicit|ModRM|Mov, simd_packed_int, d8s_vl }, - [0x80 ... 0x8f] =3D { DstImplicit|SrcImm }, - [0x90 ... 0x9f] =3D { ByteOp|DstMem|SrcNone|ModRM|Mov }, - [0xa0 ... 0xa1] =3D { ImplicitOps|Mov }, - [0xa2] =3D { ImplicitOps }, - [0xa3] =3D { DstBitBase|SrcReg|ModRM }, - [0xa4] =3D { DstMem|SrcImmByte|ModRM }, - [0xa5] =3D { DstMem|SrcReg|ModRM }, - [0xa6 ... 0xa7] =3D { ModRM }, - [0xa8 ... 0xa9] =3D { ImplicitOps|Mov }, - [0xaa] =3D { ImplicitOps }, - [0xab] =3D { DstBitBase|SrcReg|ModRM }, - [0xac] =3D { DstMem|SrcImmByte|ModRM }, - [0xad] =3D { DstMem|SrcReg|ModRM }, - [0xae] =3D { ImplicitOps|ModRM }, - [0xaf] =3D { DstReg|SrcMem|ModRM }, - [0xb0] =3D { ByteOp|DstMem|SrcReg|ModRM }, - [0xb1] =3D { DstMem|SrcReg|ModRM }, - [0xb2] =3D { DstReg|SrcMem|ModRM|Mov }, - [0xb3] =3D { DstBitBase|SrcReg|ModRM }, - [0xb4 ... 0xb5] =3D { DstReg|SrcMem|ModRM|Mov }, - [0xb6] =3D { ByteOp|DstReg|SrcMem|ModRM|Mov }, - [0xb7] =3D { DstReg|SrcMem16|ModRM|Mov }, - [0xb8] =3D { DstReg|SrcMem|ModRM }, - [0xb9] =3D { ModRM }, - [0xba] =3D { DstBitBase|SrcImmByte|ModRM }, - [0xbb] =3D { DstBitBase|SrcReg|ModRM }, - [0xbc ... 0xbd] =3D { DstReg|SrcMem|ModRM }, - [0xbe] =3D { ByteOp|DstReg|SrcMem|ModRM|Mov }, - [0xbf] =3D { DstReg|SrcMem16|ModRM|Mov }, - [0xc0] =3D { ByteOp|DstMem|SrcReg|ModRM }, - [0xc1] =3D { DstMem|SrcReg|ModRM }, - [0xc2] =3D { DstImplicit|SrcImmByte|ModRM, simd_any_fp, d8s_vl }, - [0xc3] =3D { DstMem|SrcReg|ModRM|Mov }, - [0xc4] =3D { DstImplicit|SrcImmByte|ModRM, simd_none, 1 }, - [0xc5] =3D { DstReg|SrcImmByte|ModRM|Mov }, - [0xc6] =3D { DstImplicit|SrcImmByte|ModRM, simd_packed_fp, d8s_vl }, - [0xc7] =3D { ImplicitOps|ModRM }, - [0xc8 ... 0xcf] =3D { ImplicitOps }, - [0xd0] =3D { DstImplicit|SrcMem|ModRM, simd_other }, - [0xd1 ... 0xd3] =3D { DstImplicit|SrcMem|ModRM, simd_128, 4 }, - [0xd4 ... 0xd5] =3D { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_v= l }, - [0xd6] =3D { DstMem|SrcImplicit|ModRM|Mov, simd_other, 3 }, - [0xd7] =3D { DstReg|SrcImplicit|ModRM|Mov }, - [0xd8 ... 0xdf] =3D { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_v= l }, - [0xe0] =3D { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl }, - [0xe1 ... 0xe2] =3D { DstImplicit|SrcMem|ModRM, simd_128, 4 }, - [0xe3 ... 0xe5] =3D { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_v= l }, - [0xe6] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_packed_fp, d8s_vl }, - [0xe7] =3D { DstMem|SrcImplicit|ModRM|Mov, simd_packed_int, d8s_vl }, - [0xe8 ... 0xef] =3D { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_v= l }, - [0xf0] =3D { DstImplicit|SrcMem|ModRM|Mov, simd_other }, - [0xf1 ... 0xf3] =3D { DstImplicit|SrcMem|ModRM, simd_128, 4 }, - [0xf4 ... 0xf6] =3D { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_v= l }, - [0xf7] =3D { DstMem|SrcMem|ModRM|Mov, simd_packed_int }, - [0xf8 ... 0xfe] =3D { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_v= l }, - [0xff] =3D { ModRM } -}; - /* * The next two tables are indexed by high opcode extension byte (the one * that's encoded like an immediate) nibble, with each table element then @@ -325,257 +57,9 @@ static const uint16_t _3dnow_ext_table[1 [0xb] =3D (1 << 0xb) /* pswapd */, }; =20 -/* - * "two_op" and "four_op" below refer to the number of register operands - * (one of which possibly also allowing to be a memory one). The named - * operand counts do not include any immediate operands. - */ -static const struct ext0f38_table { - uint8_t simd_size:5; - uint8_t to_mem:1; - uint8_t two_op:1; - uint8_t vsib:1; - disp8scale_t d8s:4; -} ext0f38_table[256] =3D { - [0x00] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, - [0x01 ... 0x03] =3D { .simd_size =3D simd_packed_int }, - [0x04] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, - [0x05 ... 0x0a] =3D { .simd_size =3D simd_packed_int }, - [0x0b] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, - [0x0c ... 0x0d] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, - [0x0e ... 0x0f] =3D { .simd_size =3D simd_packed_fp }, - [0x10 ... 0x12] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, - [0x13] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_2 }, - [0x14 ... 0x16] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, - [0x17] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, - [0x18] =3D { .simd_size =3D simd_scalar_opc, .two_op =3D 1, .d8s =3D 2= }, - [0x19] =3D { .simd_size =3D simd_scalar_opc, .two_op =3D 1, .d8s =3D 3= }, - [0x1a] =3D { .simd_size =3D simd_128, .two_op =3D 1, .d8s =3D 4 }, - [0x1b] =3D { .simd_size =3D simd_256, .two_op =3D 1, .d8s =3D d8s_vl_b= y_2 }, - [0x1c ... 0x1f] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1, .= d8s =3D d8s_vl }, - [0x20] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_2 }, - [0x21] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_4 }, - [0x22] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_8 }, - [0x23] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_2 }, - [0x24] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_4 }, - [0x25] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_2 }, - [0x26 ... 0x29] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, - [0x2a] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1, .d8s =3D d= 8s_vl }, - [0x2b] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, - [0x2c] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, - [0x2d] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_dq }, - [0x2e ... 0x2f] =3D { .simd_size =3D simd_packed_fp, .to_mem =3D 1 }, - [0x30] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_2 }, - [0x31] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_4 }, - [0x32] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_8 }, - [0x33] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_2 }, - [0x34] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_4 }, - [0x35] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D d8s_vl= _by_2 }, - [0x36 ... 0x3f] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, - [0x40] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, - [0x41] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, - [0x42] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d8s =3D d8= s_vl }, - [0x43] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, - [0x44] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1, .d8s =3D d= 8s_vl }, - [0x45 ... 0x47] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, - [0x4c] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d8s =3D d8= s_vl }, - [0x4d] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, - [0x4e] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d8s =3D d8= s_vl }, - [0x4f] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, - [0x50 ... 0x53] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, - [0x54 ... 0x55] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1, .= d8s =3D d8s_vl }, - [0x58] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D 2 }, - [0x59] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D 3 }, - [0x5a] =3D { .simd_size =3D simd_128, .two_op =3D 1, .d8s =3D 4 }, - [0x5b] =3D { .simd_size =3D simd_256, .two_op =3D 1, .d8s =3D d8s_vl_b= y_2 }, - [0x62] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1, .d8s =3D d= 8s_bw }, - [0x63] =3D { .simd_size =3D simd_packed_int, .to_mem =3D 1, .two_op = =3D 1, .d8s =3D d8s_bw }, - [0x64 ... 0x66] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, - [0x68] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, - [0x70 ... 0x73] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, - [0x75 ... 0x76] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, - [0x77] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, - [0x78] =3D { .simd_size =3D simd_other, .two_op =3D 1 }, - [0x79] =3D { .simd_size =3D simd_other, .two_op =3D 1, .d8s =3D 1 }, - [0x7a ... 0x7c] =3D { .simd_size =3D simd_none, .two_op =3D 1 }, - [0x7d ... 0x7e] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, - [0x7f] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, - [0x82] =3D { .simd_size =3D simd_other }, - [0x83] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, - [0x88] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d8s =3D d8= s_dq }, - [0x89] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1, .d8s =3D d= 8s_dq }, - [0x8a] =3D { .simd_size =3D simd_packed_fp, .to_mem =3D 1, .two_op =3D= 1, .d8s =3D d8s_dq }, - [0x8b] =3D { .simd_size =3D simd_packed_int, .to_mem =3D 1, .two_op = =3D 1, .d8s =3D d8s_dq }, - [0x8c] =3D { .simd_size =3D simd_packed_int }, - [0x8d] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, - [0x8e] =3D { .simd_size =3D simd_packed_int, .to_mem =3D 1 }, - [0x8f] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, - [0x90 ... 0x93] =3D { .simd_size =3D simd_other, .vsib =3D 1, .d8s =3D= d8s_dq }, - [0x96 ... 0x98] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, - [0x99] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, - [0x9a] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, - [0x9b] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, - [0x9c] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, - [0x9d] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, - [0x9e] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, - [0x9f] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, - [0xa0 ... 0xa3] =3D { .simd_size =3D simd_other, .to_mem =3D 1, .vsib = =3D 1, .d8s =3D d8s_dq }, - [0xa6 ... 0xa8] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, - [0xa9] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, - [0xaa] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, - [0xab] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, - [0xac] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, - [0xad] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, - [0xae] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, - [0xaf] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, - [0xb4 ... 0xb5] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, - [0xb6 ... 0xb8] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, - [0xb9] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, - [0xba] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, - [0xbb] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, - [0xbc] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, - [0xbd] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, - [0xbe] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, - [0xbf] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, - [0xc4] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1, .d8s =3D d= 8s_vl }, - [0xc6 ... 0xc7] =3D { .simd_size =3D simd_other, .vsib =3D 1, .d8s =3D= d8s_dq }, - [0xc8] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d8s =3D d8= s_vl }, - [0xc9] =3D { .simd_size =3D simd_other }, - [0xca] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d8s =3D d8= s_vl }, - [0xcb] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, - [0xcc] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d8s =3D d8= s_vl }, - [0xcd] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, - [0xcf] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, - [0xdb] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, - [0xdc ... 0xdf] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, - [0xf0] =3D { .two_op =3D 1 }, - [0xf1] =3D { .to_mem =3D 1, .two_op =3D 1 }, - [0xf2 ... 0xf3] =3D {}, - [0xf5 ... 0xf7] =3D {}, - [0xf8] =3D { .simd_size =3D simd_other }, - [0xf9] =3D { .to_mem =3D 1, .two_op =3D 1 /* Mov */ }, -}; - /* Shift values between src and dst sizes of pmov{s,z}x{b,w,d}{w,d,q}. */ static const uint8_t pmov_convert_delta[] =3D { 1, 2, 3, 1, 2, 1 }; =20 -static const struct ext0f3a_table { - uint8_t simd_size:5; - uint8_t to_mem:1; - uint8_t two_op:1; - uint8_t four_op:1; - disp8scale_t d8s:4; -} ext0f3a_table[256] =3D { - [0x00] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1, .d8s =3D d= 8s_vl }, - [0x01] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d8s =3D d8= s_vl }, - [0x02] =3D { .simd_size =3D simd_packed_int }, - [0x03] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, - [0x04 ... 0x05] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d= 8s =3D d8s_vl }, - [0x06] =3D { .simd_size =3D simd_packed_fp }, - [0x08 ... 0x09] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d= 8s =3D d8s_vl }, - [0x0a ... 0x0b] =3D { .simd_size =3D simd_scalar_opc, .d8s =3D d8s_dq = }, - [0x0c ... 0x0d] =3D { .simd_size =3D simd_packed_fp }, - [0x0e] =3D { .simd_size =3D simd_packed_int }, - [0x0f] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, - [0x14] =3D { .simd_size =3D simd_none, .to_mem =3D 1, .two_op =3D 1, .= d8s =3D 0 }, - [0x15] =3D { .simd_size =3D simd_none, .to_mem =3D 1, .two_op =3D 1, .= d8s =3D 1 }, - [0x16] =3D { .simd_size =3D simd_none, .to_mem =3D 1, .two_op =3D 1, .= d8s =3D d8s_dq64 }, - [0x17] =3D { .simd_size =3D simd_none, .to_mem =3D 1, .two_op =3D 1, .= d8s =3D 2 }, - [0x18] =3D { .simd_size =3D simd_128, .d8s =3D 4 }, - [0x19] =3D { .simd_size =3D simd_128, .to_mem =3D 1, .two_op =3D 1, .d= 8s =3D 4 }, - [0x1a] =3D { .simd_size =3D simd_256, .d8s =3D d8s_vl_by_2 }, - [0x1b] =3D { .simd_size =3D simd_256, .to_mem =3D 1, .two_op =3D 1, .d= 8s =3D d8s_vl_by_2 }, - [0x1d] =3D { .simd_size =3D simd_other, .to_mem =3D 1, .two_op =3D 1, = .d8s =3D d8s_vl_by_2 }, - [0x1e ... 0x1f] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, - [0x20] =3D { .simd_size =3D simd_none, .d8s =3D 0 }, - [0x21] =3D { .simd_size =3D simd_other, .d8s =3D 2 }, - [0x22] =3D { .simd_size =3D simd_none, .d8s =3D d8s_dq64 }, - [0x23] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, - [0x25] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, - [0x26] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d8s =3D d8= s_vl }, - [0x27] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, - [0x30 ... 0x33] =3D { .simd_size =3D simd_other, .two_op =3D 1 }, - [0x38] =3D { .simd_size =3D simd_128, .d8s =3D 4 }, - [0x3a] =3D { .simd_size =3D simd_256, .d8s =3D d8s_vl_by_2 }, - [0x39] =3D { .simd_size =3D simd_128, .to_mem =3D 1, .two_op =3D 1, .d= 8s =3D 4 }, - [0x3b] =3D { .simd_size =3D simd_256, .to_mem =3D 1, .two_op =3D 1, .d= 8s =3D d8s_vl_by_2 }, - [0x3e ... 0x3f] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, - [0x40 ... 0x41] =3D { .simd_size =3D simd_packed_fp }, - [0x42 ... 0x43] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, - [0x44] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl }, - [0x46] =3D { .simd_size =3D simd_packed_int }, - [0x48 ... 0x49] =3D { .simd_size =3D simd_packed_fp, .four_op =3D 1 }, - [0x4a ... 0x4b] =3D { .simd_size =3D simd_packed_fp, .four_op =3D 1 }, - [0x4c] =3D { .simd_size =3D simd_packed_int, .four_op =3D 1 }, - [0x50] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, - [0x51] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, - [0x54] =3D { .simd_size =3D simd_packed_fp, .d8s =3D d8s_vl }, - [0x55] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, - [0x56] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d8s =3D d8= s_vl }, - [0x57] =3D { .simd_size =3D simd_scalar_vexw, .d8s =3D d8s_dq }, - [0x5c ... 0x5f] =3D { .simd_size =3D simd_packed_fp, .four_op =3D 1 }, - [0x60 ... 0x63] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, - [0x66] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1, .d8s =3D d8= s_vl }, - [0x67] =3D { .simd_size =3D simd_scalar_vexw, .two_op =3D 1, .d8s =3D = d8s_dq }, - [0x68 ... 0x69] =3D { .simd_size =3D simd_packed_fp, .four_op =3D 1 }, - [0x6a ... 0x6b] =3D { .simd_size =3D simd_scalar_opc, .four_op =3D 1 }, - [0x6c ... 0x6d] =3D { .simd_size =3D simd_packed_fp, .four_op =3D 1 }, - [0x6e ... 0x6f] =3D { .simd_size =3D simd_scalar_opc, .four_op =3D 1 }, - [0x70 ... 0x73] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, - [0x78 ... 0x79] =3D { .simd_size =3D simd_packed_fp, .four_op =3D 1 }, - [0x7a ... 0x7b] =3D { .simd_size =3D simd_scalar_opc, .four_op =3D 1 }, - [0x7c ... 0x7d] =3D { .simd_size =3D simd_packed_fp, .four_op =3D 1 }, - [0x7e ... 0x7f] =3D { .simd_size =3D simd_scalar_opc, .four_op =3D 1 }, - [0xcc] =3D { .simd_size =3D simd_other }, - [0xce ... 0xcf] =3D { .simd_size =3D simd_packed_int, .d8s =3D d8s_vl = }, - [0xdf] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, - [0xf0] =3D {}, -}; - -static const opcode_desc_t xop_table[] =3D { - DstReg|SrcImmByte|ModRM, - DstReg|SrcMem|ModRM, - DstReg|SrcImm|ModRM, -}; - -static const struct ext8f08_table { - uint8_t simd_size:5; - uint8_t two_op:1; - uint8_t four_op:1; -} ext8f08_table[256] =3D { - [0xa2] =3D { .simd_size =3D simd_packed_int, .four_op =3D 1 }, - [0x85 ... 0x87] =3D { .simd_size =3D simd_packed_int, .four_op =3D 1 }, - [0x8e ... 0x8f] =3D { .simd_size =3D simd_packed_int, .four_op =3D 1 }, - [0x95 ... 0x97] =3D { .simd_size =3D simd_packed_int, .four_op =3D 1 }, - [0x9e ... 0x9f] =3D { .simd_size =3D simd_packed_int, .four_op =3D 1 }, - [0xa3] =3D { .simd_size =3D simd_packed_int, .four_op =3D 1 }, - [0xa6] =3D { .simd_size =3D simd_packed_int, .four_op =3D 1 }, - [0xb6] =3D { .simd_size =3D simd_packed_int, .four_op =3D 1 }, - [0xc0 ... 0xc3] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, - [0xcc ... 0xcf] =3D { .simd_size =3D simd_packed_int }, - [0xec ... 0xef] =3D { .simd_size =3D simd_packed_int }, -}; - -static const struct ext8f09_table { - uint8_t simd_size:5; - uint8_t two_op:1; -} ext8f09_table[256] =3D { - [0x01 ... 0x02] =3D { .two_op =3D 1 }, - [0x80 ... 0x81] =3D { .simd_size =3D simd_packed_fp, .two_op =3D 1 }, - [0x82 ... 0x83] =3D { .simd_size =3D simd_scalar_opc, .two_op =3D 1 }, - [0x90 ... 0x9b] =3D { .simd_size =3D simd_packed_int }, - [0xc1 ... 0xc3] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, - [0xc6 ... 0xc7] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, - [0xcb] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, - [0xd1 ... 0xd3] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, - [0xd6 ... 0xd7] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, - [0xdb] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, - [0xe1 ... 0xe3] =3D { .simd_size =3D simd_packed_int, .two_op =3D 1 }, -}; - -#define VEX_PREFIX_DOUBLE_MASK 0x1 -#define VEX_PREFIX_SCALAR_MASK 0x2 - static const uint8_t sse_prefix[] =3D { 0x66, 0xf3, 0xf2 }; =20 #ifdef __x86_64__ @@ -637,12 +121,6 @@ static const uint8_t sse_prefix[] =3D { 0x #define repe_prefix() (vex.pfx =3D=3D vex_f3) #define repne_prefix() (vex.pfx =3D=3D vex_f2) =20 -#ifdef __x86_64__ -#define PTR_POISON ((void *)0x8086000000008086UL) /* non-canonical */ -#else -#define PTR_POISON NULL /* 32-bit builds are for user-space, so NULL is OK= . */ -#endif - /* * While proper alignment gets specified in mmval_t, this doesn't get hono= red * by the compiler for automatic variables. Use this helper to instantiate= a @@ -831,19 +309,6 @@ do{ asm volatile ( : [msk] "i" (EFLAGS_MASK), ## src); \ } while (0) =20 -/* Fetch next part of the instruction being emulated. */ -#define insn_fetch_bytes(_size) \ -({ unsigned long _x =3D 0, _ip =3D state->ip; = \ - state->ip +=3D (_size); /* real hardware doesn't truncate */ \ - generate_exception_if((uint8_t)(state->ip - \ - ctxt->regs->r(ip)) > MAX_INST_LEN, \ - EXC_GP, 0); \ - rc =3D ops->insn_fetch(x86_seg_cs, _ip, &_x, (_size), ctxt); \ - if ( rc ) goto done; \ - _x; \ -}) -#define insn_fetch_type(_type) ((_type)insn_fetch_bytes(sizeof(_type))) - /* * Given byte has even parity (even number of 1s)? SDM Vol. 1 Sec. 3.4.3.1, * "Status Flags": EFLAGS.PF reflects parity of least-sig. byte of result = only. @@ -1354,13 +819,6 @@ static int ioport_access_check( return rc; } =20 -/* Initialise output state in x86_emulate_ctxt */ -static void init_context(struct x86_emulate_ctxt *ctxt) -{ - ctxt->retire.raw =3D 0; - x86_emul_reset_event(ctxt); -} - static int realmode_load_seg( enum x86_segment seg, @@ -1707,51 +1165,6 @@ static unsigned long *decode_vex_gpr( return decode_gpr(regs, ~vex_reg & (mode_64bit() ? 0xf : 7)); } =20 -static unsigned int decode_disp8scale(enum disp8scale scale, - const struct x86_emulate_state *stat= e) -{ - switch ( scale ) - { - case d8s_bw: - return state->evex.w; - - default: - if ( scale < d8s_vl ) - return scale; - if ( state->evex.brs ) - { - case d8s_dq: - return 2 + state->evex.w; - } - break; - - case d8s_dq64: - return 2 + (state->op_bytes =3D=3D 8); - } - - switch ( state->simd_size ) - { - case simd_any_fp: - case simd_single_fp: - if ( !(state->evex.pfx & VEX_PREFIX_SCALAR_MASK) ) - break; - /* fall through */ - case simd_scalar_opc: - case simd_scalar_vexw: - return 2 + state->evex.w; - - case simd_128: - /* These should have an explicit size specified. */ - ASSERT_UNREACHABLE(); - return 4; - - default: - break; - } - - return 4 + state->evex.lr - (scale - d8s_vl); -} - #define avx512_vlen_check(lig) do { \ switch ( evex.lr ) \ { \ @@ -1833,1138 +1246,6 @@ int x86emul_unhandleable_rw( #define evex_encoded() (evex.mbs) #define ea (state->ea) =20 -static int -x86_decode_onebyte( - struct x86_emulate_state *state, - struct x86_emulate_ctxt *ctxt, - const struct x86_emulate_ops *ops) -{ - int rc =3D X86EMUL_OKAY; - - switch ( ctxt->opcode ) - { - case 0x06: /* push %%es */ - case 0x07: /* pop %%es */ - case 0x0e: /* push %%cs */ - case 0x16: /* push %%ss */ - case 0x17: /* pop %%ss */ - case 0x1e: /* push %%ds */ - case 0x1f: /* pop %%ds */ - case 0x27: /* daa */ - case 0x2f: /* das */ - case 0x37: /* aaa */ - case 0x3f: /* aas */ - case 0x60: /* pusha */ - case 0x61: /* popa */ - case 0x62: /* bound */ - case 0xc4: /* les */ - case 0xc5: /* lds */ - case 0xce: /* into */ - case 0xd4: /* aam */ - case 0xd5: /* aad */ - case 0xd6: /* salc */ - state->not_64bit =3D true; - break; - - case 0x82: /* Grp1 (x86/32 only) */ - state->not_64bit =3D true; - /* fall through */ - case 0x80: case 0x81: case 0x83: /* Grp1 */ - if ( (modrm_reg & 7) =3D=3D 7 ) /* cmp */ - state->desc =3D (state->desc & ByteOp) | DstNone | SrcMem; - break; - - case 0x90: /* nop / pause */ - if ( repe_prefix() ) - ctxt->opcode |=3D X86EMUL_OPC_F3(0, 0); - break; - - case 0x9a: /* call (far, absolute) */ - case 0xea: /* jmp (far, absolute) */ - generate_exception_if(mode_64bit(), EXC_UD); - - imm1 =3D insn_fetch_bytes(op_bytes); - imm2 =3D insn_fetch_type(uint16_t); - break; - - case 0xa0: case 0xa1: /* mov mem.offs,{%al,%ax,%eax,%rax} */ - case 0xa2: case 0xa3: /* mov {%al,%ax,%eax,%rax},mem.offs */ - /* Source EA is not encoded via ModRM. */ - ea.type =3D OP_MEM; - ea.mem.off =3D insn_fetch_bytes(ad_bytes); - break; - - case 0xb8 ... 0xbf: /* mov imm{16,32,64},r{16,32,64} */ - if ( op_bytes =3D=3D 8 ) /* Fetch more bytes to obtain imm64. */ - imm1 =3D ((uint32_t)imm1 | - ((uint64_t)insn_fetch_type(uint32_t) << 32)); - break; - - case 0xc8: /* enter imm16,imm8 */ - imm2 =3D insn_fetch_type(uint8_t); - break; - - case 0xf6: case 0xf7: /* Grp3 */ - if ( !(modrm_reg & 6) ) /* test */ - state->desc =3D (state->desc & ByteOp) | DstNone | SrcMem; - break; - - case 0xff: /* Grp5 */ - switch ( modrm_reg & 7 ) - { - case 2: /* call (near) */ - case 4: /* jmp (near) */ - if ( mode_64bit() && (op_bytes =3D=3D 4 || !amd_like(ctxt)) ) - op_bytes =3D 8; - state->desc =3D DstNone | SrcMem | Mov; - break; - - case 3: /* call (far, absolute indirect) */ - case 5: /* jmp (far, absolute indirect) */ - /* REX.W ignored on a vendor-dependent basis. */ - if ( op_bytes =3D=3D 8 && amd_like(ctxt) ) - op_bytes =3D 4; - state->desc =3D DstNone | SrcMem | Mov; - break; - - case 6: /* push */ - if ( mode_64bit() && op_bytes =3D=3D 4 ) - op_bytes =3D 8; - state->desc =3D DstNone | SrcMem | Mov; - break; - } - break; - } - - done: - return rc; -} - -static int -x86_decode_twobyte( - struct x86_emulate_state *state, - struct x86_emulate_ctxt *ctxt, - const struct x86_emulate_ops *ops) -{ - int rc =3D X86EMUL_OKAY; - - switch ( ctxt->opcode & X86EMUL_OPC_MASK ) - { - case 0x00: /* Grp6 */ - switch ( modrm_reg & 6 ) - { - case 0: - state->desc |=3D DstMem | SrcImplicit | Mov; - break; - case 2: case 4: - state->desc |=3D SrcMem16; - break; - } - break; - - case 0x78: - state->desc =3D ImplicitOps; - state->simd_size =3D simd_none; - switch ( vex.pfx ) - { - case vex_66: /* extrq $imm8, $imm8, xmm */ - case vex_f2: /* insertq $imm8, $imm8, xmm, xmm */ - imm1 =3D insn_fetch_type(uint8_t); - imm2 =3D insn_fetch_type(uint8_t); - break; - } - /* fall through */ - case 0x10 ... 0x18: - case 0x28 ... 0x2f: - case 0x50 ... 0x77: - case 0x7a ... 0x7d: - case 0x7f: - case 0xc2 ... 0xc3: - case 0xc5 ... 0xc6: - case 0xd0 ... 0xef: - case 0xf1 ... 0xfe: - ctxt->opcode |=3D MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK); - break; - - case 0x20: case 0x22: /* mov to/from cr */ - if ( lock_prefix && vcpu_has_cr8_legacy() ) - { - modrm_reg +=3D 8; - lock_prefix =3D false; - } - /* fall through */ - case 0x21: case 0x23: /* mov to/from dr */ - ASSERT(ea.type =3D=3D OP_REG); /* Early operand adjustment ensures= this. */ - generate_exception_if(lock_prefix, EXC_UD); - op_bytes =3D mode_64bit() ? 8 : 4; - break; - - case 0x79: - state->desc =3D DstReg | SrcMem; - state->simd_size =3D simd_packed_int; - ctxt->opcode |=3D MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK); - break; - - case 0x7e: - ctxt->opcode |=3D MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK); - if ( vex.pfx =3D=3D vex_f3 ) /* movq xmm/m64,xmm */ - { - case X86EMUL_OPC_VEX_F3(0, 0x7e): /* vmovq xmm/m64,xmm */ - case X86EMUL_OPC_EVEX_F3(0, 0x7e): /* vmovq xmm/m64,xmm */ - state->desc =3D DstImplicit | SrcMem | TwoOp; - state->simd_size =3D simd_other; - /* Avoid the state->desc clobbering of TwoOp below. */ - return X86EMUL_OKAY; - } - break; - - case X86EMUL_OPC_VEX(0, 0x90): /* kmov{w,q} */ - case X86EMUL_OPC_VEX_66(0, 0x90): /* kmov{b,d} */ - state->desc =3D DstReg | SrcMem | Mov; - state->simd_size =3D simd_other; - break; - - case X86EMUL_OPC_VEX(0, 0x91): /* kmov{w,q} */ - case X86EMUL_OPC_VEX_66(0, 0x91): /* kmov{b,d} */ - state->desc =3D DstMem | SrcReg | Mov; - state->simd_size =3D simd_other; - break; - - case 0xae: - ctxt->opcode |=3D MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK); - /* fall through */ - case X86EMUL_OPC_VEX(0, 0xae): - switch ( modrm_reg & 7 ) - { - case 2: /* {,v}ldmxcsr */ - state->desc =3D DstImplicit | SrcMem | Mov; - op_bytes =3D 4; - break; - - case 3: /* {,v}stmxcsr */ - state->desc =3D DstMem | SrcImplicit | Mov; - op_bytes =3D 4; - break; - } - break; - - case 0xb2: /* lss */ - case 0xb4: /* lfs */ - case 0xb5: /* lgs */ - /* REX.W ignored on a vendor-dependent basis. */ - if ( op_bytes =3D=3D 8 && amd_like(ctxt) ) - op_bytes =3D 4; - break; - - case 0xb8: /* jmpe / popcnt */ - if ( rep_prefix() ) - ctxt->opcode |=3D MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK); - break; - - /* Intentionally not handling here despite being modified by F3: - case 0xbc: bsf / tzcnt - case 0xbd: bsr / lzcnt - * They're being dealt with in the execution phase (if at all). - */ - - case 0xc4: /* pinsrw */ - ctxt->opcode |=3D MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK); - /* fall through */ - case X86EMUL_OPC_VEX_66(0, 0xc4): /* vpinsrw */ - case X86EMUL_OPC_EVEX_66(0, 0xc4): /* vpinsrw */ - state->desc =3D DstImplicit | SrcMem16; - break; - - case 0xf0: - ctxt->opcode |=3D MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK); - if ( vex.pfx =3D=3D vex_f2 ) /* lddqu mem,xmm */ - { - /* fall through */ - case X86EMUL_OPC_VEX_F2(0, 0xf0): /* vlddqu mem,{x,y}mm */ - state->desc =3D DstImplicit | SrcMem | TwoOp; - state->simd_size =3D simd_other; - /* Avoid the state->desc clobbering of TwoOp below. */ - return X86EMUL_OKAY; - } - break; - } - - /* - * Scalar forms of most VEX-/EVEX-encoded TwoOp instructions have - * three operands. Those which do really have two operands - * should have exited earlier. - */ - if ( state->simd_size && vex.opcx && - (vex.pfx & VEX_PREFIX_SCALAR_MASK) ) - state->desc &=3D ~TwoOp; - - done: - return rc; -} - -static int -x86_decode_0f38( - struct x86_emulate_state *state, - struct x86_emulate_ctxt *ctxt, - const struct x86_emulate_ops *ops) -{ - switch ( ctxt->opcode & X86EMUL_OPC_MASK ) - { - case 0x00 ... 0xef: - case 0xf2 ... 0xf5: - case 0xf7 ... 0xf8: - case 0xfa ... 0xff: - op_bytes =3D 0; - /* fall through */ - case 0xf6: /* adcx / adox */ - case 0xf9: /* movdiri */ - ctxt->opcode |=3D MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK); - break; - - case X86EMUL_OPC_EVEX_66(0, 0x2d): /* vscalefs{s,d} */ - state->simd_size =3D simd_scalar_vexw; - break; - - case X86EMUL_OPC_EVEX_66(0, 0x7a): /* vpbroadcastb */ - case X86EMUL_OPC_EVEX_66(0, 0x7b): /* vpbroadcastw */ - case X86EMUL_OPC_EVEX_66(0, 0x7c): /* vpbroadcast{d,q} */ - break; - - case 0xf0: /* movbe / crc32 */ - state->desc |=3D repne_prefix() ? ByteOp : Mov; - if ( rep_prefix() ) - ctxt->opcode |=3D MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK); - break; - - case 0xf1: /* movbe / crc32 */ - if ( repne_prefix() ) - state->desc =3D DstReg | SrcMem; - if ( rep_prefix() ) - ctxt->opcode |=3D MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK); - break; - - case X86EMUL_OPC_VEX(0, 0xf2): /* andn */ - case X86EMUL_OPC_VEX(0, 0xf3): /* Grp 17 */ - case X86EMUL_OPC_VEX(0, 0xf5): /* bzhi */ - case X86EMUL_OPC_VEX_F3(0, 0xf5): /* pext */ - case X86EMUL_OPC_VEX_F2(0, 0xf5): /* pdep */ - case X86EMUL_OPC_VEX_F2(0, 0xf6): /* mulx */ - case X86EMUL_OPC_VEX(0, 0xf7): /* bextr */ - case X86EMUL_OPC_VEX_66(0, 0xf7): /* shlx */ - case X86EMUL_OPC_VEX_F3(0, 0xf7): /* sarx */ - case X86EMUL_OPC_VEX_F2(0, 0xf7): /* shrx */ - break; - - default: - op_bytes =3D 0; - break; - } - - return X86EMUL_OKAY; -} - -static int -x86_decode_0f3a( - struct x86_emulate_state *state, - struct x86_emulate_ctxt *ctxt, - const struct x86_emulate_ops *ops) -{ - if ( !vex.opcx ) - ctxt->opcode |=3D MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK); - - switch ( ctxt->opcode & X86EMUL_OPC_MASK ) - { - case X86EMUL_OPC_66(0, 0x14) - ... X86EMUL_OPC_66(0, 0x17): /* pextr*, extractps */ - case X86EMUL_OPC_VEX_66(0, 0x14) - ... X86EMUL_OPC_VEX_66(0, 0x17): /* vpextr*, vextractps */ - case X86EMUL_OPC_EVEX_66(0, 0x14) - ... X86EMUL_OPC_EVEX_66(0, 0x17): /* vpextr*, vextractps */ - case X86EMUL_OPC_VEX_F2(0, 0xf0): /* rorx */ - break; - - case X86EMUL_OPC_66(0, 0x20): /* pinsrb */ - case X86EMUL_OPC_VEX_66(0, 0x20): /* vpinsrb */ - case X86EMUL_OPC_EVEX_66(0, 0x20): /* vpinsrb */ - state->desc =3D DstImplicit | SrcMem; - if ( modrm_mod !=3D 3 ) - state->desc |=3D ByteOp; - break; - - case X86EMUL_OPC_66(0, 0x22): /* pinsr{d,q} */ - case X86EMUL_OPC_VEX_66(0, 0x22): /* vpinsr{d,q} */ - case X86EMUL_OPC_EVEX_66(0, 0x22): /* vpinsr{d,q} */ - state->desc =3D DstImplicit | SrcMem; - break; - - default: - op_bytes =3D 0; - break; - } - - return X86EMUL_OKAY; -} - -static int -x86_decode( - struct x86_emulate_state *state, - struct x86_emulate_ctxt *ctxt, - const struct x86_emulate_ops *ops) -{ - uint8_t b, d; - unsigned int def_op_bytes, def_ad_bytes, opcode; - enum x86_segment override_seg =3D x86_seg_none; - bool pc_rel =3D false; - int rc =3D X86EMUL_OKAY; - - ASSERT(ops->insn_fetch); - - memset(state, 0, sizeof(*state)); - ea.type =3D OP_NONE; - ea.mem.seg =3D x86_seg_ds; - ea.reg =3D PTR_POISON; - state->regs =3D ctxt->regs; - state->ip =3D ctxt->regs->r(ip); - - op_bytes =3D def_op_bytes =3D ad_bytes =3D def_ad_bytes =3D ctxt->addr= _size/8; - if ( op_bytes =3D=3D 8 ) - { - op_bytes =3D def_op_bytes =3D 4; -#ifndef __x86_64__ - return X86EMUL_UNHANDLEABLE; -#endif - } - - /* Prefix bytes. */ - for ( ; ; ) - { - switch ( b =3D insn_fetch_type(uint8_t) ) - { - case 0x66: /* operand-size override */ - op_bytes =3D def_op_bytes ^ 6; - if ( !vex.pfx ) - vex.pfx =3D vex_66; - break; - case 0x67: /* address-size override */ - ad_bytes =3D def_ad_bytes ^ (mode_64bit() ? 12 : 6); - break; - case 0x2e: /* CS override / ignored in 64-bit mode */ - if ( !mode_64bit() ) - override_seg =3D x86_seg_cs; - break; - case 0x3e: /* DS override / ignored in 64-bit mode */ - if ( !mode_64bit() ) - override_seg =3D x86_seg_ds; - break; - case 0x26: /* ES override / ignored in 64-bit mode */ - if ( !mode_64bit() ) - override_seg =3D x86_seg_es; - break; - case 0x64: /* FS override */ - override_seg =3D x86_seg_fs; - break; - case 0x65: /* GS override */ - override_seg =3D x86_seg_gs; - break; - case 0x36: /* SS override / ignored in 64-bit mode */ - if ( !mode_64bit() ) - override_seg =3D x86_seg_ss; - break; - case 0xf0: /* LOCK */ - lock_prefix =3D 1; - break; - case 0xf2: /* REPNE/REPNZ */ - vex.pfx =3D vex_f2; - break; - case 0xf3: /* REP/REPE/REPZ */ - vex.pfx =3D vex_f3; - break; - case 0x40 ... 0x4f: /* REX */ - if ( !mode_64bit() ) - goto done_prefixes; - rex_prefix =3D b; - continue; - default: - goto done_prefixes; - } - - /* Any legacy prefix after a REX prefix nullifies its effect. */ - rex_prefix =3D 0; - } - done_prefixes: - - if ( rex_prefix & REX_W ) - op_bytes =3D 8; - - /* Opcode byte(s). */ - d =3D opcode_table[b]; - if ( d =3D=3D 0 && b =3D=3D 0x0f ) - { - /* Two-byte opcode. */ - b =3D insn_fetch_type(uint8_t); - d =3D twobyte_table[b].desc; - switch ( b ) - { - default: - opcode =3D b | MASK_INSR(0x0f, X86EMUL_OPC_EXT_MASK); - ext =3D ext_0f; - state->simd_size =3D twobyte_table[b].size; - break; - case 0x38: - b =3D insn_fetch_type(uint8_t); - opcode =3D b | MASK_INSR(0x0f38, X86EMUL_OPC_EXT_MASK); - ext =3D ext_0f38; - break; - case 0x3a: - b =3D insn_fetch_type(uint8_t); - opcode =3D b | MASK_INSR(0x0f3a, X86EMUL_OPC_EXT_MASK); - ext =3D ext_0f3a; - break; - } - } - else - opcode =3D b; - - /* ModRM and SIB bytes. */ - if ( d & ModRM ) - { - modrm =3D insn_fetch_type(uint8_t); - modrm_mod =3D (modrm & 0xc0) >> 6; - - if ( !ext && ((b & ~1) =3D=3D 0xc4 || (b =3D=3D 0x8f && (modrm & 0= x18)) || - b =3D=3D 0x62) ) - switch ( def_ad_bytes ) - { - default: - BUG(); /* Shouldn't be possible. */ - case 2: - if ( state->regs->eflags & X86_EFLAGS_VM ) - break; - /* fall through */ - case 4: - if ( modrm_mod !=3D 3 || in_realmode(ctxt, ops) ) - break; - /* fall through */ - case 8: - /* VEX / XOP / EVEX */ - generate_exception_if(rex_prefix || vex.pfx, EXC_UD); - /* - * With operand size override disallowed (see above), op_b= ytes - * should not have changed from its default. - */ - ASSERT(op_bytes =3D=3D def_op_bytes); - - vex.raw[0] =3D modrm; - if ( b =3D=3D 0xc5 ) - { - opcode =3D X86EMUL_OPC_VEX_; - vex.raw[1] =3D modrm; - vex.opcx =3D vex_0f; - vex.x =3D 1; - vex.b =3D 1; - vex.w =3D 0; - } - else - { - vex.raw[1] =3D insn_fetch_type(uint8_t); - if ( mode_64bit() ) - { - if ( !vex.b ) - rex_prefix |=3D REX_B; - if ( !vex.x ) - rex_prefix |=3D REX_X; - if ( vex.w ) - { - rex_prefix |=3D REX_W; - op_bytes =3D 8; - } - } - else - { - /* Operand size fixed at 4 (no override via W bit)= . */ - op_bytes =3D 4; - vex.b =3D 1; - } - switch ( b ) - { - case 0x62: - opcode =3D X86EMUL_OPC_EVEX_; - evex.raw[0] =3D vex.raw[0]; - evex.raw[1] =3D vex.raw[1]; - evex.raw[2] =3D insn_fetch_type(uint8_t); - - generate_exception_if(!evex.mbs || evex.mbz, EXC_U= D); - generate_exception_if(!evex.opmsk && evex.z, EXC_U= D); - - if ( !mode_64bit() ) - evex.R =3D 1; - - vex.opcx =3D evex.opcx; - break; - case 0xc4: - opcode =3D X86EMUL_OPC_VEX_; - break; - default: - opcode =3D 0; - break; - } - } - if ( !vex.r ) - rex_prefix |=3D REX_R; - - ext =3D vex.opcx; - if ( b !=3D 0x8f ) - { - b =3D insn_fetch_type(uint8_t); - switch ( ext ) - { - case vex_0f: - opcode |=3D MASK_INSR(0x0f, X86EMUL_OPC_EXT_MASK); - d =3D twobyte_table[b].desc; - state->simd_size =3D twobyte_table[b].size; - break; - case vex_0f38: - opcode |=3D MASK_INSR(0x0f38, X86EMUL_OPC_EXT_MASK= ); - d =3D twobyte_table[0x38].desc; - break; - case vex_0f3a: - opcode |=3D MASK_INSR(0x0f3a, X86EMUL_OPC_EXT_MASK= ); - d =3D twobyte_table[0x3a].desc; - break; - default: - rc =3D X86EMUL_UNRECOGNIZED; - goto done; - } - } - else if ( ext < ext_8f08 + ARRAY_SIZE(xop_table) ) - { - b =3D insn_fetch_type(uint8_t); - opcode |=3D MASK_INSR(0x8f08 + ext - ext_8f08, - X86EMUL_OPC_EXT_MASK); - d =3D array_access_nospec(xop_table, ext - ext_8f08); - } - else - { - rc =3D X86EMUL_UNRECOGNIZED; - goto done; - } - - opcode |=3D b | MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK); - - if ( !evex_encoded() ) - evex.lr =3D vex.l; - - if ( !(d & ModRM) ) - break; - - modrm =3D insn_fetch_type(uint8_t); - modrm_mod =3D (modrm & 0xc0) >> 6; - - break; - } - } - - if ( d & ModRM ) - { - unsigned int disp8scale =3D 0; - - d &=3D ~ModRM; -#undef ModRM /* Only its aliases are valid to use from here on. */ - modrm_reg =3D ((rex_prefix & 4) << 1) | ((modrm & 0x38) >> 3) | - ((evex_encoded() && !evex.R) << 4); - modrm_rm =3D modrm & 0x07; - - /* - * Early operand adjustments. Only ones affecting further processi= ng - * prior to the x86_decode_*() calls really belong here. That would - * normally be only addition/removal of SrcImm/SrcImm16, so their - * fetching can be taken care of by the common code below. - */ - switch ( ext ) - { - case ext_none: - switch ( b ) - { - case 0xf6 ... 0xf7: /* Grp3 */ - switch ( modrm_reg & 7 ) - { - case 0 ... 1: /* test */ - d |=3D DstMem | SrcImm; - break; - case 2: /* not */ - case 3: /* neg */ - d |=3D DstMem; - break; - case 4: /* mul */ - case 5: /* imul */ - case 6: /* div */ - case 7: /* idiv */ - /* - * DstEax isn't really precise for all cases; updates = to - * rDX get handled in an open coded manner. - */ - d |=3D DstEax | SrcMem; - break; - } - break; - } - break; - - case ext_0f: - if ( evex_encoded() ) - disp8scale =3D decode_disp8scale(twobyte_table[b].d8s, sta= te); - - switch ( b ) - { - case 0x12: /* vmovsldup / vmovddup */ - if ( evex.pfx =3D=3D vex_f2 ) - disp8scale =3D evex.lr ? 4 + evex.lr : 3; - /* fall through */ - case 0x16: /* vmovshdup */ - if ( evex.pfx =3D=3D vex_f3 ) - disp8scale =3D 4 + evex.lr; - break; - - case 0x20: /* mov cr,reg */ - case 0x21: /* mov dr,reg */ - case 0x22: /* mov reg,cr */ - case 0x23: /* mov reg,dr */ - /* - * Mov to/from cr/dr ignore the encoding of Mod, and behav= e as - * if they were encoded as reg/reg instructions. No furth= er - * disp/SIB bytes are fetched. - */ - modrm_mod =3D 3; - break; - - case 0x78: - case 0x79: - if ( !evex.pfx ) - break; - /* vcvt{,t}ps2uqq need special casing */ - if ( evex.pfx =3D=3D vex_66 ) - { - if ( !evex.w && !evex.brs ) - --disp8scale; - break; - } - /* vcvt{,t}s{s,d}2usi need special casing: fall through */ - case 0x2c: /* vcvtts{s,d}2si need special casing */ - case 0x2d: /* vcvts{s,d}2si need special casing */ - if ( evex_encoded() ) - disp8scale =3D 2 + (evex.pfx & VEX_PREFIX_DOUBLE_MASK); - break; - - case 0x5a: /* vcvtps2pd needs special casing */ - if ( disp8scale && !evex.pfx && !evex.brs ) - --disp8scale; - break; - - case 0x7a: /* vcvttps2qq and vcvtudq2pd need special casing */ - if ( disp8scale && evex.pfx !=3D vex_f2 && !evex.w && !eve= x.brs ) - --disp8scale; - break; - - case 0x7b: /* vcvtp{s,d}2qq need special casing */ - if ( disp8scale && evex.pfx =3D=3D vex_66 ) - disp8scale =3D (evex.brs ? 2 : 3 + evex.lr) + evex.w; - break; - - case 0x7e: /* vmovq xmm/m64,xmm needs special casing */ - if ( disp8scale =3D=3D 2 && evex.pfx =3D=3D vex_f3 ) - disp8scale =3D 3; - break; - - case 0xe6: /* vcvtdq2pd needs special casing */ - if ( disp8scale && evex.pfx =3D=3D vex_f3 && !evex.w && !e= vex.brs ) - --disp8scale; - break; - } - break; - - case ext_0f38: - d =3D ext0f38_table[b].to_mem ? DstMem | SrcReg - : DstReg | SrcMem; - if ( ext0f38_table[b].two_op ) - d |=3D TwoOp; - if ( ext0f38_table[b].vsib ) - d |=3D vSIB; - state->simd_size =3D ext0f38_table[b].simd_size; - if ( evex_encoded() ) - { - /* - * VPMOVUS* are identical to VPMOVS* Disp8-scaling-wise, b= ut - * their attributes don't match those of the vex_66 encoded - * insns with the same base opcodes. Rather than adding new - * columns to the table, handle this here for now. - */ - if ( evex.pfx !=3D vex_f3 || (b & 0xf8) !=3D 0x10 ) - disp8scale =3D decode_disp8scale(ext0f38_table[b].d8s,= state); - else - { - disp8scale =3D decode_disp8scale(ext0f38_table[b ^ 0x3= 0].d8s, - state); - state->simd_size =3D simd_other; - } - - switch ( b ) - { - /* vp4dpwssd{,s} need special casing */ - case 0x52: case 0x53: - /* v4f{,n}madd{p,s}s need special casing */ - case 0x9a: case 0x9b: case 0xaa: case 0xab: - if ( evex.pfx =3D=3D vex_f2 ) - { - disp8scale =3D 4; - state->simd_size =3D simd_128; - } - break; - } - } - break; - - case ext_0f3a: - /* - * Cannot update d here yet, as the immediate operand still - * needs fetching. - */ - state->simd_size =3D ext0f3a_table[b].simd_size; - if ( evex_encoded() ) - disp8scale =3D decode_disp8scale(ext0f3a_table[b].d8s, sta= te); - break; - - case ext_8f09: - if ( ext8f09_table[b].two_op ) - d |=3D TwoOp; - state->simd_size =3D ext8f09_table[b].simd_size; - break; - - case ext_8f08: - case ext_8f0a: - /* - * Cannot update d here yet, as the immediate operand still - * needs fetching. - */ - break; - - default: - ASSERT_UNREACHABLE(); - return X86EMUL_UNIMPLEMENTED; - } - - if ( modrm_mod =3D=3D 3 ) - { - generate_exception_if(d & vSIB, EXC_UD); - modrm_rm |=3D ((rex_prefix & 1) << 3) | - ((evex_encoded() && !evex.x) << 4); - ea.type =3D OP_REG; - } - else if ( ad_bytes =3D=3D 2 ) - { - /* 16-bit ModR/M decode. */ - generate_exception_if(d & vSIB, EXC_UD); - ea.type =3D OP_MEM; - switch ( modrm_rm ) - { - case 0: - ea.mem.off =3D state->regs->bx + state->regs->si; - break; - case 1: - ea.mem.off =3D state->regs->bx + state->regs->di; - break; - case 2: - ea.mem.seg =3D x86_seg_ss; - ea.mem.off =3D state->regs->bp + state->regs->si; - break; - case 3: - ea.mem.seg =3D x86_seg_ss; - ea.mem.off =3D state->regs->bp + state->regs->di; - break; - case 4: - ea.mem.off =3D state->regs->si; - break; - case 5: - ea.mem.off =3D state->regs->di; - break; - case 6: - if ( modrm_mod =3D=3D 0 ) - break; - ea.mem.seg =3D x86_seg_ss; - ea.mem.off =3D state->regs->bp; - break; - case 7: - ea.mem.off =3D state->regs->bx; - break; - } - switch ( modrm_mod ) - { - case 0: - if ( modrm_rm =3D=3D 6 ) - ea.mem.off =3D insn_fetch_type(int16_t); - break; - case 1: - ea.mem.off +=3D insn_fetch_type(int8_t) * (1 << disp8scale= ); - break; - case 2: - ea.mem.off +=3D insn_fetch_type(int16_t); - break; - } - } - else - { - /* 32/64-bit ModR/M decode. */ - ea.type =3D OP_MEM; - if ( modrm_rm =3D=3D 4 ) - { - uint8_t sib =3D insn_fetch_type(uint8_t); - uint8_t sib_base =3D (sib & 7) | ((rex_prefix << 3) & 8); - - state->sib_index =3D ((sib >> 3) & 7) | ((rex_prefix << 2)= & 8); - state->sib_scale =3D (sib >> 6) & 3; - if ( unlikely(d & vSIB) ) - state->sib_index |=3D (mode_64bit() && evex_encoded() = && - !evex.RX) << 4; - else if ( state->sib_index !=3D 4 ) - { - ea.mem.off =3D *decode_gpr(state->regs, state->sib_ind= ex); - ea.mem.off <<=3D state->sib_scale; - } - if ( (modrm_mod =3D=3D 0) && ((sib_base & 7) =3D=3D 5) ) - ea.mem.off +=3D insn_fetch_type(int32_t); - else if ( sib_base =3D=3D 4 ) - { - ea.mem.seg =3D x86_seg_ss; - ea.mem.off +=3D state->regs->r(sp); - if ( !ext && (b =3D=3D 0x8f) ) - /* POP computes its EA post increment. */ - ea.mem.off +=3D ((mode_64bit() && (op_bytes =3D=3D= 4)) - ? 8 : op_bytes); - } - else if ( sib_base =3D=3D 5 ) - { - ea.mem.seg =3D x86_seg_ss; - ea.mem.off +=3D state->regs->r(bp); - } - else - ea.mem.off +=3D *decode_gpr(state->regs, sib_base); - } - else - { - generate_exception_if(d & vSIB, EXC_UD); - modrm_rm |=3D (rex_prefix & 1) << 3; - ea.mem.off =3D *decode_gpr(state->regs, modrm_rm); - if ( (modrm_rm =3D=3D 5) && (modrm_mod !=3D 0) ) - ea.mem.seg =3D x86_seg_ss; - } - switch ( modrm_mod ) - { - case 0: - if ( (modrm_rm & 7) !=3D 5 ) - break; - ea.mem.off =3D insn_fetch_type(int32_t); - pc_rel =3D mode_64bit(); - break; - case 1: - ea.mem.off +=3D insn_fetch_type(int8_t) * (1 << disp8scale= ); - break; - case 2: - ea.mem.off +=3D insn_fetch_type(int32_t); - break; - } - } - } - else - { - modrm_mod =3D 0xff; - modrm_reg =3D modrm_rm =3D modrm =3D 0; - } - - if ( override_seg !=3D x86_seg_none ) - ea.mem.seg =3D override_seg; - - /* Fetch the immediate operand, if present. */ - switch ( d & SrcMask ) - { - unsigned int bytes; - - case SrcImm: - if ( !(d & ByteOp) ) - { - if ( mode_64bit() && !amd_like(ctxt) && - ((ext =3D=3D ext_none && (b | 1) =3D=3D 0xe9) /* call / j= mp */ || - (ext =3D=3D ext_0f && (b | 0xf) =3D=3D 0x8f) /* jcc */ )= ) - op_bytes =3D 4; - bytes =3D op_bytes !=3D 8 ? op_bytes : 4; - } - else - { - case SrcImmByte: - bytes =3D 1; - } - /* NB. Immediates are sign-extended as necessary. */ - switch ( bytes ) - { - case 1: imm1 =3D insn_fetch_type(int8_t); break; - case 2: imm1 =3D insn_fetch_type(int16_t); break; - case 4: imm1 =3D insn_fetch_type(int32_t); break; - } - break; - case SrcImm16: - imm1 =3D insn_fetch_type(uint16_t); - break; - } - - ctxt->opcode =3D opcode; - state->desc =3D d; - - switch ( ext ) - { - case ext_none: - rc =3D x86_decode_onebyte(state, ctxt, ops); - break; - - case ext_0f: - rc =3D x86_decode_twobyte(state, ctxt, ops); - break; - - case ext_0f38: - rc =3D x86_decode_0f38(state, ctxt, ops); - break; - - case ext_0f3a: - d =3D ext0f3a_table[b].to_mem ? DstMem | SrcReg : DstReg | SrcMem; - if ( ext0f3a_table[b].two_op ) - d |=3D TwoOp; - else if ( ext0f3a_table[b].four_op && !mode_64bit() && vex.opcx ) - imm1 &=3D 0x7f; - state->desc =3D d; - rc =3D x86_decode_0f3a(state, ctxt, ops); - break; - - case ext_8f08: - d =3D DstReg | SrcMem; - if ( ext8f08_table[b].two_op ) - d |=3D TwoOp; - else if ( ext8f08_table[b].four_op && !mode_64bit() ) - imm1 &=3D 0x7f; - state->desc =3D d; - state->simd_size =3D ext8f08_table[b].simd_size; - break; - - case ext_8f09: - case ext_8f0a: - break; - - default: - ASSERT_UNREACHABLE(); - return X86EMUL_UNIMPLEMENTED; - } - - if ( ea.type =3D=3D OP_MEM ) - { - if ( pc_rel ) - ea.mem.off +=3D state->ip; - - ea.mem.off =3D truncate_ea(ea.mem.off); - } - - /* - * Simple op_bytes calculations. More complicated cases produce 0 - * and are further handled during execute. - */ - switch ( state->simd_size ) - { - case simd_none: - /* - * When prefix 66 has a meaning different from operand-size overri= de, - * operand size defaults to 4 and can't be overridden to 2. - */ - if ( op_bytes =3D=3D 2 && - (ctxt->opcode & X86EMUL_OPC_PFX_MASK) =3D=3D X86EMUL_OPC_66(0= , 0) ) - op_bytes =3D 4; - break; - -#ifndef X86EMUL_NO_SIMD - case simd_packed_int: - switch ( vex.pfx ) - { - case vex_none: - if ( !vex.opcx ) - { - op_bytes =3D 8; - break; - } - /* fall through */ - case vex_66: - op_bytes =3D 16 << evex.lr; - break; - default: - op_bytes =3D 0; - break; - } - break; - - case simd_single_fp: - if ( vex.pfx & VEX_PREFIX_DOUBLE_MASK ) - { - op_bytes =3D 0; - break; - case simd_packed_fp: - if ( vex.pfx & VEX_PREFIX_SCALAR_MASK ) - { - op_bytes =3D 0; - break; - } - } - /* fall through */ - case simd_any_fp: - switch ( vex.pfx ) - { - default: - op_bytes =3D 16 << evex.lr; - break; - case vex_f3: - generate_exception_if(evex_encoded() && evex.w, EXC_UD); - op_bytes =3D 4; - break; - case vex_f2: - generate_exception_if(evex_encoded() && !evex.w, EXC_UD); - op_bytes =3D 8; - break; - } - break; - - case simd_scalar_opc: - op_bytes =3D 4 << (ctxt->opcode & 1); - break; - - case simd_scalar_vexw: - op_bytes =3D 4 << vex.w; - break; - - case simd_128: - /* The special cases here are MMX shift insns. */ - op_bytes =3D vex.opcx || vex.pfx ? 16 : 8; - break; - - case simd_256: - op_bytes =3D 32; - break; -#endif /* !X86EMUL_NO_SIMD */ - - default: - op_bytes =3D 0; - break; - } - - done: - return rc; -} - -/* No insn fetching past this point. */ -#undef insn_fetch_bytes -#undef insn_fetch_type - /* Undo DEBUG wrapper. */ #undef x86_emulate =20 @@ -3000,7 +1281,7 @@ x86_emulate( (_regs.eflags & X86_EFLAGS_VIP)), EXC_GP, 0); =20 - rc =3D x86_decode(&state, ctxt, ops); + rc =3D x86emul_decode(&state, ctxt, ops); if ( rc !=3D X86EMUL_OKAY ) return rc; =20 @@ -10497,46 +8778,6 @@ int x86_emulate_wrapper( } #endif =20 -struct x86_emulate_state * -x86_decode_insn( - struct x86_emulate_ctxt *ctxt, - int (*insn_fetch)( - enum x86_segment seg, unsigned long offset, - void *p_data, unsigned int bytes, - struct x86_emulate_ctxt *ctxt)) -{ - static DEFINE_PER_CPU(struct x86_emulate_state, state); - struct x86_emulate_state *state =3D &this_cpu(state); - const struct x86_emulate_ops ops =3D { - .insn_fetch =3D insn_fetch, - .read =3D x86emul_unhandleable_rw, - }; - int rc; - - init_context(ctxt); - - rc =3D x86_decode(state, ctxt, &ops); - if ( unlikely(rc !=3D X86EMUL_OKAY) ) - return ERR_PTR(-rc); - -#if defined(__XEN__) && !defined(NDEBUG) - /* - * While we avoid memory allocation (by use of per-CPU data) above, - * nevertheless make sure callers properly release the state structure - * for forward compatibility. - */ - if ( state->caller ) - { - printk(XENLOG_ERR "Unreleased emulation state acquired by %ps\n", - state->caller); - dump_execution_state(); - } - state->caller =3D __builtin_return_address(0); -#endif - - return state; -} - static inline void check_state(const struct x86_emulate_state *state) { #if defined(__XEN__) && !defined(NDEBUG) From nobody Thu May 2 08:52:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; arc=pass (i=1 dmarc=pass fromdomain=suse.com); dmarc=pass(p=quarantine dis=none) header.from=suse.com ARC-Seal: i=2; a=rsa-sha256; t=1628684730; cv=pass; d=zohomail.com; s=zohoarc; b=L4KzYfXSCs9YD2WKO7J2d6ZrGanewLVmyTK1OL/vx42Kb8p5WAfiGodrl6bpfj+rgPNz5S6B9qtyFTzaDGnGrUoVwlEA11dA63+DJP68h/HbpA2p+JfCVO9wGcPitIbgRZfhFaqphnDbV7jFundap+B0FAnUZETlv9SPk3DiUTY= ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1628684730; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=xDuVUu/uls/nwQdBKf78ux7Pqg+0gXhI7uyUIB57IBM=; b=HBhwlS9wfNTQsutWe3BB7kHriGCHqUWaIZvqu4+EpBpGLw1jWcvjkfyTyJ4t3YqCSIaQYknC5b/sCrfcEBlzXzj4A5oW+p1/nSkpRWOQ9zflSxRroBrLIoamp7YOMNUAuclgXu6kRDt/EUjFwHrxnHrGh4QuU69TBDGfElxPzNA= ARC-Authentication-Results: i=2; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; arc=pass (i=1 dmarc=pass fromdomain=suse.com); dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 16286847306451.962918380782071; Wed, 11 Aug 2021 05:25:30 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.166003.303184 (Exim 4.92) (envelope-from ) id 1mDnIF-0000Rc-FT; Wed, 11 Aug 2021 12:25:11 +0000 Received: by outflank-mailman (output) from mailman id 166003.303184; Wed, 11 Aug 2021 12:25:11 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1mDnIF-0000RP-CF; Wed, 11 Aug 2021 12:25:11 +0000 Received: by outflank-mailman (input) for mailman id 166003; Wed, 11 Aug 2021 12:25:09 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1mDnID-0000QW-Hn for xen-devel@lists.xenproject.org; Wed, 11 Aug 2021 12:25:09 +0000 Received: from de-smtp-delivery-102.mimecast.com (unknown [194.104.111.102]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id 2921fac4-fa9f-11eb-a06e-12813bfff9fa; Wed, 11 Aug 2021 12:25:07 +0000 (UTC) Received: from EUR05-AM6-obe.outbound.protection.outlook.com (mail-am6eur05lp2111.outbound.protection.outlook.com [104.47.18.111]) (Using TLS) by relay.mimecast.com with ESMTP id de-mta-14-zpVizQREPeWltKaVkRMfXA-1; Wed, 11 Aug 2021 14:25:04 +0200 Received: from VI1PR04MB5600.eurprd04.prod.outlook.com (2603:10a6:803:e7::16) by VI1PR0401MB2335.eurprd04.prod.outlook.com (2603:10a6:800:2e::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4394.17; Wed, 11 Aug 2021 12:25:02 +0000 Received: from VI1PR04MB5600.eurprd04.prod.outlook.com ([fe80::99d3:99cd:8adf:3eea]) by VI1PR04MB5600.eurprd04.prod.outlook.com ([fe80::99d3:99cd:8adf:3eea%5]) with mapi id 15.20.4394.025; Wed, 11 Aug 2021 12:25:02 +0000 Received: from [10.156.60.236] (37.24.206.209) by FR3P281CA0059.DEUP281.PROD.OUTLOOK.COM (2603:10a6:d10:4b::21) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4415.6 via Frontend Transport; Wed, 11 Aug 2021 12:25:02 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 2921fac4-fa9f-11eb-a06e-12813bfff9fa DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=mimecast20200619; t=1628684706; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=xDuVUu/uls/nwQdBKf78ux7Pqg+0gXhI7uyUIB57IBM=; b=baHp8KtcoL5criQGzmZ/BFFBPjEq47d1X9jSKaZYAzHMrfEggCMTJQo6n802a9qmmC+irL 1CafCTXbVl1aSt7b1sQs+1e+dvS7LKjExcsfhf22iXAi0Fwm4FLs+KTt4slP7lvSRbcv1R fgV1V4ikg06+bmrcACL04uHBpLRqFgg= X-MC-Unique: zpVizQREPeWltKaVkRMfXA-1 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=EDisUcvY6+co7ZQkKCv2oJmGoFo0SAVg7Nra4wBW7+n8KAaBH5GiEpxWY+TFznVKTJX/p+5bw7FrYrMKO9OQqd4yv+x9r803kl+gG9w6PoHv7EeM+kLik6bUe6zJPCSvTygbGAG2sUGDsJGSqhmCHQsGrb7hePEQMhLLQKZ7aEQOqxmeZqw7bxA5H0Uoir9sOuHg7OLVWq7EXjSJlE05+vzBzVyi7MhxKmBpQNsvITcE/wN7e2xQwnM9FyP+KpnXlDVtsw46TGeDOFXJ0BGGId9fVDFuJGa3YylW7yJYvCqm/EKhzGoAuedDvkFgHAEuQ/54DWpDMfIGBaORGOIHxw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=xDuVUu/uls/nwQdBKf78ux7Pqg+0gXhI7uyUIB57IBM=; b=cA1gYBXob8J0jN9/u4qS4C+Gdvo6jF3v9feSp6J9oWpibEL6n97EmXaUdqai4FSe/xsokyIzMjRqVedt3IfBzYcr5bSA5ZGarjAhRtwMHJ4sAx4VRNvb1YCsjULcDkRCo2qF1UV36hJPZbebYPbccEQU4tj4U9cOK2adDYFIVNfnruJNOWHBQO8gdxh5k/imWfgx0NHsg4cCMj0QYcsSha6oWu5eQCJhEDAo1GMlRl9dT/cbD+JzV5J9stHZG6UDQBKnOLgNVPDDW4xajJM1rZ7JDgNBcS4L1gB72jIM40FQ21/lh/fBhvz0Y1RvPOlxqx2RX7ihGQeK5nWi2AFM4g== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=suse.com; dmarc=pass action=none header.from=suse.com; dkim=pass header.d=suse.com; arc=none Authentication-Results: citrix.com; dkim=none (message not signed) header.d=none;citrix.com; dmarc=none action=none header.from=suse.com; Subject: [PATCH 6/7] x86emul: move x86_emul_blk() to separate source file From: Jan Beulich To: "xen-devel@lists.xenproject.org" Cc: Andrew Cooper , Wei Liu , =?UTF-8?Q?Roger_Pau_Monn=c3=a9?= References: Message-ID: <03a230d9-d4f5-d3fe-738a-2208a8d56f05@suse.com> Date: Wed, 11 Aug 2021 14:25:01 +0200 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Thunderbird/78.12.0 In-Reply-To: Content-Language: en-US Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: FR3P281CA0059.DEUP281.PROD.OUTLOOK.COM (2603:10a6:d10:4b::21) To VI1PR04MB5600.eurprd04.prod.outlook.com (2603:10a6:803:e7::16) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 4e06b252-5fec-4704-4d62-08d95cc30b3a X-MS-TrafficTypeDiagnostic: VI1PR0401MB2335: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:3826; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: cGSChJVp1DMizIep/ej/xdHg0FdBdVsP1Y9lGAvOxFRjsCr+kp0uMk5V58QZIhprXBY5nBU81N3tWKQ0fALa+oV/PNuq79/NW3MBhBPQWwSCFD+pm1si5GILkJEyc4VYZOo4gV+8hCfYVC3l+TeAfVuQyCm/t8/z97uM6m28f8N7sOmeauhfD58R2aYwSceuWplNGnUDl21my4pVwR8xbR8++7zbTnLqeZ5VmTdbBr2ru73FSIGwk9s3dD1UVJFYepd8r8AzmGSTJeNT0I6X12O2ZCjalIsH8ddRA9HbnvUC/CE/PuF610+1OHST4/3/a0uV2vwcT10uB9M1GlwrAKHZefHxkcpMR3LF76goKivCP8G+sRpHveciWgUS6/OvGsh32EQB+mpAspQXWnyqsqZLGcDJhsmHb5IsssJJwnBjgWtAzY/2xlwP2DuTZgV+wMnytm4+IIZSXcvqPKGlQF+Nacjq6zbYWmPa5EDtzm3r/ECm7eKL7Q5V+jq6vcjC+q98Q1H8XYwL9SySV8N6bYDKTuhQsbdBmYgxDF9ebizPnLho8m/cAmPNHfKBG35AhoNeF9eTcalxEqdthr3Ii9mbtYORRaR6vBJOgPymrcxJ77L2ZxjeoAou546hjHnHJpw0zXBYBkF83o+mcNTuHjHUz99OLfXV8gA4j8mfpmU+cRzQipnKcftkSUO0uIiSXP/bGeeej82fVQi6WYTrHhxIm8W8KHJiaI7f/cpTRZDkG0Pes36163vClgCg3KxD1RIJQ/rE4xPJS2TD5TmgF3aW9yHR1vxtQomeC4mESoxMQ0Q3Axp4ar/l6zjvwWr/z4mxExBAmV30NmuON3JAKw== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:VI1PR04MB5600.eurprd04.prod.outlook.com;PTR:;CAT:NONE;SFS:(136003)(396003)(39860400002)(366004)(346002)(376002)(6916009)(31696002)(316002)(956004)(6486002)(2906002)(36756003)(478600001)(30864003)(86362001)(16576012)(8676002)(31686004)(8936002)(38100700002)(2616005)(66556008)(83380400001)(186003)(66476007)(66946007)(5660300002)(26005)(54906003)(4326008)(2004002)(45980500001)(43740500002);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?d0xRQmFRZGRQaEdNQVhUWmdYUFNyS0RoZlMxZk5ZSFBEN3QvLzJ1djZ6bEVP?= =?utf-8?B?SEdoTEVncGJab0hpVXo1SnlMV0RDMWFiN2pncFlHeVoxMjJlTmw2Q1RsYkVM?= =?utf-8?B?TmFqd1c4R28yUnMrVWFSUEd1VmlwbDE0ZXh6MTM0U3g5ak95aXV4Zk9iZ3lJ?= =?utf-8?B?ZEsvWDNBajRRK0wvemNuc0NmcmkrVkhTWlFzTHRJYXBBTzdFLzUyMlBRVS9m?= =?utf-8?B?TFh0dnJnQUt2SHRIaXV1aFY5amRUSWtHdFFmZFpFRHZKMXlHbHR4WmUzWk80?= =?utf-8?B?WTNBTUZRQUJRYTBGbXJacTdSTkxjamU3dDJIQVlieHViczJIV3phZUZYU3dk?= =?utf-8?B?eS9saUVXcEZhS2lmdjB5MTNqQUxrRTQrYTJHcDVDRWlua0xOajhIb3ZhQnNZ?= =?utf-8?B?Nkc0amkrd2xBL3RxL0VENFIwV2hweTFSVExIUk5FU3FmRmplZkRwazd2UEJv?= =?utf-8?B?VlVvVThtUkFra1hGM0RPcDZMQmZOZmNFMDQ1RE45M0JEeW1JMEFkaTdPVTNw?= =?utf-8?B?NFpuQjlRd2tXdG5FR1hLZm5EeUlIL01GNDlWZmtxVHNXR29zejRLZ1BXTnA3?= =?utf-8?B?ZEw1ZWFxbXBPM2V1d01LeU5YckY0anJ0Mk9iTDBLaGd0dWk3ZGhCcjFCZTdP?= =?utf-8?B?Y3VnbHZYNlFHaE5EZmp2NiszcklyNzB1ZUI2bEdJK0dFQzNpa0tCNi9kUVha?= =?utf-8?B?ZE5SRWdCMnBpV0lwS2lqaEJCRysrUWhZc3FJZm02UmF0NmpDTWhzeVpGTjVC?= =?utf-8?B?TkhuaU5pYnl4c3RPQnU1WHdWa2piZXZObFU1SEtxM0w3dG5qbjYreXB4MHVH?= =?utf-8?B?U244QW1LYyttN3ZvNmtwWG4wY2lZNUR5ajQ4NXZaQzFKZmczVTdtMURBNHlI?= =?utf-8?B?UHpaekJnVUt6TlBQSnYvS1crODV1aXlTbnBwVHlNS0lBQkFuWlNmU0J5bFZm?= =?utf-8?B?UjVmZ0REYXA1d2djYkFXaE9TUXVsdEtldUtwZytnSjAxUjd4Qi95NnBGd21n?= =?utf-8?B?WVJJWWJwWFF5V0pEajFaa3Q5cXJ3Y21jZ01OdGJjL3JoR2o3Z0w3RVJBS0RB?= =?utf-8?B?YWFjZUROb1BCUDIrR1lDTFA3U3Nvb0lBaCsyS3ViM2FleGdiTW5XeVhtRDNM?= =?utf-8?B?bzBLRFoycHVNbThPdnNOcHZTUklGTUI0Y0ZlZXU5WXRhRXRrcEtIYkVoZlBP?= =?utf-8?B?c2FWamczYXhnL3MzSFZBTDUxR1JsNTFWWUxvNXY5ZGQreUIraGIxVWZ3YmdV?= =?utf-8?B?M21RTm81SVd3b2tCb2crK1lVSnhKZytWTFg2bHZvSUp0SU5mNENjeGZFQWRy?= =?utf-8?B?MVJCK3lOcmNsckxZdDFkd3dEMHFzRVB5aEpRN2p4aTJpSFN2SFQ3enlZTkdZ?= =?utf-8?B?QU92VTdDbUs3cEszSjhHK2lJTHZScmdQbmRoeE1sNDh2ZEZRYy9DSkZqOUN3?= =?utf-8?B?YVBuZWk5UVY3bGJ1aHdSdHRldVV3cW12N1FDSHNTVU5idjhKTURPNnB3S29N?= =?utf-8?B?RXNLdFY5aFMzVHh1NXZwWnVKclZOMmhzam42T1lyb3NCYjdXeDNHczcrOWhK?= =?utf-8?B?ZkZrUUJiYlJGTW5MOXlBWDZVU2MrUlEvc0JBeHVoUzdDdGRvUG1peCsyYmhO?= =?utf-8?B?M3dSYnlBQXhDRE9sUnVrbXpkNHZQeGY4dEgvL2NFOEZOcTltb1NNaGJYMEVR?= =?utf-8?B?ZE5YWGduaWl3d2lNYVRxbDlwN2RYOU5XZmRtVzRUWVRrYmdGRFd5VE1icnJI?= =?utf-8?Q?KQWXlDvMUDy/AqKRgiSDeQ+REJydOUwoZ+yDEDb?= X-OriginatorOrg: suse.com X-MS-Exchange-CrossTenant-Network-Message-Id: 4e06b252-5fec-4704-4d62-08d95cc30b3a X-MS-Exchange-CrossTenant-AuthSource: VI1PR04MB5600.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 11 Aug 2021 12:25:02.7553 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: f7a17af6-1c5c-4a36-aa8b-f5be247aa4ba X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: IruX2bTsLOHGc8BUadRGOcrLU2CR15E5J/kzrhhg+qqhuXqQZNui5LRsTxgX2aa2DedmgwGPenEmUS6cKcYwDQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR0401MB2335 X-ZohoMail-DKIM: pass (identity @suse.com) X-ZM-MESSAGEID: 1628684731655100005 Content-Type: text/plain; charset="utf-8" The function is already non-trivial and is expected to further grow. Code moved gets slightly adjusted in a few places, e.g. replacing EXC_* by X86_EXC_* (such that EXC_* don't need to move as well; we want these to be phased out anyway). Signed-off-by: Jan Beulich --- a/tools/tests/x86_emulator/Makefile +++ b/tools/tests/x86_emulator/Makefile @@ -252,7 +252,7 @@ endif # 32-bit override =20 OBJS :=3D x86-emulate.o cpuid.o test_x86_emulator.o evex-disp8.o predicate= s.o wrappers.o OBJS +=3D x86_emulate/0f01.o x86_emulate/0fae.o x86_emulate/0fc7.o -OBJS +=3D x86_emulate/decode.o x86_emulate/fpu.o +OBJS +=3D x86_emulate/blk.o x86_emulate/decode.o x86_emulate/fpu.o =20 $(TARGET): $(OBJS) $(HOSTCC) $(HOSTCFLAGS) -o $@ $^ --- a/tools/tests/x86_emulator/x86-emulate.c +++ b/tools/tests/x86_emulator/x86-emulate.c @@ -35,7 +35,10 @@ static bool use_xsave; * (When debugging the emulator, care needs to be taken when inserting * printf() or alike function calls into regions using this.) */ -#define FXSAVE_AREA ((struct x86_fxsr *)fpu_save_area) +struct x86_fxsr *get_fpu_save_area(void) +{ + return (void *)fpu_save_area; +} =20 void emul_save_fpu_state(void) { --- a/tools/tests/x86_emulator/x86-emulate.h +++ b/tools/tests/x86_emulator/x86-emulate.h @@ -83,6 +83,8 @@ bool emul_test_init(void); void emul_save_fpu_state(void); void emul_restore_fpu_state(void); =20 +struct x86_fxsr *get_fpu_save_area(void); + /* * In order to reasonably use the above, wrap library calls we use and whi= ch we * think might access any of the FPU state into wrappers saving/restoring = state --- a/xen/arch/x86/x86_emulate.c +++ b/xen/arch/x86/x86_emulate.c @@ -24,8 +24,6 @@ #define cpu_has_amd_erratum(nr) \ cpu_has_amd_erratum(¤t_cpu_data, AMD_ERRATUM_##nr) =20 -#define FXSAVE_AREA current->arch.fpu_ctxt - #include "x86_emulate/x86_emulate.c" =20 int x86emul_read_xcr(unsigned int reg, uint64_t *val, --- a/xen/arch/x86/x86_emulate/Makefile +++ b/xen/arch/x86/x86_emulate/Makefile @@ -1,5 +1,6 @@ obj-y +=3D 0f01.o obj-y +=3D 0fae.o obj-y +=3D 0fc7.o +obj-y +=3D blk.o obj-y +=3D decode.o obj-$(CONFIG_HVM) +=3D fpu.o --- /dev/null +++ b/xen/arch/x86/x86_emulate/blk.c @@ -0,0 +1,396 @@ +/*************************************************************************= ***** + * blk.c - helper for x86_emulate.c + * + * Generic x86 (32-bit and 64-bit) instruction decoder and emulator. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; If not, see . + */ + +#include "private.h" + +#if !defined(X86EMUL_NO_FPU) || !defined(X86EMUL_NO_MMX) || \ + !defined(X86EMUL_NO_SIMD) +# ifdef __XEN__ +# include +# define FXSAVE_AREA current->arch.fpu_ctxt +# else +# define FXSAVE_AREA get_fpu_save_area() +# endif +#endif + +int x86_emul_blk( + void *ptr, + void *data, + unsigned int bytes, + uint32_t *eflags, + struct x86_emulate_state *s, + struct x86_emulate_ctxt *ctxt) +{ + int rc =3D X86EMUL_OKAY; + + switch ( s->blk ) + { + bool zf; +#ifndef X86EMUL_NO_FPU + struct { + struct x87_env32 env; + struct { + uint8_t bytes[10]; + } freg[8]; + } fpstate; +#endif + + /* + * Throughout this switch(), memory clobbers are used to compensate + * that other operands may not properly express the (full) memory + * ranges covered. + */ + case blk_enqcmd: + ASSERT(bytes =3D=3D 64); + if ( ((unsigned long)ptr & 0x3f) ) + { + ASSERT_UNREACHABLE(); + return X86EMUL_UNHANDLEABLE; + } + *eflags &=3D ~EFLAGS_MASK; +#ifdef HAVE_AS_ENQCMD + asm ( "enqcmds (%[src]), %[dst]" ASM_FLAG_OUT(, "; setz %[zf]") + : [zf] ASM_FLAG_OUT("=3D@ccz", "=3Dqm") (zf) + : [src] "r" (data), [dst] "r" (ptr) : "memory" ); +#else + /* enqcmds (%rsi), %rdi */ + asm ( ".byte 0xf3, 0x0f, 0x38, 0xf8, 0x3e" + ASM_FLAG_OUT(, "; setz %[zf]") + : [zf] ASM_FLAG_OUT("=3D@ccz", "=3Dqm") (zf) + : "S" (data), "D" (ptr) : "memory" ); +#endif + if ( zf ) + *eflags |=3D X86_EFLAGS_ZF; + break; + +#ifndef X86EMUL_NO_FPU + + case blk_fld: + ASSERT(!data); + + /* s->rex_prefix carries CR0.PE && !EFLAGS.VM setting */ + switch ( bytes ) + { + case sizeof(fpstate.env): /* 32-bit FLDENV */ + case sizeof(fpstate): /* 32-bit FRSTOR */ + memcpy(&fpstate.env, ptr, sizeof(fpstate.env)); + if ( !s->rex_prefix ) + { + /* Convert 32-bit real/vm86 to 32-bit prot format. */ + unsigned int fip =3D fpstate.env.mode.real.fip_lo + + (fpstate.env.mode.real.fip_hi << 16); + unsigned int fdp =3D fpstate.env.mode.real.fdp_lo + + (fpstate.env.mode.real.fdp_hi << 16); + unsigned int fop =3D fpstate.env.mode.real.fop; + + fpstate.env.mode.prot.fip =3D fip & 0xf; + fpstate.env.mode.prot.fcs =3D fip >> 4; + fpstate.env.mode.prot.fop =3D fop; + fpstate.env.mode.prot.fdp =3D fdp & 0xf; + fpstate.env.mode.prot.fds =3D fdp >> 4; + } + + if ( bytes =3D=3D sizeof(fpstate.env) ) + ptr =3D NULL; + else + ptr +=3D sizeof(fpstate.env); + break; + + case sizeof(struct x87_env16): /* 16-bit FL= DENV */ + case sizeof(struct x87_env16) + sizeof(fpstate.freg): /* 16-bit FR= STOR */ + { + const struct x87_env16 *env =3D ptr; + + fpstate.env.fcw =3D env->fcw; + fpstate.env.fsw =3D env->fsw; + fpstate.env.ftw =3D env->ftw; + + if ( s->rex_prefix ) + { + /* Convert 16-bit prot to 32-bit prot format. */ + fpstate.env.mode.prot.fip =3D env->mode.prot.fip; + fpstate.env.mode.prot.fcs =3D env->mode.prot.fcs; + fpstate.env.mode.prot.fdp =3D env->mode.prot.fdp; + fpstate.env.mode.prot.fds =3D env->mode.prot.fds; + fpstate.env.mode.prot.fop =3D 0; /* unknown */ + } + else + { + /* Convert 16-bit real/vm86 to 32-bit prot format. */ + unsigned int fip =3D env->mode.real.fip_lo + + (env->mode.real.fip_hi << 16); + unsigned int fdp =3D env->mode.real.fdp_lo + + (env->mode.real.fdp_hi << 16); + unsigned int fop =3D env->mode.real.fop; + + fpstate.env.mode.prot.fip =3D fip & 0xf; + fpstate.env.mode.prot.fcs =3D fip >> 4; + fpstate.env.mode.prot.fop =3D fop; + fpstate.env.mode.prot.fdp =3D fdp & 0xf; + fpstate.env.mode.prot.fds =3D fdp >> 4; + } + + if ( bytes =3D=3D sizeof(*env) ) + ptr =3D NULL; + else + ptr +=3D sizeof(*env); + break; + } + + default: + ASSERT_UNREACHABLE(); + return X86EMUL_UNHANDLEABLE; + } + + if ( ptr ) + { + memcpy(fpstate.freg, ptr, sizeof(fpstate.freg)); + asm volatile ( "frstor %0" :: "m" (fpstate) ); + } + else + asm volatile ( "fldenv %0" :: "m" (fpstate.env) ); + break; + + case blk_fst: + ASSERT(!data); + + /* Don't chance consuming uninitialized data. */ + memset(&fpstate, 0, sizeof(fpstate)); + if ( bytes > sizeof(fpstate.env) ) + asm ( "fnsave %0" : "+m" (fpstate) ); + else + asm ( "fnstenv %0" : "+m" (fpstate.env) ); + + /* s->rex_prefix carries CR0.PE && !EFLAGS.VM setting */ + switch ( bytes ) + { + case sizeof(fpstate.env): /* 32-bit FNSTENV */ + case sizeof(fpstate): /* 32-bit FNSAVE */ + if ( !s->rex_prefix ) + { + /* Convert 32-bit prot to 32-bit real/vm86 format. */ + unsigned int fip =3D fpstate.env.mode.prot.fip + + (fpstate.env.mode.prot.fcs << 4); + unsigned int fdp =3D fpstate.env.mode.prot.fdp + + (fpstate.env.mode.prot.fds << 4); + unsigned int fop =3D fpstate.env.mode.prot.fop; + + memset(&fpstate.env.mode, 0, sizeof(fpstate.env.mode)); + fpstate.env.mode.real.fip_lo =3D fip; + fpstate.env.mode.real.fip_hi =3D fip >> 16; + fpstate.env.mode.real.fop =3D fop; + fpstate.env.mode.real.fdp_lo =3D fdp; + fpstate.env.mode.real.fdp_hi =3D fdp >> 16; + } + memcpy(ptr, &fpstate.env, sizeof(fpstate.env)); + if ( bytes =3D=3D sizeof(fpstate.env) ) + ptr =3D NULL; + else + ptr +=3D sizeof(fpstate.env); + break; + + case sizeof(struct x87_env16): /* 16-bit FN= STENV */ + case sizeof(struct x87_env16) + sizeof(fpstate.freg): /* 16-bit FN= SAVE */ + if ( s->rex_prefix ) + { + /* Convert 32-bit prot to 16-bit prot format. */ + struct x87_env16 *env =3D ptr; + + env->fcw =3D fpstate.env.fcw; + env->fsw =3D fpstate.env.fsw; + env->ftw =3D fpstate.env.ftw; + env->mode.prot.fip =3D fpstate.env.mode.prot.fip; + env->mode.prot.fcs =3D fpstate.env.mode.prot.fcs; + env->mode.prot.fdp =3D fpstate.env.mode.prot.fdp; + env->mode.prot.fds =3D fpstate.env.mode.prot.fds; + } + else + { + /* Convert 32-bit prot to 16-bit real/vm86 format. */ + unsigned int fip =3D fpstate.env.mode.prot.fip + + (fpstate.env.mode.prot.fcs << 4); + unsigned int fdp =3D fpstate.env.mode.prot.fdp + + (fpstate.env.mode.prot.fds << 4); + struct x87_env16 env =3D { + .fcw =3D fpstate.env.fcw, + .fsw =3D fpstate.env.fsw, + .ftw =3D fpstate.env.ftw, + .mode.real.fip_lo =3D fip, + .mode.real.fip_hi =3D fip >> 16, + .mode.real.fop =3D fpstate.env.mode.prot.fop, + .mode.real.fdp_lo =3D fdp, + .mode.real.fdp_hi =3D fdp >> 16 + }; + + memcpy(ptr, &env, sizeof(env)); + } + if ( bytes =3D=3D sizeof(struct x87_env16) ) + ptr =3D NULL; + else + ptr +=3D sizeof(struct x87_env16); + break; + + default: + ASSERT_UNREACHABLE(); + return X86EMUL_UNHANDLEABLE; + } + + if ( ptr ) + memcpy(ptr, fpstate.freg, sizeof(fpstate.freg)); + break; + +#endif /* X86EMUL_NO_FPU */ + +#if !defined(X86EMUL_NO_FPU) || !defined(X86EMUL_NO_MMX) || \ + !defined(X86EMUL_NO_SIMD) + + case blk_fxrstor: + { + struct x86_fxsr *fxsr =3D FXSAVE_AREA; + + ASSERT(!data); + ASSERT(bytes =3D=3D sizeof(*fxsr)); + ASSERT(s->op_bytes <=3D bytes); + + if ( s->op_bytes < sizeof(*fxsr) ) + { + if ( s->rex_prefix & REX_W ) + { + /* + * The only way to force fxsaveq on a wide range of gas + * versions. On older versions the rex64 prefix works only= if + * we force an addressing mode that doesn't require extend= ed + * registers. + */ + asm volatile ( ".byte 0x48; fxsave (%1)" + : "=3Dm" (*fxsr) : "R" (fxsr) ); + } + else + asm volatile ( "fxsave %0" : "=3Dm" (*fxsr) ); + } + + /* + * Don't chance the reserved or available ranges to contain any + * data FXRSTOR may actually consume in some way: Copy only the + * defined portion, and zero the rest. + */ + memcpy(fxsr, ptr, min(s->op_bytes, + (unsigned int)offsetof(struct x86_fxsr, rsvd= ))); + memset(fxsr->rsvd, 0, sizeof(*fxsr) - offsetof(struct x86_fxsr, rs= vd)); + + generate_exception_if(fxsr->mxcsr & ~mxcsr_mask, X86_EXC_GP, 0); + + if ( s->rex_prefix & REX_W ) + { + /* See above for why operand/constraints are this way. */ + asm volatile ( ".byte 0x48; fxrstor (%1)" + :: "m" (*fxsr), "R" (fxsr) ); + } + else + asm volatile ( "fxrstor %0" :: "m" (*fxsr) ); + break; + } + + case blk_fxsave: + { + struct x86_fxsr *fxsr =3D FXSAVE_AREA; + + ASSERT(!data); + ASSERT(bytes =3D=3D sizeof(*fxsr)); + ASSERT(s->op_bytes <=3D bytes); + + if ( s->op_bytes < sizeof(*fxsr) ) + /* Don't chance consuming uninitialized data. */ + memset(fxsr, 0, s->op_bytes); + else + fxsr =3D ptr; + + if ( s->rex_prefix & REX_W ) + { + /* See above for why operand/constraints are this way. */ + asm volatile ( ".byte 0x48; fxsave (%1)" + : "=3Dm" (*fxsr) : "R" (fxsr) ); + } + else + asm volatile ( "fxsave %0" : "=3Dm" (*fxsr) ); + + if ( fxsr !=3D ptr ) /* i.e. s->op_bytes < sizeof(*fxsr) */ + memcpy(ptr, fxsr, s->op_bytes); + break; + } + +#endif /* X86EMUL_NO_{FPU,MMX,SIMD} */ + + case blk_movdir: + switch ( bytes ) + { +#ifdef __x86_64__ + case sizeof(uint32_t): +# ifdef HAVE_AS_MOVDIR + asm ( "movdiri %0, (%1)" + :: "r" (*(uint32_t *)data), "r" (ptr) : "memory" ); +# else + /* movdiri %esi, (%rdi) */ + asm ( ".byte 0x0f, 0x38, 0xf9, 0x37" + :: "S" (*(uint32_t *)data), "D" (ptr) : "memory" ); +# endif + break; +#endif + + case sizeof(unsigned long): +#ifdef HAVE_AS_MOVDIR + asm ( "movdiri %0, (%1)" + :: "r" (*(unsigned long *)data), "r" (ptr) : "memory" ); +#else + /* movdiri %rsi, (%rdi) */ + asm ( ".byte 0x48, 0x0f, 0x38, 0xf9, 0x37" + :: "S" (*(unsigned long *)data), "D" (ptr) : "memory" ); +#endif + break; + + case 64: + if ( ((unsigned long)ptr & 0x3f) ) + { + ASSERT_UNREACHABLE(); + return X86EMUL_UNHANDLEABLE; + } +#ifdef HAVE_AS_MOVDIR + asm ( "movdir64b (%0), %1" :: "r" (data), "r" (ptr) : "memory"= ); +#else + /* movdir64b (%rsi), %rdi */ + asm ( ".byte 0x66, 0x0f, 0x38, 0xf8, 0x3e" + :: "S" (data), "D" (ptr) : "memory" ); +#endif + break; + + default: + ASSERT_UNREACHABLE(); + return X86EMUL_UNHANDLEABLE; + } + break; + + default: + ASSERT_UNREACHABLE(); + return X86EMUL_UNHANDLEABLE; + } + + done: __maybe_unused; + return rc; + +} --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -8342,371 +8342,6 @@ int x86_emul_rmw( return X86EMUL_OKAY; } =20 -int x86_emul_blk( - void *ptr, - void *data, - unsigned int bytes, - uint32_t *eflags, - struct x86_emulate_state *state, - struct x86_emulate_ctxt *ctxt) -{ - int rc =3D X86EMUL_OKAY; - - switch ( state->blk ) - { - bool zf; -#ifndef X86EMUL_NO_FPU - struct { - struct x87_env32 env; - struct { - uint8_t bytes[10]; - } freg[8]; - } fpstate; -#endif - - /* - * Throughout this switch(), memory clobbers are used to compensate - * that other operands may not properly express the (full) memory - * ranges covered. - */ - case blk_enqcmd: - ASSERT(bytes =3D=3D 64); - if ( ((unsigned long)ptr & 0x3f) ) - { - ASSERT_UNREACHABLE(); - return X86EMUL_UNHANDLEABLE; - } - *eflags &=3D ~EFLAGS_MASK; -#ifdef HAVE_AS_ENQCMD - asm ( "enqcmds (%[src]), %[dst]" ASM_FLAG_OUT(, "; setz %[zf]") - : [zf] ASM_FLAG_OUT("=3D@ccz", "=3Dqm") (zf) - : [src] "r" (data), [dst] "r" (ptr) : "memory" ); -#else - /* enqcmds (%rsi), %rdi */ - asm ( ".byte 0xf3, 0x0f, 0x38, 0xf8, 0x3e" - ASM_FLAG_OUT(, "; setz %[zf]") - : [zf] ASM_FLAG_OUT("=3D@ccz", "=3Dqm") (zf) - : "S" (data), "D" (ptr) : "memory" ); -#endif - if ( zf ) - *eflags |=3D X86_EFLAGS_ZF; - break; - -#ifndef X86EMUL_NO_FPU - - case blk_fld: - ASSERT(!data); - - /* state->rex_prefix carries CR0.PE && !EFLAGS.VM setting */ - switch ( bytes ) - { - case sizeof(fpstate.env): /* 32-bit FLDENV */ - case sizeof(fpstate): /* 32-bit FRSTOR */ - memcpy(&fpstate.env, ptr, sizeof(fpstate.env)); - if ( !state->rex_prefix ) - { - /* Convert 32-bit real/vm86 to 32-bit prot format. */ - unsigned int fip =3D fpstate.env.mode.real.fip_lo + - (fpstate.env.mode.real.fip_hi << 16); - unsigned int fdp =3D fpstate.env.mode.real.fdp_lo + - (fpstate.env.mode.real.fdp_hi << 16); - unsigned int fop =3D fpstate.env.mode.real.fop; - - fpstate.env.mode.prot.fip =3D fip & 0xf; - fpstate.env.mode.prot.fcs =3D fip >> 4; - fpstate.env.mode.prot.fop =3D fop; - fpstate.env.mode.prot.fdp =3D fdp & 0xf; - fpstate.env.mode.prot.fds =3D fdp >> 4; - } - - if ( bytes =3D=3D sizeof(fpstate.env) ) - ptr =3D NULL; - else - ptr +=3D sizeof(fpstate.env); - break; - - case sizeof(struct x87_env16): /* 16-bit FL= DENV */ - case sizeof(struct x87_env16) + sizeof(fpstate.freg): /* 16-bit FR= STOR */ - { - const struct x87_env16 *env =3D ptr; - - fpstate.env.fcw =3D env->fcw; - fpstate.env.fsw =3D env->fsw; - fpstate.env.ftw =3D env->ftw; - - if ( state->rex_prefix ) - { - /* Convert 16-bit prot to 32-bit prot format. */ - fpstate.env.mode.prot.fip =3D env->mode.prot.fip; - fpstate.env.mode.prot.fcs =3D env->mode.prot.fcs; - fpstate.env.mode.prot.fdp =3D env->mode.prot.fdp; - fpstate.env.mode.prot.fds =3D env->mode.prot.fds; - fpstate.env.mode.prot.fop =3D 0; /* unknown */ - } - else - { - /* Convert 16-bit real/vm86 to 32-bit prot format. */ - unsigned int fip =3D env->mode.real.fip_lo + - (env->mode.real.fip_hi << 16); - unsigned int fdp =3D env->mode.real.fdp_lo + - (env->mode.real.fdp_hi << 16); - unsigned int fop =3D env->mode.real.fop; - - fpstate.env.mode.prot.fip =3D fip & 0xf; - fpstate.env.mode.prot.fcs =3D fip >> 4; - fpstate.env.mode.prot.fop =3D fop; - fpstate.env.mode.prot.fdp =3D fdp & 0xf; - fpstate.env.mode.prot.fds =3D fdp >> 4; - } - - if ( bytes =3D=3D sizeof(*env) ) - ptr =3D NULL; - else - ptr +=3D sizeof(*env); - break; - } - - default: - ASSERT_UNREACHABLE(); - return X86EMUL_UNHANDLEABLE; - } - - if ( ptr ) - { - memcpy(fpstate.freg, ptr, sizeof(fpstate.freg)); - asm volatile ( "frstor %0" :: "m" (fpstate) ); - } - else - asm volatile ( "fldenv %0" :: "m" (fpstate.env) ); - break; - - case blk_fst: - ASSERT(!data); - - /* Don't chance consuming uninitialized data. */ - memset(&fpstate, 0, sizeof(fpstate)); - if ( bytes > sizeof(fpstate.env) ) - asm ( "fnsave %0" : "+m" (fpstate) ); - else - asm ( "fnstenv %0" : "+m" (fpstate.env) ); - - /* state->rex_prefix carries CR0.PE && !EFLAGS.VM setting */ - switch ( bytes ) - { - case sizeof(fpstate.env): /* 32-bit FNSTENV */ - case sizeof(fpstate): /* 32-bit FNSAVE */ - if ( !state->rex_prefix ) - { - /* Convert 32-bit prot to 32-bit real/vm86 format. */ - unsigned int fip =3D fpstate.env.mode.prot.fip + - (fpstate.env.mode.prot.fcs << 4); - unsigned int fdp =3D fpstate.env.mode.prot.fdp + - (fpstate.env.mode.prot.fds << 4); - unsigned int fop =3D fpstate.env.mode.prot.fop; - - memset(&fpstate.env.mode, 0, sizeof(fpstate.env.mode)); - fpstate.env.mode.real.fip_lo =3D fip; - fpstate.env.mode.real.fip_hi =3D fip >> 16; - fpstate.env.mode.real.fop =3D fop; - fpstate.env.mode.real.fdp_lo =3D fdp; - fpstate.env.mode.real.fdp_hi =3D fdp >> 16; - } - memcpy(ptr, &fpstate.env, sizeof(fpstate.env)); - if ( bytes =3D=3D sizeof(fpstate.env) ) - ptr =3D NULL; - else - ptr +=3D sizeof(fpstate.env); - break; - - case sizeof(struct x87_env16): /* 16-bit FN= STENV */ - case sizeof(struct x87_env16) + sizeof(fpstate.freg): /* 16-bit FN= SAVE */ - if ( state->rex_prefix ) - { - /* Convert 32-bit prot to 16-bit prot format. */ - struct x87_env16 *env =3D ptr; - - env->fcw =3D fpstate.env.fcw; - env->fsw =3D fpstate.env.fsw; - env->ftw =3D fpstate.env.ftw; - env->mode.prot.fip =3D fpstate.env.mode.prot.fip; - env->mode.prot.fcs =3D fpstate.env.mode.prot.fcs; - env->mode.prot.fdp =3D fpstate.env.mode.prot.fdp; - env->mode.prot.fds =3D fpstate.env.mode.prot.fds; - } - else - { - /* Convert 32-bit prot to 16-bit real/vm86 format. */ - unsigned int fip =3D fpstate.env.mode.prot.fip + - (fpstate.env.mode.prot.fcs << 4); - unsigned int fdp =3D fpstate.env.mode.prot.fdp + - (fpstate.env.mode.prot.fds << 4); - struct x87_env16 env =3D { - .fcw =3D fpstate.env.fcw, - .fsw =3D fpstate.env.fsw, - .ftw =3D fpstate.env.ftw, - .mode.real.fip_lo =3D fip, - .mode.real.fip_hi =3D fip >> 16, - .mode.real.fop =3D fpstate.env.mode.prot.fop, - .mode.real.fdp_lo =3D fdp, - .mode.real.fdp_hi =3D fdp >> 16 - }; - - memcpy(ptr, &env, sizeof(env)); - } - if ( bytes =3D=3D sizeof(struct x87_env16) ) - ptr =3D NULL; - else - ptr +=3D sizeof(struct x87_env16); - break; - - default: - ASSERT_UNREACHABLE(); - return X86EMUL_UNHANDLEABLE; - } - - if ( ptr ) - memcpy(ptr, fpstate.freg, sizeof(fpstate.freg)); - break; - -#endif /* X86EMUL_NO_FPU */ - -#if !defined(X86EMUL_NO_FPU) || !defined(X86EMUL_NO_MMX) || \ - !defined(X86EMUL_NO_SIMD) - - case blk_fxrstor: - { - struct x86_fxsr *fxsr =3D FXSAVE_AREA; - - ASSERT(!data); - ASSERT(bytes =3D=3D sizeof(*fxsr)); - ASSERT(state->op_bytes <=3D bytes); - - if ( state->op_bytes < sizeof(*fxsr) ) - { - if ( state->rex_prefix & REX_W ) - { - /* - * The only way to force fxsaveq on a wide range of gas - * versions. On older versions the rex64 prefix works only= if - * we force an addressing mode that doesn't require extend= ed - * registers. - */ - asm volatile ( ".byte 0x48; fxsave (%1)" - : "=3Dm" (*fxsr) : "R" (fxsr) ); - } - else - asm volatile ( "fxsave %0" : "=3Dm" (*fxsr) ); - } - - /* - * Don't chance the reserved or available ranges to contain any - * data FXRSTOR may actually consume in some way: Copy only the - * defined portion, and zero the rest. - */ - memcpy(fxsr, ptr, min(state->op_bytes, - (unsigned int)offsetof(struct x86_fxsr, rsvd= ))); - memset(fxsr->rsvd, 0, sizeof(*fxsr) - offsetof(struct x86_fxsr, rs= vd)); - - generate_exception_if(fxsr->mxcsr & ~mxcsr_mask, EXC_GP, 0); - - if ( state->rex_prefix & REX_W ) - { - /* See above for why operand/constraints are this way. */ - asm volatile ( ".byte 0x48; fxrstor (%1)" - :: "m" (*fxsr), "R" (fxsr) ); - } - else - asm volatile ( "fxrstor %0" :: "m" (*fxsr) ); - break; - } - - case blk_fxsave: - { - struct x86_fxsr *fxsr =3D FXSAVE_AREA; - - ASSERT(!data); - ASSERT(bytes =3D=3D sizeof(*fxsr)); - ASSERT(state->op_bytes <=3D bytes); - - if ( state->op_bytes < sizeof(*fxsr) ) - /* Don't chance consuming uninitialized data. */ - memset(fxsr, 0, state->op_bytes); - else - fxsr =3D ptr; - - if ( state->rex_prefix & REX_W ) - { - /* See above for why operand/constraints are this way. */ - asm volatile ( ".byte 0x48; fxsave (%1)" - : "=3Dm" (*fxsr) : "R" (fxsr) ); - } - else - asm volatile ( "fxsave %0" : "=3Dm" (*fxsr) ); - - if ( fxsr !=3D ptr ) /* i.e. state->op_bytes < sizeof(*fxsr) */ - memcpy(ptr, fxsr, state->op_bytes); - break; - } - -#endif /* X86EMUL_NO_{FPU,MMX,SIMD} */ - - case blk_movdir: - switch ( bytes ) - { -#ifdef __x86_64__ - case sizeof(uint32_t): -# ifdef HAVE_AS_MOVDIR - asm ( "movdiri %0, (%1)" - :: "r" (*(uint32_t *)data), "r" (ptr) : "memory" ); -# else - /* movdiri %esi, (%rdi) */ - asm ( ".byte 0x0f, 0x38, 0xf9, 0x37" - :: "S" (*(uint32_t *)data), "D" (ptr) : "memory" ); -# endif - break; -#endif - - case sizeof(unsigned long): -#ifdef HAVE_AS_MOVDIR - asm ( "movdiri %0, (%1)" - :: "r" (*(unsigned long *)data), "r" (ptr) : "memory" ); -#else - /* movdiri %rsi, (%rdi) */ - asm ( ".byte 0x48, 0x0f, 0x38, 0xf9, 0x37" - :: "S" (*(unsigned long *)data), "D" (ptr) : "memory" ); -#endif - break; - - case 64: - if ( ((unsigned long)ptr & 0x3f) ) - { - ASSERT_UNREACHABLE(); - return X86EMUL_UNHANDLEABLE; - } -#ifdef HAVE_AS_MOVDIR - asm ( "movdir64b (%0), %1" :: "r" (data), "r" (ptr) : "memory"= ); -#else - /* movdir64b (%rsi), %rdi */ - asm ( ".byte 0x66, 0x0f, 0x38, 0xf8, 0x3e" - :: "S" (data), "D" (ptr) : "memory" ); -#endif - break; - - default: - ASSERT_UNREACHABLE(); - return X86EMUL_UNHANDLEABLE; - } - break; - - default: - ASSERT_UNREACHABLE(); - return X86EMUL_UNHANDLEABLE; - } - - done: - return rc; -} - static void __init __maybe_unused build_assertions(void) { /* Check the values against SReg3 encoding in opcode/ModRM bytes. */ From nobody Thu May 2 08:52:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; arc=pass (i=1 dmarc=pass fromdomain=suse.com); dmarc=pass(p=quarantine dis=none) header.from=suse.com ARC-Seal: i=2; a=rsa-sha256; t=1628684762; cv=pass; d=zohomail.com; s=zohoarc; b=PKBS5YColBNJIc3Ik5FJaKwDUHiwUHXj8Zt251r/JmexHIcO02VSRs2WbOejGMSA09JqX0mHDOJdguHRm6BxiW4cADtCRXq4yNw2GO9lTgRzc/dBJ18hHVehTDYZSAhnWkl12uEakBc+jORK/l3lwkPNny2XE2H96iFey23m4V0= ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1628684762; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=61nzHG3t05KhKcSaMocj8vKTFGtTFK0LBUFu1Mp+C7o=; b=nltyy0iVVlUjECqXPOSrxIkOyOilEobsjM/UTrM8XOwQmfIEP/I1bpvoDhww3X5UZskmxVqCYJkASw6PRoc8MI/VB5ygB3TvcrKJK8H9zT3Fr4voYD6tis+ABz+dxyrSuZBNSeTH+XdUvqx+FkqBwBU7yyetvvAyUrQLayJrmA4= ARC-Authentication-Results: i=2; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; arc=pass (i=1 dmarc=pass fromdomain=suse.com); dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1628684762503414.27650752740783; Wed, 11 Aug 2021 05:26:02 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.166015.303195 (Exim 4.92) (envelope-from ) id 1mDnIj-0001Mi-V0; Wed, 11 Aug 2021 12:25:41 +0000 Received: by outflank-mailman (output) from mailman id 166015.303195; Wed, 11 Aug 2021 12:25:41 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1mDnIj-0001MZ-Rf; Wed, 11 Aug 2021 12:25:41 +0000 Received: by outflank-mailman (input) for mailman id 166015; Wed, 11 Aug 2021 12:25:40 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1mDnIi-0001MJ-H0 for xen-devel@lists.xenproject.org; Wed, 11 Aug 2021 12:25:40 +0000 Received: from de-smtp-delivery-102.mimecast.com (unknown [194.104.109.102]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id 3b573b6e-fa9f-11eb-a06e-12813bfff9fa; Wed, 11 Aug 2021 12:25:37 +0000 (UTC) Received: from EUR05-AM6-obe.outbound.protection.outlook.com (mail-am6eur05lp2110.outbound.protection.outlook.com [104.47.18.110]) (Using TLS) by relay.mimecast.com with ESMTP id de-mta-21-jsf7zT2MPLaK2ijKyaY8EA-1; Wed, 11 Aug 2021 14:25:35 +0200 Received: from VI1PR04MB5600.eurprd04.prod.outlook.com (2603:10a6:803:e7::16) by VI1PR0401MB2335.eurprd04.prod.outlook.com (2603:10a6:800:2e::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4394.17; Wed, 11 Aug 2021 12:25:34 +0000 Received: from VI1PR04MB5600.eurprd04.prod.outlook.com ([fe80::99d3:99cd:8adf:3eea]) by VI1PR04MB5600.eurprd04.prod.outlook.com ([fe80::99d3:99cd:8adf:3eea%5]) with mapi id 15.20.4394.025; Wed, 11 Aug 2021 12:25:34 +0000 Received: from [10.156.60.236] (37.24.206.209) by PR0P264CA0147.FRAP264.PROD.OUTLOOK.COM (2603:10a6:100:1b::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4415.13 via Frontend Transport; Wed, 11 Aug 2021 12:25:33 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 3b573b6e-fa9f-11eb-a06e-12813bfff9fa DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=mimecast20200619; t=1628684736; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=61nzHG3t05KhKcSaMocj8vKTFGtTFK0LBUFu1Mp+C7o=; b=k1RNEqGgj6OMKEIWvZg+rbRgSaPJQ9dLkhs2+sy6Dhv5+WyUFrvHg0rHnoSXOGhwfyIwSX +T3tbtqAwJk2mzA4mw6IX/pwUv9gDYP2uVUp2qAqMhIcsCUFSkDQXju3KGnaPL98elCZOV sqGBWjUEKuHRnB5OEBV2ptF+UTmLwlM= X-MC-Unique: jsf7zT2MPLaK2ijKyaY8EA-1 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=LdN8C3k0yr5dcb4RXpl5BevPqL5d5F8GHLu3QPgQn1hI9GJv+l4QEj6DOqmiIEb53dyBsGHtMuwwykHZQQC6UDRbzYn8eYO1gO9XDZ527MBjUHovd2UE8M6+cvuG+ochwyLRz1G59hVAmBMrl0hqvCDmpoHayGC7Tgx5UWETNbWd/2ErcUy0Uo4LYaVEF1Lg1ucrFTJOdZJlN23a47mWTwLlCiqRb1JaUu2rntDHlsIkwFFbX1/+lK+YQ4RIvabxXPPSBikpcyk5DNe9o5a9IgeyFjwiZ7iE6ic6aCgyji4eE+6QqUv5SqbB2QapX8ybt4nU2dTgCz3587SjNfoXrg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=61nzHG3t05KhKcSaMocj8vKTFGtTFK0LBUFu1Mp+C7o=; b=V/87wLPEhb33gnRGlAjbiVHaLX1maSZ6RYxJ+7q+0SH2c5HLcM06qUKd5+9vMGY+GVbYFdOrsq+9YkTpy1OcSqLL3JZKcE892hTkqE5wbsy59ercDlf3djduc+SLCDIjuf5wThVIcj5HCaQlz9Ao/y9/uTnCCS3jedBu7bKDVoupl46JkYxUIj9kMNtezqyyyFtxyaXBgz87zO/rZN9HdFnZm2YnK0LXobK1KVE+s60amZV6XNlyipdSsxJyINv34CgHpF396S3sAfRzAPuLcbnNZhghFbMzztxfQB4Oj5cf2SoPCaA6LuG2UNE7O1m8z65hUkQzntRJFt0mkxMKuQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=suse.com; dmarc=pass action=none header.from=suse.com; dkim=pass header.d=suse.com; arc=none Authentication-Results: citrix.com; dkim=none (message not signed) header.d=none;citrix.com; dmarc=none action=none header.from=suse.com; Subject: [PATCH 7/7] x86emul: move various utility functions to separate source files From: Jan Beulich To: "xen-devel@lists.xenproject.org" Cc: Andrew Cooper , Wei Liu , =?UTF-8?Q?Roger_Pau_Monn=c3=a9?= References: Message-ID: Date: Wed, 11 Aug 2021 14:25:32 +0200 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Thunderbird/78.12.0 In-Reply-To: Content-Language: en-US Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: PR0P264CA0147.FRAP264.PROD.OUTLOOK.COM (2603:10a6:100:1b::15) To VI1PR04MB5600.eurprd04.prod.outlook.com (2603:10a6:803:e7::16) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: dd90436e-ef31-44a8-f014-08d95cc31dca X-MS-TrafficTypeDiagnostic: VI1PR0401MB2335: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:3276; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: vFBl5dUaz+o3sgzMbQ05UP323dsAOIp2cKHjNSDscFQobl8kKDD5l0xrC855tzKYNMbdBjYbS6j04mqmorIQVHNsE5KqN4qxdbvRSuG/lCZbnOxgNP+14uX1jqBrBl11k6igfasdoBsy+wtLrdep1hdSQDzIHSgC4dd3Dt9pLhvyl8RdJLeYm0OrNbSfqec1WqRwyI9+wUWNscahQlF7i43pkyZcmRjbx/4tr5b4gTGpeJzSO6aVL2xRFaZXrkMuS2EzwSC18Aok4JcDIAb/Qh/H3boXlJEyAqazR4okQ8Af37+Fiy731mPtVi8zJlrS1rt73Cm4Q8fwfzh42ryxcIoJPmL0AhTVUYB7hAenpztNIE/ODKnoDpqAcLA+IvWD3m8xUQ1HL7pOdDB59nWR+L6N8x+qYqWXaODoH4Q4WulsNHp4IvuIGHe5Uhv69JD9JGjLPNbDrFaVReCqHEBagb/vcR41KzeVmgRSNHC8SbtWGIfQ0lF0egpYCh5O6/zuMcl5T3mqmveb/itiYbBTScNyYAcjyFu0FwBwLzON7jqfkoLBQiRZaXesCoOJTkMtVOOWz0/4HH/fljG05TvexX3snKTaFK8z8CSDwpusp7mJbr2bPnwFT/aB+1J7nLw40pAJFBaTgCZ5NSjUlGo+gxMUvyS+RMmNyc9cilKkgwtm8Srpx7XSQhpqo0NAVAr055VculXEpxYW2PW7tiT5lTHbutTNM25tOPmQJQztPGfz5cI6blLNxwSd5EvaV1eY7bA5LKdSM29rybQODJq7Tw6VZpnnRJKLe6klq0Mmu2TZbrJEI6ndE929FZr4JWYeUW7meOoZ73oAZ0XkSf0wCg== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:VI1PR04MB5600.eurprd04.prod.outlook.com;PTR:;CAT:NONE;SFS:(136003)(396003)(39860400002)(366004)(346002)(376002)(6916009)(31696002)(316002)(956004)(6486002)(2906002)(36756003)(478600001)(30864003)(86362001)(16576012)(8676002)(31686004)(8936002)(38100700002)(2616005)(66556008)(83380400001)(186003)(66476007)(66946007)(5660300002)(26005)(54906003)(66574015)(4326008)(2004002)(45980500001)(43740500002);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?THIrUExPTjZnMmczS0xRemg4R3pVdFBVc2pROTFnaGU3ampocE9tRGRBWjNC?= =?utf-8?B?b1JTSzlmSmZJZUs0T21aOVFYU0Y1STJ5MExMTFE3NTlselhSUHRxZmc0cTlh?= =?utf-8?B?V2hqTzhJam5VTzBIMXNtYXJUSnhWM1JsM1ZSUFRCZlUxdzFKcTFzTGdqTVE5?= =?utf-8?B?Y3Zzb3NUQUJPUWFxSWVWSUFlLyt5TmZtYWt0alg1VFhkMnJsQlhCZzc4NFNJ?= =?utf-8?B?VlE5Vi9zc3NMVjZFUFkzQWtQK01nb053QUxuR1FPZUVsL2VCUnQrMHVJVnRD?= =?utf-8?B?b3ZGdlVkV0t2dFdEUmxOSllXSVoxVW1VcndudDRxVDNwWUJsNWwrc1pnZStC?= =?utf-8?B?bFgrUXRHUTUrM0FhS0s4RkQyRWF1blNXT2xvaUU3ajk3TWl4NVdmM0VhNUhS?= =?utf-8?B?NWhDRWRBTEpnUGZsMUI2NGFxSTZmOW5kbFQxMERqemNNdVE3SHd2Nzc1Slgr?= =?utf-8?B?NmViTWxEd3dSTU1oekZmNnFneXQ5bWxQLzZmODBHazAwWXVjMGJLVEMrTlhS?= =?utf-8?B?ZWRBNSs1MHZMNGVIdUFlSWVIOWhETnVDMG50dUFvMWhkZ2lPdTVQV01jT0U4?= =?utf-8?B?cVpxMTlwYS9uL3NNOWUyQ3Brb2JsQ29qY3o0c3pHRUVJVGJwL1IxcC9LUDd0?= =?utf-8?B?TEJSQ3JLZWEwcE5ubkwxWHZXRTUrcHM0VS92Vi9udUNHRmxIK3p1WEQ4a3NL?= =?utf-8?B?NlJucG1Sb1hwKzJQN2ZpdEJOZHFJcktKM3hBT00zWkNWelVxWjc2cmJaMHN0?= =?utf-8?B?T01qYXhlRnFoY3hxeHFHeW93RVVhdExoS1JUczVwVGVSeUtQNFo3Tjl3STg1?= =?utf-8?B?YUpsaTZsdHpsUWlDU1E0dDZmeTlHblNISE03WUt2RVhBV25vYysyNk53QzJy?= =?utf-8?B?WXdrUjlWR2JRTzFCb2I1em9uOFk3QldKa1JQa3dFckNMdFZ5MER5cUJRRlNn?= =?utf-8?B?TXM4Q2c2V3pna3pxQ3ljOTlKK01yK1ZwcHZxWmNXc1JoRXZUZjBXTHRicE5Q?= =?utf-8?B?YUplRUJUMWphcVF3YkpxMXNoQTBmYVdHK0RFeTBDQTdpUU50VUh4U1ZNc1do?= =?utf-8?B?YzVMSEJBeUNENUNNenhLbXUwTGdtTDc5M2lBaVJxQ3BnMjRSNmpIcStmSjlh?= =?utf-8?B?OWMxYys5WGxWbVNYcDlLT0hmTnBDSWRtMjB2SmRTcHpsRS9nRWRuVXJSRjZp?= =?utf-8?B?YzBvcHZwQm5zUDlDMHluVk94amFzWnkyeHdiL3d3Q3BXTGNWREZaV1pZM095?= =?utf-8?B?S3kzekw4Q3FPNTg1ZHI1aXQyZTJQU2FzNTNiK3RoWTJaMEdQcXdYUVFsVVV4?= =?utf-8?B?Z0pWMEhQUkpQMG8xZDQ1VVl3VmtOaHYvRlU3em1lV1BtaU9wVU5hMWhUUENt?= =?utf-8?B?K2RVbXUyT01ZTUR3SWJjZm9FNHl1YjlxQkpLNVFrS3FWREtEbFBaOFFUKzFr?= =?utf-8?B?QVlTbE5yY0drS2NXRXRxcGVPQ3pVUVhlTGhIRm1GZERlZDA4RXVuMXNZV1FV?= =?utf-8?B?ZThSczlialZZSVc1NVpuUldyV1RRbERyRWxpTXlFRjNRdzY5YkJvdWpMeXpB?= =?utf-8?B?OStIOUQxQTZYekI0eFlpalN6dHNMRnVDbEN3VFJHRWdvek5MUlZLaFdHdlVo?= =?utf-8?B?bXlsMi84R3NWcm04citLSDE3ZTFXL2VSWWVLeEh1RStyMXAyTzU1cFNTYW1O?= =?utf-8?B?Z2NmQ0t3eGdReWZaeHVCSDJPbi90cUhtQzAxQW4vdGhpS0xscXQ4bis4dGN3?= =?utf-8?Q?BxuaP6PH5biV20wBcNU3+709hzM4hMPI5cTa0Fa?= X-OriginatorOrg: suse.com X-MS-Exchange-CrossTenant-Network-Message-Id: dd90436e-ef31-44a8-f014-08d95cc31dca X-MS-Exchange-CrossTenant-AuthSource: VI1PR04MB5600.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 11 Aug 2021 12:25:33.9292 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: f7a17af6-1c5c-4a36-aa8b-f5be247aa4ba X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: P9HlXbiA7mDhA9xz4MZajks/5MajZe/RTIV/paer+BZOdkURVyc2XYzFbzvhzqqXojDMjD1VCa0ag2n1cLpRWQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR0401MB2335 X-ZohoMail-DKIM: pass (identity @suse.com) X-ZM-MESSAGEID: 1628684763047100003 Content-Type: text/plain; charset="utf-8" Many are needed by the hypervisor only - have one file for this purpose. Some are also needed by the harness (but not the fuzzer) - have another file for these. Code moved gets slightly adjusted in a few places, e.g. replacing "state" by "s" (like was done for other that has been split off). Signed-off-by: Jan Beulich --- a/tools/tests/x86_emulator/Makefile +++ b/tools/tests/x86_emulator/Makefile @@ -252,7 +252,7 @@ endif # 32-bit override =20 OBJS :=3D x86-emulate.o cpuid.o test_x86_emulator.o evex-disp8.o predicate= s.o wrappers.o OBJS +=3D x86_emulate/0f01.o x86_emulate/0fae.o x86_emulate/0fc7.o -OBJS +=3D x86_emulate/blk.o x86_emulate/decode.o x86_emulate/fpu.o +OBJS +=3D x86_emulate/blk.o x86_emulate/decode.o x86_emulate/fpu.o x86_emu= late/util.o =20 $(TARGET): $(OBJS) $(HOSTCC) $(HOSTCFLAGS) -o $@ $^ --- a/xen/arch/x86/x86_emulate.c +++ b/xen/arch/x86/x86_emulate.c @@ -14,7 +14,6 @@ #include /* current_cpu_info */ #include #include /* cpu_has_amd_erratum() */ -#include =20 /* Avoid namespace pollution. */ #undef cmpxchg @@ -26,128 +25,6 @@ =20 #include "x86_emulate/x86_emulate.c" =20 -int x86emul_read_xcr(unsigned int reg, uint64_t *val, - struct x86_emulate_ctxt *ctxt) -{ - switch ( reg ) - { - case 0: - *val =3D current->arch.xcr0; - return X86EMUL_OKAY; - - case 1: - if ( current->domain->arch.cpuid->xstate.xgetbv1 ) - break; - /* fall through */ - default: - x86_emul_hw_exception(TRAP_gp_fault, 0, ctxt); - return X86EMUL_EXCEPTION; - } - - *val =3D xgetbv(reg); - - return X86EMUL_OKAY; -} - -/* Note: May be called with ctxt=3DNULL. */ -int x86emul_write_xcr(unsigned int reg, uint64_t val, - struct x86_emulate_ctxt *ctxt) -{ - switch ( reg ) - { - case 0: - break; - - default: - gp_fault: - if ( ctxt ) - x86_emul_hw_exception(TRAP_gp_fault, 0, ctxt); - return X86EMUL_EXCEPTION; - } - - if ( unlikely(handle_xsetbv(reg, val) !=3D 0) ) - goto gp_fault; - - return X86EMUL_OKAY; -} - -#ifdef CONFIG_PV -/* Called with NULL ctxt in hypercall context. */ -int x86emul_read_dr(unsigned int reg, unsigned long *val, - struct x86_emulate_ctxt *ctxt) -{ - struct vcpu *curr =3D current; - - /* HVM support requires a bit more plumbing before it will work. */ - ASSERT(is_pv_vcpu(curr)); - - switch ( reg ) - { - case 0 ... 3: - *val =3D array_access_nospec(curr->arch.dr, reg); - break; - - case 4: - if ( curr->arch.pv.ctrlreg[4] & X86_CR4_DE ) - goto ud_fault; - - /* Fallthrough */ - case 6: - *val =3D curr->arch.dr6; - break; - - case 5: - if ( curr->arch.pv.ctrlreg[4] & X86_CR4_DE ) - goto ud_fault; - - /* Fallthrough */ - case 7: - *val =3D curr->arch.dr7 | curr->arch.pv.dr7_emul; - break; - - ud_fault: - default: - if ( ctxt ) - x86_emul_hw_exception(TRAP_invalid_op, X86_EVENT_NO_EC, ctxt); - - return X86EMUL_EXCEPTION; - } - - return X86EMUL_OKAY; -} - -int x86emul_write_dr(unsigned int reg, unsigned long val, - struct x86_emulate_ctxt *ctxt) -{ - struct vcpu *curr =3D current; - - /* HVM support requires a bit more plumbing before it will work. */ - ASSERT(is_pv_vcpu(curr)); - - switch ( set_debugreg(curr, reg, val) ) - { - case 0: - return X86EMUL_OKAY; - - case -ENODEV: - x86_emul_hw_exception(TRAP_invalid_op, X86_EVENT_NO_EC, ctxt); - return X86EMUL_EXCEPTION; - - default: - x86_emul_hw_exception(TRAP_gp_fault, 0, ctxt); - return X86EMUL_EXCEPTION; - } -} -#endif /* CONFIG_PV */ - -int x86emul_cpuid(uint32_t leaf, uint32_t subleaf, - struct cpuid_leaf *res, struct x86_emulate_ctxt *ctxt) -{ - guest_cpuid(current, leaf, subleaf, res); - - return X86EMUL_OKAY; -} - /* * Local variables: * mode: C --- a/xen/arch/x86/x86_emulate/Makefile +++ b/xen/arch/x86/x86_emulate/Makefile @@ -4,3 +4,5 @@ obj-y +=3D 0fc7.o obj-y +=3D blk.o obj-y +=3D decode.o obj-$(CONFIG_HVM) +=3D fpu.o +obj-y +=3D util.o +obj-y +=3D util-xen.o --- a/xen/arch/x86/x86_emulate/private.h +++ b/xen/arch/x86/x86_emulate/private.h @@ -330,6 +330,13 @@ struct x86_emulate_state { #endif }; =20 +static inline void check_state(const struct x86_emulate_state *s) +{ +#if defined(__XEN__) && !defined(NDEBUG) + ASSERT(s->caller); +#endif +} + typedef union { uint64_t mmx; uint64_t __attribute__ ((aligned(16))) xmm[2]; --- /dev/null +++ b/xen/arch/x86/x86_emulate/util.c @@ -0,0 +1,298 @@ +/*************************************************************************= ***** + * util.c + * + * Generic x86 (32-bit and 64-bit) instruction decoder and emulator utility + * functions. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; If not, see . + */ + +#include "private.h" + +unsigned int x86_insn_length(const struct x86_emulate_state *s, + const struct x86_emulate_ctxt *ctxt) +{ + check_state(s); + + return s->ip - ctxt->regs->r(ip); +} + +/* + * This function means to return 'true' for all supported insns with expli= cit + * accesses to memory. This means also insns which don't have an explicit + * memory operand (like POP), but it does not mean e.g. segment selector + * loads, where the descriptor table access is considered an implicit one. + */ +bool x86_insn_is_mem_access(const struct x86_emulate_state *s, + const struct x86_emulate_ctxt *ctxt) +{ + if ( mode_64bit() && s->not_64bit ) + return false; + + if ( s->ea.type =3D=3D OP_MEM ) + { + switch ( ctxt->opcode ) + { + case 0x8d: /* LEA */ + case X86EMUL_OPC(0x0f, 0x0d): /* PREFETCH */ + case X86EMUL_OPC(0x0f, 0x18) + ... X86EMUL_OPC(0x0f, 0x1f): /* NOP space */ + case X86EMUL_OPC_66(0x0f, 0x18) + ... X86EMUL_OPC_66(0x0f, 0x1f): /* NOP space */ + case X86EMUL_OPC_F3(0x0f, 0x18) + ... X86EMUL_OPC_F3(0x0f, 0x1f): /* NOP space */ + case X86EMUL_OPC_F2(0x0f, 0x18) + ... X86EMUL_OPC_F2(0x0f, 0x1f): /* NOP space */ + case X86EMUL_OPC(0x0f, 0xb9): /* UD1 */ + case X86EMUL_OPC(0x0f, 0xff): /* UD0 */ + case X86EMUL_OPC_EVEX_66(0x0f38, 0xc6): /* V{GATH,SCATT}ERPF*D* */ + case X86EMUL_OPC_EVEX_66(0x0f38, 0xc7): /* V{GATH,SCATT}ERPF*Q* */ + return false; + + case X86EMUL_OPC(0x0f, 0x01): + return (s->modrm_reg & 7) !=3D 7; /* INVLPG */ + + case X86EMUL_OPC(0x0f, 0xae): + return (s->modrm_reg & 7) !=3D 7; /* CLFLUSH */ + + case X86EMUL_OPC_66(0x0f, 0xae): + return (s->modrm_reg & 7) < 6; /* CLWB, CLFLUSHOPT */ + } + + return true; + } + + switch ( ctxt->opcode ) + { + case 0x06 ... 0x07: /* PUSH / POP %es */ + case 0x0e: /* PUSH %cs */ + case 0x16 ... 0x17: /* PUSH / POP %ss */ + case 0x1e ... 0x1f: /* PUSH / POP %ds */ + case 0x50 ... 0x5f: /* PUSH / POP reg */ + case 0x60 ... 0x61: /* PUSHA / POPA */ + case 0x68: case 0x6a: /* PUSH imm */ + case 0x6c ... 0x6f: /* INS / OUTS */ + case 0x8f: /* POP r/m */ + case 0x9a: /* CALL (far, direct) */ + case 0x9c ... 0x9d: /* PUSHF / POPF */ + case 0xa4 ... 0xa7: /* MOVS / CMPS */ + case 0xaa ... 0xaf: /* STOS / LODS / SCAS */ + case 0xc2 ... 0xc3: /* RET (near) */ + case 0xc8 ... 0xc9: /* ENTER / LEAVE */ + case 0xca ... 0xcb: /* RET (far) */ + case 0xd7: /* XLAT */ + case 0xe8: /* CALL (near, direct) */ + case X86EMUL_OPC(0x0f, 0xa0): /* PUSH %fs */ + case X86EMUL_OPC(0x0f, 0xa1): /* POP %fs */ + case X86EMUL_OPC(0x0f, 0xa8): /* PUSH %gs */ + case X86EMUL_OPC(0x0f, 0xa9): /* POP %gs */ + case X86EMUL_OPC(0x0f, 0xf7): /* MASKMOVQ */ + case X86EMUL_OPC_66(0x0f, 0xf7): /* MASKMOVDQU */ + case X86EMUL_OPC_VEX_66(0x0f, 0xf7): /* VMASKMOVDQU */ + return true; + + case 0xff: + switch ( s->modrm_reg & 7 ) + { + case 2: /* CALL (near, indirect) */ + case 6: /* PUSH r/m */ + return true; + } + break; + + case X86EMUL_OPC(0x0f, 0x01): + /* Cover CLZERO. */ + return (s->modrm_rm & 7) =3D=3D 4 && (s->modrm_reg & 7) =3D=3D 7; + } + + return false; +} + +/* + * This function means to return 'true' for all supported insns with expli= cit + * writes to memory. This means also insns which don't have an explicit + * memory operand (like PUSH), but it does not mean e.g. segment selector + * loads, where the (possible) descriptor table write is considered an + * implicit access. + */ +bool x86_insn_is_mem_write(const struct x86_emulate_state *s, + const struct x86_emulate_ctxt *ctxt) +{ + if ( mode_64bit() && s->not_64bit ) + return false; + + switch ( s->desc & DstMask ) + { + case DstMem: + /* The SrcMem check is to cover {,V}MASKMOV{Q,DQU}. */ + return s->modrm_mod !=3D 3 || (s->desc & SrcMask) =3D=3D SrcMem; + + case DstBitBase: + case DstImplicit: + break; + + default: + switch ( ctxt->opcode ) + { + case 0x63: /* ARPL */ + return !mode_64bit(); + + case X86EMUL_OPC_66(0x0f38, 0xf8): /* MOVDIR64B */ + case X86EMUL_OPC_F2(0x0f38, 0xf8): /* ENQCMD */ + case X86EMUL_OPC_F3(0x0f38, 0xf8): /* ENQCMDS */ + return true; + + case X86EMUL_OPC_EVEX_F3(0x0f38, 0x10) ... + X86EMUL_OPC_EVEX_F3(0x0f38, 0x15): /* VPMOVUS* */ + case X86EMUL_OPC_EVEX_F3(0x0f38, 0x20) ... + X86EMUL_OPC_EVEX_F3(0x0f38, 0x25): /* VPMOVS* */ + case X86EMUL_OPC_EVEX_F3(0x0f38, 0x30) ... + X86EMUL_OPC_EVEX_F3(0x0f38, 0x35): /* VPMOV{D,Q,W}* */ + return s->modrm_mod !=3D 3; + } + + return false; + } + + if ( s->modrm_mod =3D=3D 3 ) + { + switch ( ctxt->opcode ) + { + case 0xff: /* Grp5 */ + break; + + case X86EMUL_OPC(0x0f, 0x01): /* CLZERO is the odd one. */ + return (s->modrm_rm & 7) =3D=3D 4 && (s->modrm_reg & 7) =3D=3D= 7; + + default: + return false; + } + } + + switch ( ctxt->opcode ) + { + case 0x06: /* PUSH %es */ + case 0x0e: /* PUSH %cs */ + case 0x16: /* PUSH %ss */ + case 0x1e: /* PUSH %ds */ + case 0x50 ... 0x57: /* PUSH reg */ + case 0x60: /* PUSHA */ + case 0x68: case 0x6a: /* PUSH imm */ + case 0x6c: case 0x6d: /* INS */ + case 0x9a: /* CALL (far, direct) */ + case 0x9c: /* PUSHF */ + case 0xa4: case 0xa5: /* MOVS */ + case 0xaa: case 0xab: /* STOS */ + case 0xc8: /* ENTER */ + case 0xe8: /* CALL (near, direct) */ + case X86EMUL_OPC(0x0f, 0xa0): /* PUSH %fs */ + case X86EMUL_OPC(0x0f, 0xa8): /* PUSH %gs */ + case X86EMUL_OPC(0x0f, 0xab): /* BTS */ + case X86EMUL_OPC(0x0f, 0xb3): /* BTR */ + case X86EMUL_OPC(0x0f, 0xbb): /* BTC */ + return true; + + case 0xd9: + switch ( s->modrm_reg & 7 ) + { + case 2: /* FST m32fp */ + case 3: /* FSTP m32fp */ + case 6: /* FNSTENV */ + case 7: /* FNSTCW */ + return true; + } + break; + + case 0xdb: + switch ( s->modrm_reg & 7 ) + { + case 1: /* FISTTP m32i */ + case 2: /* FIST m32i */ + case 3: /* FISTP m32i */ + case 7: /* FSTP m80fp */ + return true; + } + break; + + case 0xdd: + switch ( s->modrm_reg & 7 ) + { + case 1: /* FISTTP m64i */ + case 2: /* FST m64fp */ + case 3: /* FSTP m64fp */ + case 6: /* FNSAVE */ + case 7: /* FNSTSW */ + return true; + } + break; + + case 0xdf: + switch ( s->modrm_reg & 7 ) + { + case 1: /* FISTTP m16i */ + case 2: /* FIST m16i */ + case 3: /* FISTP m16i */ + case 6: /* FBSTP */ + case 7: /* FISTP m64i */ + return true; + } + break; + + case 0xff: + switch ( s->modrm_reg & 7 ) + { + case 2: /* CALL (near, indirect) */ + case 3: /* CALL (far, indirect) */ + case 6: /* PUSH r/m */ + return true; + } + break; + + case X86EMUL_OPC(0x0f, 0x01): + switch ( s->modrm_reg & 7 ) + { + case 0: /* SGDT */ + case 1: /* SIDT */ + case 4: /* SMSW */ + return true; + } + break; + + case X86EMUL_OPC(0x0f, 0xae): + switch ( s->modrm_reg & 7 ) + { + case 0: /* FXSAVE */ + /* case 3: STMXCSR - handled above */ + case 4: /* XSAVE */ + case 6: /* XSAVEOPT */ + return true; + } + break; + + case X86EMUL_OPC(0x0f, 0xba): + return (s->modrm_reg & 7) > 4; /* BTS / BTR / BTC */ + + case X86EMUL_OPC(0x0f, 0xc7): + switch ( s->modrm_reg & 7 ) + { + case 1: /* CMPXCHG{8,16}B */ + case 4: /* XSAVEC */ + case 5: /* XSAVES */ + return true; + } + break; + } + + return false; +} --- /dev/null +++ b/xen/arch/x86/x86_emulate/util-xen.c @@ -0,0 +1,249 @@ +/*************************************************************************= ***** + * util-xen.c + * + * Generic x86 (32-bit and 64-bit) instruction decoder and emulator hyperv= isor- + * only utility functions. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; If not, see . + */ + +#include "private.h" + +#include +#include +#include +#include + +#ifndef NDEBUG +void x86_emulate_free_state(struct x86_emulate_state *s) +{ + check_state(s); + s->caller =3D NULL; +} +#endif + +unsigned int x86_insn_opsize(const struct x86_emulate_state *s) +{ + check_state(s); + + return s->op_bytes << 3; +} + +int x86_insn_modrm(const struct x86_emulate_state *s, + unsigned int *rm, unsigned int *reg) +{ + check_state(s); + + if ( unlikely(s->modrm_mod > 3) ) + { + if ( rm ) + *rm =3D ~0U; + if ( reg ) + *reg =3D ~0U; + return -EINVAL; + } + + if ( rm ) + *rm =3D s->modrm_rm; + if ( reg ) + *reg =3D s->modrm_reg; + + return s->modrm_mod; +} + +unsigned long x86_insn_operand_ea(const struct x86_emulate_state *s, + enum x86_segment *seg) +{ + *seg =3D s->ea.type =3D=3D OP_MEM ? s->ea.mem.seg : x86_seg_none; + + check_state(s); + + return s->ea.mem.off; +} + +bool x86_insn_is_portio(const struct x86_emulate_state *s, + const struct x86_emulate_ctxt *ctxt) +{ + switch ( ctxt->opcode ) + { + case 0x6c ... 0x6f: /* INS / OUTS */ + case 0xe4 ... 0xe7: /* IN / OUT imm8 */ + case 0xec ... 0xef: /* IN / OUT %dx */ + return true; + } + + return false; +} + +bool x86_insn_is_cr_access(const struct x86_emulate_state *s, + const struct x86_emulate_ctxt *ctxt) +{ + switch ( ctxt->opcode ) + { + unsigned int ext; + + case X86EMUL_OPC(0x0f, 0x01): + if ( x86_insn_modrm(s, NULL, &ext) >=3D 0 + && (ext & 5) =3D=3D 4 ) /* SMSW / LMSW */ + return true; + break; + + case X86EMUL_OPC(0x0f, 0x06): /* CLTS */ + case X86EMUL_OPC(0x0f, 0x20): /* MOV from CRn */ + case X86EMUL_OPC(0x0f, 0x22): /* MOV to CRn */ + return true; + } + + return false; +} + +unsigned long x86_insn_immediate(const struct x86_emulate_state *s, + unsigned int nr) +{ + check_state(s); + + switch ( nr ) + { + case 0: + return s->imm1; + case 1: + return s->imm2; + } + + return 0; +} + +int x86emul_read_xcr(unsigned int reg, uint64_t *val, + struct x86_emulate_ctxt *ctxt) +{ + switch ( reg ) + { + case 0: + *val =3D current->arch.xcr0; + return X86EMUL_OKAY; + + case 1: + if ( current->domain->arch.cpuid->xstate.xgetbv1 ) + break; + /* fall through */ + default: + x86_emul_hw_exception(TRAP_gp_fault, 0, ctxt); + return X86EMUL_EXCEPTION; + } + + *val =3D xgetbv(reg); + + return X86EMUL_OKAY; +} + +/* Note: May be called with ctxt=3DNULL. */ +int x86emul_write_xcr(unsigned int reg, uint64_t val, + struct x86_emulate_ctxt *ctxt) +{ + switch ( reg ) + { + case 0: + break; + + default: + gp_fault: + if ( ctxt ) + x86_emul_hw_exception(TRAP_gp_fault, 0, ctxt); + return X86EMUL_EXCEPTION; + } + + if ( unlikely(handle_xsetbv(reg, val) !=3D 0) ) + goto gp_fault; + + return X86EMUL_OKAY; +} + +#ifdef CONFIG_PV + +/* Called with NULL ctxt in hypercall context. */ +int x86emul_read_dr(unsigned int reg, unsigned long *val, + struct x86_emulate_ctxt *ctxt) +{ + struct vcpu *curr =3D current; + + /* HVM support requires a bit more plumbing before it will work. */ + ASSERT(is_pv_vcpu(curr)); + + switch ( reg ) + { + case 0 ... 3: + *val =3D array_access_nospec(curr->arch.dr, reg); + break; + + case 4: + if ( curr->arch.pv.ctrlreg[4] & X86_CR4_DE ) + goto ud_fault; + + /* Fallthrough */ + case 6: + *val =3D curr->arch.dr6; + break; + + case 5: + if ( curr->arch.pv.ctrlreg[4] & X86_CR4_DE ) + goto ud_fault; + + /* Fallthrough */ + case 7: + *val =3D curr->arch.dr7 | curr->arch.pv.dr7_emul; + break; + + ud_fault: + default: + if ( ctxt ) + x86_emul_hw_exception(TRAP_invalid_op, X86_EVENT_NO_EC, ctxt); + + return X86EMUL_EXCEPTION; + } + + return X86EMUL_OKAY; +} + +int x86emul_write_dr(unsigned int reg, unsigned long val, + struct x86_emulate_ctxt *ctxt) +{ + struct vcpu *curr =3D current; + + /* HVM support requires a bit more plumbing before it will work. */ + ASSERT(is_pv_vcpu(curr)); + + switch ( set_debugreg(curr, reg, val) ) + { + case 0: + return X86EMUL_OKAY; + + case -ENODEV: + x86_emul_hw_exception(TRAP_invalid_op, X86_EVENT_NO_EC, ctxt); + return X86EMUL_EXCEPTION; + + default: + x86_emul_hw_exception(TRAP_gp_fault, 0, ctxt); + return X86EMUL_EXCEPTION; + } +} + +#endif /* CONFIG_PV */ + +int x86emul_cpuid(uint32_t leaf, uint32_t subleaf, + struct cpuid_leaf *res, struct x86_emulate_ctxt *ctxt) +{ + guest_cpuid(current, leaf, subleaf, res); + + return X86EMUL_OKAY; +} --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -8412,393 +8412,3 @@ int x86_emulate_wrapper( return rc; } #endif - -static inline void check_state(const struct x86_emulate_state *state) -{ -#if defined(__XEN__) && !defined(NDEBUG) - ASSERT(state->caller); -#endif -} - -#if defined(__XEN__) && !defined(NDEBUG) -void x86_emulate_free_state(struct x86_emulate_state *state) -{ - check_state(state); - state->caller =3D NULL; -} -#endif - -unsigned int -x86_insn_opsize(const struct x86_emulate_state *state) -{ - check_state(state); - - return state->op_bytes << 3; -} - -int -x86_insn_modrm(const struct x86_emulate_state *state, - unsigned int *rm, unsigned int *reg) -{ - check_state(state); - - if ( unlikely(state->modrm_mod > 3) ) - { - if ( rm ) - *rm =3D ~0U; - if ( reg ) - *reg =3D ~0U; - return -EINVAL; - } - - if ( rm ) - *rm =3D state->modrm_rm; - if ( reg ) - *reg =3D state->modrm_reg; - - return state->modrm_mod; -} - -unsigned long -x86_insn_operand_ea(const struct x86_emulate_state *state, - enum x86_segment *seg) -{ - *seg =3D state->ea.type =3D=3D OP_MEM ? state->ea.mem.seg : x86_seg_no= ne; - - check_state(state); - - return state->ea.mem.off; -} - -/* - * This function means to return 'true' for all supported insns with expli= cit - * accesses to memory. This means also insns which don't have an explicit - * memory operand (like POP), but it does not mean e.g. segment selector - * loads, where the descriptor table access is considered an implicit one. - */ -bool -x86_insn_is_mem_access(const struct x86_emulate_state *state, - const struct x86_emulate_ctxt *ctxt) -{ - if ( mode_64bit() && state->not_64bit ) - return false; - - if ( state->ea.type =3D=3D OP_MEM ) - { - switch ( ctxt->opcode ) - { - case 0x8d: /* LEA */ - case X86EMUL_OPC(0x0f, 0x0d): /* PREFETCH */ - case X86EMUL_OPC(0x0f, 0x18) - ... X86EMUL_OPC(0x0f, 0x1f): /* NOP space */ - case X86EMUL_OPC_66(0x0f, 0x18) - ... X86EMUL_OPC_66(0x0f, 0x1f): /* NOP space */ - case X86EMUL_OPC_F3(0x0f, 0x18) - ... X86EMUL_OPC_F3(0x0f, 0x1f): /* NOP space */ - case X86EMUL_OPC_F2(0x0f, 0x18) - ... X86EMUL_OPC_F2(0x0f, 0x1f): /* NOP space */ - case X86EMUL_OPC(0x0f, 0xb9): /* UD1 */ - case X86EMUL_OPC(0x0f, 0xff): /* UD0 */ - case X86EMUL_OPC_EVEX_66(0x0f38, 0xc6): /* V{GATH,SCATT}ERPF*D* */ - case X86EMUL_OPC_EVEX_66(0x0f38, 0xc7): /* V{GATH,SCATT}ERPF*Q* */ - return false; - - case X86EMUL_OPC(0x0f, 0x01): - return (state->modrm_reg & 7) !=3D 7; /* INVLPG */ - - case X86EMUL_OPC(0x0f, 0xae): - return (state->modrm_reg & 7) !=3D 7; /* CLFLUSH */ - - case X86EMUL_OPC_66(0x0f, 0xae): - return (state->modrm_reg & 7) < 6; /* CLWB, CLFLUSHOPT */ - } - - return true; - } - - switch ( ctxt->opcode ) - { - case 0x06 ... 0x07: /* PUSH / POP %es */ - case 0x0e: /* PUSH %cs */ - case 0x16 ... 0x17: /* PUSH / POP %ss */ - case 0x1e ... 0x1f: /* PUSH / POP %ds */ - case 0x50 ... 0x5f: /* PUSH / POP reg */ - case 0x60 ... 0x61: /* PUSHA / POPA */ - case 0x68: case 0x6a: /* PUSH imm */ - case 0x6c ... 0x6f: /* INS / OUTS */ - case 0x8f: /* POP r/m */ - case 0x9a: /* CALL (far, direct) */ - case 0x9c ... 0x9d: /* PUSHF / POPF */ - case 0xa4 ... 0xa7: /* MOVS / CMPS */ - case 0xaa ... 0xaf: /* STOS / LODS / SCAS */ - case 0xc2 ... 0xc3: /* RET (near) */ - case 0xc8 ... 0xc9: /* ENTER / LEAVE */ - case 0xca ... 0xcb: /* RET (far) */ - case 0xd7: /* XLAT */ - case 0xe8: /* CALL (near, direct) */ - case X86EMUL_OPC(0x0f, 0xa0): /* PUSH %fs */ - case X86EMUL_OPC(0x0f, 0xa1): /* POP %fs */ - case X86EMUL_OPC(0x0f, 0xa8): /* PUSH %gs */ - case X86EMUL_OPC(0x0f, 0xa9): /* POP %gs */ - CASE_SIMD_PACKED_INT_VEX(0x0f, 0xf7): /* MASKMOV{Q,DQU} */ - /* VMASKMOVDQU */ - return true; - - case 0xff: - switch ( state->modrm_reg & 7 ) - { - case 2: /* CALL (near, indirect) */ - case 6: /* PUSH r/m */ - return true; - } - break; - - case X86EMUL_OPC(0x0f, 0x01): - /* Cover CLZERO. */ - return (state->modrm_rm & 7) =3D=3D 4 && (state->modrm_reg & 7) = =3D=3D 7; - } - - return false; -} - -/* - * This function means to return 'true' for all supported insns with expli= cit - * writes to memory. This means also insns which don't have an explicit - * memory operand (like PUSH), but it does not mean e.g. segment selector - * loads, where the (possible) descriptor table write is considered an - * implicit access. - */ -bool -x86_insn_is_mem_write(const struct x86_emulate_state *state, - const struct x86_emulate_ctxt *ctxt) -{ - if ( mode_64bit() && state->not_64bit ) - return false; - - switch ( state->desc & DstMask ) - { - case DstMem: - /* The SrcMem check is to cover {,V}MASKMOV{Q,DQU}. */ - return state->modrm_mod !=3D 3 || (state->desc & SrcMask) =3D=3D S= rcMem; - - case DstBitBase: - case DstImplicit: - break; - - default: - switch ( ctxt->opcode ) - { - case 0x63: /* ARPL */ - return !mode_64bit(); - - case X86EMUL_OPC_66(0x0f38, 0xf8): /* MOVDIR64B */ - case X86EMUL_OPC_F2(0x0f38, 0xf8): /* ENQCMD */ - case X86EMUL_OPC_F3(0x0f38, 0xf8): /* ENQCMDS */ - return true; - - case X86EMUL_OPC_EVEX_F3(0x0f38, 0x10) ... - X86EMUL_OPC_EVEX_F3(0x0f38, 0x15): /* VPMOVUS* */ - case X86EMUL_OPC_EVEX_F3(0x0f38, 0x20) ... - X86EMUL_OPC_EVEX_F3(0x0f38, 0x25): /* VPMOVS* */ - case X86EMUL_OPC_EVEX_F3(0x0f38, 0x30) ... - X86EMUL_OPC_EVEX_F3(0x0f38, 0x35): /* VPMOV{D,Q,W}* */ - return state->modrm_mod !=3D 3; - } - - return false; - } - - if ( state->modrm_mod =3D=3D 3 ) - { - switch ( ctxt->opcode ) - { - case 0xff: /* Grp5 */ - break; - - case X86EMUL_OPC(0x0f, 0x01): /* CLZERO is the odd one. */ - return (state->modrm_rm & 7) =3D=3D 4 && (state->modrm_reg & 7= ) =3D=3D 7; - - default: - return false; - } - } - - switch ( ctxt->opcode ) - { - case 0x06: /* PUSH %es */ - case 0x0e: /* PUSH %cs */ - case 0x16: /* PUSH %ss */ - case 0x1e: /* PUSH %ds */ - case 0x50 ... 0x57: /* PUSH reg */ - case 0x60: /* PUSHA */ - case 0x68: case 0x6a: /* PUSH imm */ - case 0x6c: case 0x6d: /* INS */ - case 0x9a: /* CALL (far, direct) */ - case 0x9c: /* PUSHF */ - case 0xa4: case 0xa5: /* MOVS */ - case 0xaa: case 0xab: /* STOS */ - case 0xc8: /* ENTER */ - case 0xe8: /* CALL (near, direct) */ - case X86EMUL_OPC(0x0f, 0xa0): /* PUSH %fs */ - case X86EMUL_OPC(0x0f, 0xa8): /* PUSH %gs */ - case X86EMUL_OPC(0x0f, 0xab): /* BTS */ - case X86EMUL_OPC(0x0f, 0xb3): /* BTR */ - case X86EMUL_OPC(0x0f, 0xbb): /* BTC */ - return true; - - case 0xd9: - switch ( state->modrm_reg & 7 ) - { - case 2: /* FST m32fp */ - case 3: /* FSTP m32fp */ - case 6: /* FNSTENV */ - case 7: /* FNSTCW */ - return true; - } - break; - - case 0xdb: - switch ( state->modrm_reg & 7 ) - { - case 1: /* FISTTP m32i */ - case 2: /* FIST m32i */ - case 3: /* FISTP m32i */ - case 7: /* FSTP m80fp */ - return true; - } - break; - - case 0xdd: - switch ( state->modrm_reg & 7 ) - { - case 1: /* FISTTP m64i */ - case 2: /* FST m64fp */ - case 3: /* FSTP m64fp */ - case 6: /* FNSAVE */ - case 7: /* FNSTSW */ - return true; - } - break; - - case 0xdf: - switch ( state->modrm_reg & 7 ) - { - case 1: /* FISTTP m16i */ - case 2: /* FIST m16i */ - case 3: /* FISTP m16i */ - case 6: /* FBSTP */ - case 7: /* FISTP m64i */ - return true; - } - break; - - case 0xff: - switch ( state->modrm_reg & 7 ) - { - case 2: /* CALL (near, indirect) */ - case 3: /* CALL (far, indirect) */ - case 6: /* PUSH r/m */ - return true; - } - break; - - case X86EMUL_OPC(0x0f, 0x01): - switch ( state->modrm_reg & 7 ) - { - case 0: /* SGDT */ - case 1: /* SIDT */ - case 4: /* SMSW */ - return true; - } - break; - - case X86EMUL_OPC(0x0f, 0xae): - switch ( state->modrm_reg & 7 ) - { - case 0: /* FXSAVE */ - /* case 3: STMXCSR - handled above */ - case 4: /* XSAVE */ - case 6: /* XSAVEOPT */ - return true; - } - break; - - case X86EMUL_OPC(0x0f, 0xba): - return (state->modrm_reg & 7) > 4; /* BTS / BTR / BTC */ - - case X86EMUL_OPC(0x0f, 0xc7): - switch ( state->modrm_reg & 7 ) - { - case 1: /* CMPXCHG{8,16}B */ - case 4: /* XSAVEC */ - case 5: /* XSAVES */ - return true; - } - break; - } - - return false; -} - -bool -x86_insn_is_portio(const struct x86_emulate_state *state, - const struct x86_emulate_ctxt *ctxt) -{ - switch ( ctxt->opcode ) - { - case 0x6c ... 0x6f: /* INS / OUTS */ - case 0xe4 ... 0xe7: /* IN / OUT imm8 */ - case 0xec ... 0xef: /* IN / OUT %dx */ - return true; - } - - return false; -} - -bool -x86_insn_is_cr_access(const struct x86_emulate_state *state, - const struct x86_emulate_ctxt *ctxt) -{ - switch ( ctxt->opcode ) - { - unsigned int ext; - - case X86EMUL_OPC(0x0f, 0x01): - if ( x86_insn_modrm(state, NULL, &ext) >=3D 0 - && (ext & 5) =3D=3D 4 ) /* SMSW / LMSW */ - return true; - break; - - case X86EMUL_OPC(0x0f, 0x06): /* CLTS */ - case X86EMUL_OPC(0x0f, 0x20): /* MOV from CRn */ - case X86EMUL_OPC(0x0f, 0x22): /* MOV to CRn */ - return true; - } - - return false; -} - -unsigned long -x86_insn_immediate(const struct x86_emulate_state *state, unsigned int nr) -{ - check_state(state); - - switch ( nr ) - { - case 0: - return state->imm1; - case 1: - return state->imm2; - } - - return 0; -} - -unsigned int -x86_insn_length(const struct x86_emulate_state *state, - const struct x86_emulate_ctxt *ctxt) -{ - check_state(state); - - return state->ip - ctxt->regs->r(ip); -}