1*e6b71c14Sreinoud /* $NetBSD: libnvmm_x86.c,v 1.43 2020/12/27 20:56:14 reinoud Exp $ */
22760ca24Smaxv
32760ca24Smaxv /*
44a2e4dc3Smaxv * Copyright (c) 2018-2020 Maxime Villard, m00nbsd.net
52760ca24Smaxv * All rights reserved.
62760ca24Smaxv *
74a2e4dc3Smaxv * This code is part of the NVMM hypervisor.
82760ca24Smaxv *
92760ca24Smaxv * Redistribution and use in source and binary forms, with or without
102760ca24Smaxv * modification, are permitted provided that the following conditions
112760ca24Smaxv * are met:
122760ca24Smaxv * 1. Redistributions of source code must retain the above copyright
132760ca24Smaxv * notice, this list of conditions and the following disclaimer.
142760ca24Smaxv * 2. Redistributions in binary form must reproduce the above copyright
152760ca24Smaxv * notice, this list of conditions and the following disclaimer in the
162760ca24Smaxv * documentation and/or other materials provided with the distribution.
172760ca24Smaxv *
184a2e4dc3Smaxv * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
194a2e4dc3Smaxv * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
204a2e4dc3Smaxv * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
214a2e4dc3Smaxv * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
224a2e4dc3Smaxv * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
234a2e4dc3Smaxv * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
244a2e4dc3Smaxv * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
254a2e4dc3Smaxv * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
264a2e4dc3Smaxv * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
274a2e4dc3Smaxv * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
284a2e4dc3Smaxv * SUCH DAMAGE.
292760ca24Smaxv */
302760ca24Smaxv
312760ca24Smaxv #include <sys/cdefs.h>
322760ca24Smaxv
332760ca24Smaxv #include <stdio.h>
342760ca24Smaxv #include <stdlib.h>
352760ca24Smaxv #include <string.h>
362760ca24Smaxv #include <unistd.h>
372760ca24Smaxv #include <fcntl.h>
382760ca24Smaxv #include <errno.h>
392760ca24Smaxv #include <sys/ioctl.h>
402760ca24Smaxv #include <sys/mman.h>
412760ca24Smaxv #include <machine/vmparam.h>
422760ca24Smaxv #include <machine/pte.h>
432760ca24Smaxv #include <machine/psl.h>
442760ca24Smaxv
4580932742Smaxv #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
464977f2ebSmaxv #define __cacheline_aligned __attribute__((__aligned__(64)))
4780932742Smaxv
482760ca24Smaxv #include <x86/specialreg.h>
492760ca24Smaxv
50f9737344Smaxv /* -------------------------------------------------------------------------- */
51f9737344Smaxv
5238b2a665Smaxv /*
5338b2a665Smaxv * Undocumented debugging function. Helpful.
5438b2a665Smaxv */
5538b2a665Smaxv int
nvmm_vcpu_dump(struct nvmm_machine * mach,struct nvmm_vcpu * vcpu)56d1002cd7Smaxv nvmm_vcpu_dump(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu)
5738b2a665Smaxv {
58d1002cd7Smaxv struct nvmm_x64_state *state = vcpu->state;
597a4f551dSmaxv uint16_t *attr;
6038b2a665Smaxv size_t i;
6138b2a665Smaxv int ret;
6238b2a665Smaxv
6338b2a665Smaxv const char *segnames[] = {
647a4f551dSmaxv "ES", "CS", "SS", "DS", "FS", "GS", "GDT", "IDT", "LDT", "TR"
6538b2a665Smaxv };
6638b2a665Smaxv
67d1002cd7Smaxv ret = nvmm_vcpu_getstate(mach, vcpu, NVMM_X64_STATE_ALL);
6838b2a665Smaxv if (ret == -1)
6938b2a665Smaxv return -1;
7038b2a665Smaxv
71d1002cd7Smaxv printf("+ VCPU id=%d\n", (int)vcpu->cpuid);
72d1002cd7Smaxv printf("| -> RAX=%"PRIx64"\n", state->gprs[NVMM_X64_GPR_RAX]);
73d1002cd7Smaxv printf("| -> RCX=%"PRIx64"\n", state->gprs[NVMM_X64_GPR_RCX]);
74fabc9bf2Smaxv printf("| -> RDX=%"PRIx64"\n", state->gprs[NVMM_X64_GPR_RDX]);
75fabc9bf2Smaxv printf("| -> RBX=%"PRIx64"\n", state->gprs[NVMM_X64_GPR_RBX]);
76fabc9bf2Smaxv printf("| -> RSP=%"PRIx64"\n", state->gprs[NVMM_X64_GPR_RSP]);
77fabc9bf2Smaxv printf("| -> RBP=%"PRIx64"\n", state->gprs[NVMM_X64_GPR_RBP]);
78fabc9bf2Smaxv printf("| -> RSI=%"PRIx64"\n", state->gprs[NVMM_X64_GPR_RSI]);
79fabc9bf2Smaxv printf("| -> RDI=%"PRIx64"\n", state->gprs[NVMM_X64_GPR_RDI]);
80fabc9bf2Smaxv printf("| -> RIP=%"PRIx64"\n", state->gprs[NVMM_X64_GPR_RIP]);
81d1002cd7Smaxv printf("| -> RFLAGS=%p\n", (void *)state->gprs[NVMM_X64_GPR_RFLAGS]);
8238b2a665Smaxv for (i = 0; i < NVMM_X64_NSEG; i++) {
83d1002cd7Smaxv attr = (uint16_t *)&state->segs[i].attrib;
84fabc9bf2Smaxv printf("| -> %s: sel=0x%x base=%"PRIx64", limit=%x, "
85fabc9bf2Smaxv "attrib=%x [type=%d,l=%d,def=%d]\n",
8638b2a665Smaxv segnames[i],
87d1002cd7Smaxv state->segs[i].selector,
88d1002cd7Smaxv state->segs[i].base,
89d1002cd7Smaxv state->segs[i].limit,
90fabc9bf2Smaxv *attr,
91fabc9bf2Smaxv state->segs[i].attrib.type,
92fabc9bf2Smaxv state->segs[i].attrib.l,
93fabc9bf2Smaxv state->segs[i].attrib.def);
9438b2a665Smaxv }
95d1002cd7Smaxv printf("| -> MSR_EFER=%"PRIx64"\n", state->msrs[NVMM_X64_MSR_EFER]);
96d1002cd7Smaxv printf("| -> CR0=%"PRIx64"\n", state->crs[NVMM_X64_CR_CR0]);
97d1002cd7Smaxv printf("| -> CR3=%"PRIx64"\n", state->crs[NVMM_X64_CR_CR3]);
98d1002cd7Smaxv printf("| -> CR4=%"PRIx64"\n", state->crs[NVMM_X64_CR_CR4]);
99d1002cd7Smaxv printf("| -> CR8=%"PRIx64"\n", state->crs[NVMM_X64_CR_CR8]);
10038b2a665Smaxv
10138b2a665Smaxv return 0;
10238b2a665Smaxv }
10338b2a665Smaxv
1042760ca24Smaxv /* -------------------------------------------------------------------------- */
1052760ca24Smaxv
1062760ca24Smaxv #define PTE32_L1_SHIFT 12
1072760ca24Smaxv #define PTE32_L2_SHIFT 22
1082760ca24Smaxv
1092760ca24Smaxv #define PTE32_L2_MASK 0xffc00000
1102760ca24Smaxv #define PTE32_L1_MASK 0x003ff000
1112760ca24Smaxv
1122760ca24Smaxv #define PTE32_L2_FRAME (PTE32_L2_MASK)
1132760ca24Smaxv #define PTE32_L1_FRAME (PTE32_L2_FRAME|PTE32_L1_MASK)
1142760ca24Smaxv
1152760ca24Smaxv #define pte32_l1idx(va) (((va) & PTE32_L1_MASK) >> PTE32_L1_SHIFT)
1162760ca24Smaxv #define pte32_l2idx(va) (((va) & PTE32_L2_MASK) >> PTE32_L2_SHIFT)
1172760ca24Smaxv
11806a4f19aSmaxv #define CR3_FRAME_32BIT __BITS(31, 12)
11983ed0b5eSmaxv
1202760ca24Smaxv typedef uint32_t pte_32bit_t;
1212760ca24Smaxv
1222760ca24Smaxv static int
x86_gva_to_gpa_32bit(struct nvmm_machine * mach,uint64_t cr3,gvaddr_t gva,gpaddr_t * gpa,bool has_pse,nvmm_prot_t * prot)1232760ca24Smaxv x86_gva_to_gpa_32bit(struct nvmm_machine *mach, uint64_t cr3,
1242760ca24Smaxv gvaddr_t gva, gpaddr_t *gpa, bool has_pse, nvmm_prot_t *prot)
1252760ca24Smaxv {
1262760ca24Smaxv gpaddr_t L2gpa, L1gpa;
1272760ca24Smaxv uintptr_t L2hva, L1hva;
1282760ca24Smaxv pte_32bit_t *pdir, pte;
129e00a8e01Smaxv nvmm_prot_t pageprot;
1302760ca24Smaxv
1312760ca24Smaxv /* We begin with an RWXU access. */
1322760ca24Smaxv *prot = NVMM_PROT_ALL;
1332760ca24Smaxv
1342760ca24Smaxv /* Parse L2. */
13583ed0b5eSmaxv L2gpa = (cr3 & CR3_FRAME_32BIT);
136e00a8e01Smaxv if (nvmm_gpa_to_hva(mach, L2gpa, &L2hva, &pageprot) == -1)
1372760ca24Smaxv return -1;
1382760ca24Smaxv pdir = (pte_32bit_t *)L2hva;
1392760ca24Smaxv pte = pdir[pte32_l2idx(gva)];
14006a4f19aSmaxv if ((pte & PTE_P) == 0)
1412760ca24Smaxv return -1;
14206a4f19aSmaxv if ((pte & PTE_U) == 0)
1432760ca24Smaxv *prot &= ~NVMM_PROT_USER;
14406a4f19aSmaxv if ((pte & PTE_W) == 0)
1452760ca24Smaxv *prot &= ~NVMM_PROT_WRITE;
14606a4f19aSmaxv if ((pte & PTE_PS) && !has_pse)
1472760ca24Smaxv return -1;
14806a4f19aSmaxv if (pte & PTE_PS) {
1492760ca24Smaxv *gpa = (pte & PTE32_L2_FRAME);
15080932742Smaxv *gpa = *gpa + (gva & PTE32_L1_MASK);
1512760ca24Smaxv return 0;
1522760ca24Smaxv }
1532760ca24Smaxv
1542760ca24Smaxv /* Parse L1. */
15506a4f19aSmaxv L1gpa = (pte & PTE_FRAME);
156e00a8e01Smaxv if (nvmm_gpa_to_hva(mach, L1gpa, &L1hva, &pageprot) == -1)
1572760ca24Smaxv return -1;
1582760ca24Smaxv pdir = (pte_32bit_t *)L1hva;
1592760ca24Smaxv pte = pdir[pte32_l1idx(gva)];
16006a4f19aSmaxv if ((pte & PTE_P) == 0)
1612760ca24Smaxv return -1;
16206a4f19aSmaxv if ((pte & PTE_U) == 0)
1632760ca24Smaxv *prot &= ~NVMM_PROT_USER;
16406a4f19aSmaxv if ((pte & PTE_W) == 0)
1652760ca24Smaxv *prot &= ~NVMM_PROT_WRITE;
16606a4f19aSmaxv if (pte & PTE_PS)
1672760ca24Smaxv return -1;
1682760ca24Smaxv
16906a4f19aSmaxv *gpa = (pte & PTE_FRAME);
1702760ca24Smaxv return 0;
1712760ca24Smaxv }
1722760ca24Smaxv
1732760ca24Smaxv /* -------------------------------------------------------------------------- */
1742760ca24Smaxv
1752760ca24Smaxv #define PTE32_PAE_L1_SHIFT 12
1762760ca24Smaxv #define PTE32_PAE_L2_SHIFT 21
1772760ca24Smaxv #define PTE32_PAE_L3_SHIFT 30
1782760ca24Smaxv
1792760ca24Smaxv #define PTE32_PAE_L3_MASK 0xc0000000
1802760ca24Smaxv #define PTE32_PAE_L2_MASK 0x3fe00000
1812760ca24Smaxv #define PTE32_PAE_L1_MASK 0x001ff000
1822760ca24Smaxv
1832760ca24Smaxv #define PTE32_PAE_L3_FRAME (PTE32_PAE_L3_MASK)
1842760ca24Smaxv #define PTE32_PAE_L2_FRAME (PTE32_PAE_L3_FRAME|PTE32_PAE_L2_MASK)
1852760ca24Smaxv #define PTE32_PAE_L1_FRAME (PTE32_PAE_L2_FRAME|PTE32_PAE_L1_MASK)
1862760ca24Smaxv
1872760ca24Smaxv #define pte32_pae_l1idx(va) (((va) & PTE32_PAE_L1_MASK) >> PTE32_PAE_L1_SHIFT)
1882760ca24Smaxv #define pte32_pae_l2idx(va) (((va) & PTE32_PAE_L2_MASK) >> PTE32_PAE_L2_SHIFT)
1892760ca24Smaxv #define pte32_pae_l3idx(va) (((va) & PTE32_PAE_L3_MASK) >> PTE32_PAE_L3_SHIFT)
1902760ca24Smaxv
19183ed0b5eSmaxv #define CR3_FRAME_32BIT_PAE __BITS(31, 5)
19283ed0b5eSmaxv
1932760ca24Smaxv typedef uint64_t pte_32bit_pae_t;
1942760ca24Smaxv
1952760ca24Smaxv static int
x86_gva_to_gpa_32bit_pae(struct nvmm_machine * mach,uint64_t cr3,gvaddr_t gva,gpaddr_t * gpa,nvmm_prot_t * prot)1962760ca24Smaxv x86_gva_to_gpa_32bit_pae(struct nvmm_machine *mach, uint64_t cr3,
1972fad18ceSmaxv gvaddr_t gva, gpaddr_t *gpa, nvmm_prot_t *prot)
1982760ca24Smaxv {
1992760ca24Smaxv gpaddr_t L3gpa, L2gpa, L1gpa;
2002760ca24Smaxv uintptr_t L3hva, L2hva, L1hva;
2012760ca24Smaxv pte_32bit_pae_t *pdir, pte;
202e00a8e01Smaxv nvmm_prot_t pageprot;
2032760ca24Smaxv
2042760ca24Smaxv /* We begin with an RWXU access. */
2052760ca24Smaxv *prot = NVMM_PROT_ALL;
2062760ca24Smaxv
2072760ca24Smaxv /* Parse L3. */
20883ed0b5eSmaxv L3gpa = (cr3 & CR3_FRAME_32BIT_PAE);
209e00a8e01Smaxv if (nvmm_gpa_to_hva(mach, L3gpa, &L3hva, &pageprot) == -1)
2102760ca24Smaxv return -1;
2112760ca24Smaxv pdir = (pte_32bit_pae_t *)L3hva;
2122760ca24Smaxv pte = pdir[pte32_pae_l3idx(gva)];
21306a4f19aSmaxv if ((pte & PTE_P) == 0)
2142760ca24Smaxv return -1;
21506a4f19aSmaxv if (pte & PTE_NX)
2162760ca24Smaxv *prot &= ~NVMM_PROT_EXEC;
21706a4f19aSmaxv if (pte & PTE_PS)
2182760ca24Smaxv return -1;
2192760ca24Smaxv
2202760ca24Smaxv /* Parse L2. */
22106a4f19aSmaxv L2gpa = (pte & PTE_FRAME);
222e00a8e01Smaxv if (nvmm_gpa_to_hva(mach, L2gpa, &L2hva, &pageprot) == -1)
2232760ca24Smaxv return -1;
2242760ca24Smaxv pdir = (pte_32bit_pae_t *)L2hva;
2252760ca24Smaxv pte = pdir[pte32_pae_l2idx(gva)];
22606a4f19aSmaxv if ((pte & PTE_P) == 0)
2272760ca24Smaxv return -1;
22806a4f19aSmaxv if ((pte & PTE_U) == 0)
2292760ca24Smaxv *prot &= ~NVMM_PROT_USER;
23006a4f19aSmaxv if ((pte & PTE_W) == 0)
2312760ca24Smaxv *prot &= ~NVMM_PROT_WRITE;
23206a4f19aSmaxv if (pte & PTE_NX)
2332760ca24Smaxv *prot &= ~NVMM_PROT_EXEC;
23406a4f19aSmaxv if (pte & PTE_PS) {
2352760ca24Smaxv *gpa = (pte & PTE32_PAE_L2_FRAME);
23680932742Smaxv *gpa = *gpa + (gva & PTE32_PAE_L1_MASK);
2372760ca24Smaxv return 0;
2382760ca24Smaxv }
2392760ca24Smaxv
2402760ca24Smaxv /* Parse L1. */
24106a4f19aSmaxv L1gpa = (pte & PTE_FRAME);
242e00a8e01Smaxv if (nvmm_gpa_to_hva(mach, L1gpa, &L1hva, &pageprot) == -1)
2432760ca24Smaxv return -1;
2442760ca24Smaxv pdir = (pte_32bit_pae_t *)L1hva;
2452760ca24Smaxv pte = pdir[pte32_pae_l1idx(gva)];
24606a4f19aSmaxv if ((pte & PTE_P) == 0)
2472760ca24Smaxv return -1;
24806a4f19aSmaxv if ((pte & PTE_U) == 0)
2492760ca24Smaxv *prot &= ~NVMM_PROT_USER;
25006a4f19aSmaxv if ((pte & PTE_W) == 0)
2512760ca24Smaxv *prot &= ~NVMM_PROT_WRITE;
25206a4f19aSmaxv if (pte & PTE_NX)
2532760ca24Smaxv *prot &= ~NVMM_PROT_EXEC;
25406a4f19aSmaxv if (pte & PTE_PS)
2552760ca24Smaxv return -1;
2562760ca24Smaxv
25706a4f19aSmaxv *gpa = (pte & PTE_FRAME);
2582760ca24Smaxv return 0;
2592760ca24Smaxv }
2602760ca24Smaxv
2612760ca24Smaxv /* -------------------------------------------------------------------------- */
2622760ca24Smaxv
2632760ca24Smaxv #define PTE64_L1_SHIFT 12
2642760ca24Smaxv #define PTE64_L2_SHIFT 21
2652760ca24Smaxv #define PTE64_L3_SHIFT 30
2662760ca24Smaxv #define PTE64_L4_SHIFT 39
2672760ca24Smaxv
2682760ca24Smaxv #define PTE64_L4_MASK 0x0000ff8000000000
2692760ca24Smaxv #define PTE64_L3_MASK 0x0000007fc0000000
2702760ca24Smaxv #define PTE64_L2_MASK 0x000000003fe00000
2712760ca24Smaxv #define PTE64_L1_MASK 0x00000000001ff000
2722760ca24Smaxv
2732760ca24Smaxv #define PTE64_L4_FRAME PTE64_L4_MASK
2742760ca24Smaxv #define PTE64_L3_FRAME (PTE64_L4_FRAME|PTE64_L3_MASK)
2752760ca24Smaxv #define PTE64_L2_FRAME (PTE64_L3_FRAME|PTE64_L2_MASK)
2762760ca24Smaxv #define PTE64_L1_FRAME (PTE64_L2_FRAME|PTE64_L1_MASK)
2772760ca24Smaxv
2782760ca24Smaxv #define pte64_l1idx(va) (((va) & PTE64_L1_MASK) >> PTE64_L1_SHIFT)
2792760ca24Smaxv #define pte64_l2idx(va) (((va) & PTE64_L2_MASK) >> PTE64_L2_SHIFT)
2802760ca24Smaxv #define pte64_l3idx(va) (((va) & PTE64_L3_MASK) >> PTE64_L3_SHIFT)
2812760ca24Smaxv #define pte64_l4idx(va) (((va) & PTE64_L4_MASK) >> PTE64_L4_SHIFT)
2822760ca24Smaxv
28306a4f19aSmaxv #define CR3_FRAME_64BIT __BITS(51, 12)
28483ed0b5eSmaxv
2852760ca24Smaxv typedef uint64_t pte_64bit_t;
2862760ca24Smaxv
2872760ca24Smaxv static inline bool
x86_gva_64bit_canonical(gvaddr_t gva)2882760ca24Smaxv x86_gva_64bit_canonical(gvaddr_t gva)
2892760ca24Smaxv {
2902760ca24Smaxv /* Bits 63:47 must have the same value. */
2912760ca24Smaxv #define SIGN_EXTEND 0xffff800000000000ULL
2922760ca24Smaxv return (gva & SIGN_EXTEND) == 0 || (gva & SIGN_EXTEND) == SIGN_EXTEND;
2932760ca24Smaxv }
2942760ca24Smaxv
2952760ca24Smaxv static int
x86_gva_to_gpa_64bit(struct nvmm_machine * mach,uint64_t cr3,gvaddr_t gva,gpaddr_t * gpa,nvmm_prot_t * prot)2962760ca24Smaxv x86_gva_to_gpa_64bit(struct nvmm_machine *mach, uint64_t cr3,
297960d1f76Smaxv gvaddr_t gva, gpaddr_t *gpa, nvmm_prot_t *prot)
2982760ca24Smaxv {
2992760ca24Smaxv gpaddr_t L4gpa, L3gpa, L2gpa, L1gpa;
3002760ca24Smaxv uintptr_t L4hva, L3hva, L2hva, L1hva;
3012760ca24Smaxv pte_64bit_t *pdir, pte;
302e00a8e01Smaxv nvmm_prot_t pageprot;
3032760ca24Smaxv
3042760ca24Smaxv /* We begin with an RWXU access. */
3052760ca24Smaxv *prot = NVMM_PROT_ALL;
3062760ca24Smaxv
3072760ca24Smaxv if (!x86_gva_64bit_canonical(gva))
3082760ca24Smaxv return -1;
3092760ca24Smaxv
3102760ca24Smaxv /* Parse L4. */
31183ed0b5eSmaxv L4gpa = (cr3 & CR3_FRAME_64BIT);
312e00a8e01Smaxv if (nvmm_gpa_to_hva(mach, L4gpa, &L4hva, &pageprot) == -1)
3132760ca24Smaxv return -1;
3142760ca24Smaxv pdir = (pte_64bit_t *)L4hva;
3152760ca24Smaxv pte = pdir[pte64_l4idx(gva)];
31606a4f19aSmaxv if ((pte & PTE_P) == 0)
3172760ca24Smaxv return -1;
31806a4f19aSmaxv if ((pte & PTE_U) == 0)
3192760ca24Smaxv *prot &= ~NVMM_PROT_USER;
32006a4f19aSmaxv if ((pte & PTE_W) == 0)
3212760ca24Smaxv *prot &= ~NVMM_PROT_WRITE;
32206a4f19aSmaxv if (pte & PTE_NX)
3232760ca24Smaxv *prot &= ~NVMM_PROT_EXEC;
32406a4f19aSmaxv if (pte & PTE_PS)
3252760ca24Smaxv return -1;
3262760ca24Smaxv
3272760ca24Smaxv /* Parse L3. */
32806a4f19aSmaxv L3gpa = (pte & PTE_FRAME);
329e00a8e01Smaxv if (nvmm_gpa_to_hva(mach, L3gpa, &L3hva, &pageprot) == -1)
3302760ca24Smaxv return -1;
3312760ca24Smaxv pdir = (pte_64bit_t *)L3hva;
3322760ca24Smaxv pte = pdir[pte64_l3idx(gva)];
33306a4f19aSmaxv if ((pte & PTE_P) == 0)
3342760ca24Smaxv return -1;
33506a4f19aSmaxv if ((pte & PTE_U) == 0)
3362760ca24Smaxv *prot &= ~NVMM_PROT_USER;
33706a4f19aSmaxv if ((pte & PTE_W) == 0)
3382760ca24Smaxv *prot &= ~NVMM_PROT_WRITE;
33906a4f19aSmaxv if (pte & PTE_NX)
3402760ca24Smaxv *prot &= ~NVMM_PROT_EXEC;
34106a4f19aSmaxv if (pte & PTE_PS) {
3422760ca24Smaxv *gpa = (pte & PTE64_L3_FRAME);
34380932742Smaxv *gpa = *gpa + (gva & (PTE64_L2_MASK|PTE64_L1_MASK));
3442760ca24Smaxv return 0;
3452760ca24Smaxv }
3462760ca24Smaxv
3472760ca24Smaxv /* Parse L2. */
34806a4f19aSmaxv L2gpa = (pte & PTE_FRAME);
349e00a8e01Smaxv if (nvmm_gpa_to_hva(mach, L2gpa, &L2hva, &pageprot) == -1)
3502760ca24Smaxv return -1;
3512760ca24Smaxv pdir = (pte_64bit_t *)L2hva;
3522760ca24Smaxv pte = pdir[pte64_l2idx(gva)];
35306a4f19aSmaxv if ((pte & PTE_P) == 0)
3542760ca24Smaxv return -1;
35506a4f19aSmaxv if ((pte & PTE_U) == 0)
3562760ca24Smaxv *prot &= ~NVMM_PROT_USER;
35706a4f19aSmaxv if ((pte & PTE_W) == 0)
3582760ca24Smaxv *prot &= ~NVMM_PROT_WRITE;
35906a4f19aSmaxv if (pte & PTE_NX)
3602760ca24Smaxv *prot &= ~NVMM_PROT_EXEC;
36106a4f19aSmaxv if (pte & PTE_PS) {
3622760ca24Smaxv *gpa = (pte & PTE64_L2_FRAME);
36380932742Smaxv *gpa = *gpa + (gva & PTE64_L1_MASK);
3642760ca24Smaxv return 0;
3652760ca24Smaxv }
3662760ca24Smaxv
3672760ca24Smaxv /* Parse L1. */
36806a4f19aSmaxv L1gpa = (pte & PTE_FRAME);
369e00a8e01Smaxv if (nvmm_gpa_to_hva(mach, L1gpa, &L1hva, &pageprot) == -1)
3702760ca24Smaxv return -1;
3712760ca24Smaxv pdir = (pte_64bit_t *)L1hva;
3722760ca24Smaxv pte = pdir[pte64_l1idx(gva)];
37306a4f19aSmaxv if ((pte & PTE_P) == 0)
3742760ca24Smaxv return -1;
37506a4f19aSmaxv if ((pte & PTE_U) == 0)
3762760ca24Smaxv *prot &= ~NVMM_PROT_USER;
37706a4f19aSmaxv if ((pte & PTE_W) == 0)
3782760ca24Smaxv *prot &= ~NVMM_PROT_WRITE;
37906a4f19aSmaxv if (pte & PTE_NX)
3802760ca24Smaxv *prot &= ~NVMM_PROT_EXEC;
38106a4f19aSmaxv if (pte & PTE_PS)
3822760ca24Smaxv return -1;
3832760ca24Smaxv
38406a4f19aSmaxv *gpa = (pte & PTE_FRAME);
3852760ca24Smaxv return 0;
3862760ca24Smaxv }
3872760ca24Smaxv
3882760ca24Smaxv static inline int
x86_gva_to_gpa(struct nvmm_machine * mach,struct nvmm_x64_state * state,gvaddr_t gva,gpaddr_t * gpa,nvmm_prot_t * prot)3892760ca24Smaxv x86_gva_to_gpa(struct nvmm_machine *mach, struct nvmm_x64_state *state,
3902760ca24Smaxv gvaddr_t gva, gpaddr_t *gpa, nvmm_prot_t *prot)
3912760ca24Smaxv {
3922760ca24Smaxv bool is_pae, is_lng, has_pse;
3932760ca24Smaxv uint64_t cr3;
39438b2a665Smaxv size_t off;
3952760ca24Smaxv int ret;
3962760ca24Smaxv
3972760ca24Smaxv if ((state->crs[NVMM_X64_CR_CR0] & CR0_PG) == 0) {
3982760ca24Smaxv /* No paging. */
39907310f30Smaxv *prot = NVMM_PROT_ALL;
4002760ca24Smaxv *gpa = gva;
4012760ca24Smaxv return 0;
4022760ca24Smaxv }
4032760ca24Smaxv
40438b2a665Smaxv off = (gva & PAGE_MASK);
40538b2a665Smaxv gva &= ~PAGE_MASK;
40638b2a665Smaxv
4072760ca24Smaxv is_pae = (state->crs[NVMM_X64_CR_CR4] & CR4_PAE) != 0;
4087ceb32d3Smaxv is_lng = (state->msrs[NVMM_X64_MSR_EFER] & EFER_LMA) != 0;
4092760ca24Smaxv has_pse = (state->crs[NVMM_X64_CR_CR4] & CR4_PSE) != 0;
4102760ca24Smaxv cr3 = state->crs[NVMM_X64_CR_CR3];
4112760ca24Smaxv
4122760ca24Smaxv if (is_pae && is_lng) {
4132760ca24Smaxv /* 64bit */
414960d1f76Smaxv ret = x86_gva_to_gpa_64bit(mach, cr3, gva, gpa, prot);
4152760ca24Smaxv } else if (is_pae && !is_lng) {
4162760ca24Smaxv /* 32bit PAE */
4172fad18ceSmaxv ret = x86_gva_to_gpa_32bit_pae(mach, cr3, gva, gpa, prot);
4182760ca24Smaxv } else if (!is_pae && !is_lng) {
4192760ca24Smaxv /* 32bit */
4202760ca24Smaxv ret = x86_gva_to_gpa_32bit(mach, cr3, gva, gpa, has_pse, prot);
4212760ca24Smaxv } else {
4222760ca24Smaxv ret = -1;
4232760ca24Smaxv }
4242760ca24Smaxv
4252760ca24Smaxv if (ret == -1) {
4262760ca24Smaxv errno = EFAULT;
4272760ca24Smaxv }
4282760ca24Smaxv
42938b2a665Smaxv *gpa = *gpa + off;
43038b2a665Smaxv
4312760ca24Smaxv return ret;
4322760ca24Smaxv }
4332760ca24Smaxv
4342760ca24Smaxv int
nvmm_gva_to_gpa(struct nvmm_machine * mach,struct nvmm_vcpu * vcpu,gvaddr_t gva,gpaddr_t * gpa,nvmm_prot_t * prot)435d1002cd7Smaxv nvmm_gva_to_gpa(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu,
4362760ca24Smaxv gvaddr_t gva, gpaddr_t *gpa, nvmm_prot_t *prot)
4372760ca24Smaxv {
438d1002cd7Smaxv struct nvmm_x64_state *state = vcpu->state;
4392760ca24Smaxv int ret;
4402760ca24Smaxv
441d1002cd7Smaxv ret = nvmm_vcpu_getstate(mach, vcpu,
4422760ca24Smaxv NVMM_X64_STATE_CRS | NVMM_X64_STATE_MSRS);
4432760ca24Smaxv if (ret == -1)
4442760ca24Smaxv return -1;
4452760ca24Smaxv
446d1002cd7Smaxv return x86_gva_to_gpa(mach, state, gva, gpa, prot);
4472760ca24Smaxv }
4482760ca24Smaxv
4492760ca24Smaxv /* -------------------------------------------------------------------------- */
4502760ca24Smaxv
451416eaf02Smaxv #define DISASSEMBLER_BUG() \
452416eaf02Smaxv do { \
453416eaf02Smaxv errno = EINVAL; \
454416eaf02Smaxv return -1; \
455416eaf02Smaxv } while (0);
456416eaf02Smaxv
4572760ca24Smaxv static inline bool
is_long_mode(struct nvmm_x64_state * state)4587ceb32d3Smaxv is_long_mode(struct nvmm_x64_state *state)
4597ceb32d3Smaxv {
4607ceb32d3Smaxv return (state->msrs[NVMM_X64_MSR_EFER] & EFER_LMA) != 0;
4617ceb32d3Smaxv }
4627ceb32d3Smaxv
4637ceb32d3Smaxv static inline bool
is_64bit(struct nvmm_x64_state * state)4643f62f34aSmaxv is_64bit(struct nvmm_x64_state *state)
4653f62f34aSmaxv {
4667a4f551dSmaxv return (state->segs[NVMM_X64_SEG_CS].attrib.l != 0);
4673f62f34aSmaxv }
4683f62f34aSmaxv
4693f62f34aSmaxv static inline bool
is_32bit(struct nvmm_x64_state * state)4703f62f34aSmaxv is_32bit(struct nvmm_x64_state *state)
4713f62f34aSmaxv {
4727a4f551dSmaxv return (state->segs[NVMM_X64_SEG_CS].attrib.l == 0) &&
4737a4f551dSmaxv (state->segs[NVMM_X64_SEG_CS].attrib.def == 1);
4743f62f34aSmaxv }
4753f62f34aSmaxv
4763f62f34aSmaxv static inline bool
is_16bit(struct nvmm_x64_state * state)4773f62f34aSmaxv is_16bit(struct nvmm_x64_state *state)
4783f62f34aSmaxv {
4797a4f551dSmaxv return (state->segs[NVMM_X64_SEG_CS].attrib.l == 0) &&
4807a4f551dSmaxv (state->segs[NVMM_X64_SEG_CS].attrib.def == 0);
4813f62f34aSmaxv }
4823f62f34aSmaxv
4832760ca24Smaxv static int
segment_check(struct nvmm_x64_state_seg * seg,gvaddr_t gva,size_t size)4847ceb32d3Smaxv segment_check(struct nvmm_x64_state_seg *seg, gvaddr_t gva, size_t size)
4852760ca24Smaxv {
4862760ca24Smaxv uint64_t limit;
4872760ca24Smaxv
4882760ca24Smaxv /*
4892760ca24Smaxv * This is incomplete. We should check topdown, etc, really that's
4902760ca24Smaxv * tiring.
4912760ca24Smaxv */
4922760ca24Smaxv if (__predict_false(!seg->attrib.p)) {
4932760ca24Smaxv goto error;
4942760ca24Smaxv }
4952760ca24Smaxv
4967a4f551dSmaxv limit = (uint64_t)seg->limit + 1;
4977a4f551dSmaxv if (__predict_true(seg->attrib.g)) {
4982760ca24Smaxv limit *= PAGE_SIZE;
4992760ca24Smaxv }
5002760ca24Smaxv
5017ceb32d3Smaxv if (__predict_false(gva + size > limit)) {
5022760ca24Smaxv goto error;
5032760ca24Smaxv }
5042760ca24Smaxv
5052760ca24Smaxv return 0;
5062760ca24Smaxv
5072760ca24Smaxv error:
5082760ca24Smaxv errno = EFAULT;
5092760ca24Smaxv return -1;
5102760ca24Smaxv }
5112760ca24Smaxv
5127ceb32d3Smaxv static inline void
segment_apply(struct nvmm_x64_state_seg * seg,gvaddr_t * gva)5137ceb32d3Smaxv segment_apply(struct nvmm_x64_state_seg *seg, gvaddr_t *gva)
51438b2a665Smaxv {
5157ceb32d3Smaxv *gva += seg->base;
5167ceb32d3Smaxv }
5177ceb32d3Smaxv
5187ceb32d3Smaxv static inline uint64_t
size_to_mask(size_t size)5197ceb32d3Smaxv size_to_mask(size_t size)
5207ceb32d3Smaxv {
5217ceb32d3Smaxv switch (size) {
5227ceb32d3Smaxv case 1:
5237ceb32d3Smaxv return 0x00000000000000FF;
5247ceb32d3Smaxv case 2:
5257ceb32d3Smaxv return 0x000000000000FFFF;
52638b2a665Smaxv case 4:
52738b2a665Smaxv return 0x00000000FFFFFFFF;
5287ceb32d3Smaxv case 8:
5297ceb32d3Smaxv default:
5307ceb32d3Smaxv return 0xFFFFFFFFFFFFFFFF;
53138b2a665Smaxv }
53238b2a665Smaxv }
53338b2a665Smaxv
53438b2a665Smaxv static uint64_t
rep_get_cnt(struct nvmm_x64_state * state,size_t adsize)53580932742Smaxv rep_get_cnt(struct nvmm_x64_state *state, size_t adsize)
53680932742Smaxv {
53780932742Smaxv uint64_t mask, cnt;
53880932742Smaxv
5397ceb32d3Smaxv mask = size_to_mask(adsize);
54080932742Smaxv cnt = state->gprs[NVMM_X64_GPR_RCX] & mask;
54180932742Smaxv
54280932742Smaxv return cnt;
54380932742Smaxv }
54480932742Smaxv
54580932742Smaxv static void
rep_set_cnt(struct nvmm_x64_state * state,size_t adsize,uint64_t cnt)54680932742Smaxv rep_set_cnt(struct nvmm_x64_state *state, size_t adsize, uint64_t cnt)
54780932742Smaxv {
54880932742Smaxv uint64_t mask;
54980932742Smaxv
5507ceb32d3Smaxv /* XXX: should we zero-extend? */
5517ceb32d3Smaxv mask = size_to_mask(adsize);
55280932742Smaxv state->gprs[NVMM_X64_GPR_RCX] &= ~mask;
55380932742Smaxv state->gprs[NVMM_X64_GPR_RCX] |= cnt;
55480932742Smaxv }
55580932742Smaxv
55638b2a665Smaxv static int
read_guest_memory(struct nvmm_machine * mach,struct nvmm_vcpu * vcpu,gvaddr_t gva,uint8_t * data,size_t size)557e6f32a58Smaxv read_guest_memory(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu,
55838b2a665Smaxv gvaddr_t gva, uint8_t *data, size_t size)
55938b2a665Smaxv {
560e6f32a58Smaxv struct nvmm_x64_state *state = vcpu->state;
56138b2a665Smaxv struct nvmm_mem mem;
56238b2a665Smaxv nvmm_prot_t prot;
56338b2a665Smaxv gpaddr_t gpa;
56438b2a665Smaxv uintptr_t hva;
56538b2a665Smaxv bool is_mmio;
56638b2a665Smaxv int ret, remain;
56738b2a665Smaxv
56838b2a665Smaxv ret = x86_gva_to_gpa(mach, state, gva, &gpa, &prot);
56938b2a665Smaxv if (__predict_false(ret == -1)) {
57038b2a665Smaxv return -1;
57138b2a665Smaxv }
57238b2a665Smaxv if (__predict_false(!(prot & NVMM_PROT_READ))) {
57338b2a665Smaxv errno = EFAULT;
57438b2a665Smaxv return -1;
57538b2a665Smaxv }
57638b2a665Smaxv
57738b2a665Smaxv if ((gva & PAGE_MASK) + size > PAGE_SIZE) {
57838b2a665Smaxv remain = ((gva & PAGE_MASK) + size - PAGE_SIZE);
57938b2a665Smaxv } else {
58038b2a665Smaxv remain = 0;
58138b2a665Smaxv }
58238b2a665Smaxv size -= remain;
58338b2a665Smaxv
584e00a8e01Smaxv ret = nvmm_gpa_to_hva(mach, gpa, &hva, &prot);
58538b2a665Smaxv is_mmio = (ret == -1);
58638b2a665Smaxv
58738b2a665Smaxv if (is_mmio) {
588e6f32a58Smaxv mem.mach = mach;
589e6f32a58Smaxv mem.vcpu = vcpu;
590960d1f76Smaxv mem.data = data;
59138b2a665Smaxv mem.gpa = gpa;
59238b2a665Smaxv mem.write = false;
59338b2a665Smaxv mem.size = size;
594e6f32a58Smaxv (*vcpu->cbs.mem)(&mem);
59538b2a665Smaxv } else {
596e00a8e01Smaxv if (__predict_false(!(prot & NVMM_PROT_READ))) {
597e00a8e01Smaxv errno = EFAULT;
598e00a8e01Smaxv return -1;
599e00a8e01Smaxv }
60038b2a665Smaxv memcpy(data, (uint8_t *)hva, size);
60138b2a665Smaxv }
60238b2a665Smaxv
60338b2a665Smaxv if (remain > 0) {
604e6f32a58Smaxv ret = read_guest_memory(mach, vcpu, gva + size,
60538b2a665Smaxv data + size, remain);
60638b2a665Smaxv } else {
60738b2a665Smaxv ret = 0;
60838b2a665Smaxv }
60938b2a665Smaxv
61038b2a665Smaxv return ret;
61138b2a665Smaxv }
61238b2a665Smaxv
61338b2a665Smaxv static int
write_guest_memory(struct nvmm_machine * mach,struct nvmm_vcpu * vcpu,gvaddr_t gva,uint8_t * data,size_t size)614e6f32a58Smaxv write_guest_memory(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu,
61538b2a665Smaxv gvaddr_t gva, uint8_t *data, size_t size)
61638b2a665Smaxv {
617e6f32a58Smaxv struct nvmm_x64_state *state = vcpu->state;
61838b2a665Smaxv struct nvmm_mem mem;
61938b2a665Smaxv nvmm_prot_t prot;
62038b2a665Smaxv gpaddr_t gpa;
62138b2a665Smaxv uintptr_t hva;
62238b2a665Smaxv bool is_mmio;
62338b2a665Smaxv int ret, remain;
62438b2a665Smaxv
62538b2a665Smaxv ret = x86_gva_to_gpa(mach, state, gva, &gpa, &prot);
62638b2a665Smaxv if (__predict_false(ret == -1)) {
62738b2a665Smaxv return -1;
62838b2a665Smaxv }
62938b2a665Smaxv if (__predict_false(!(prot & NVMM_PROT_WRITE))) {
63038b2a665Smaxv errno = EFAULT;
63138b2a665Smaxv return -1;
63238b2a665Smaxv }
63338b2a665Smaxv
63438b2a665Smaxv if ((gva & PAGE_MASK) + size > PAGE_SIZE) {
63538b2a665Smaxv remain = ((gva & PAGE_MASK) + size - PAGE_SIZE);
63638b2a665Smaxv } else {
63738b2a665Smaxv remain = 0;
63838b2a665Smaxv }
63938b2a665Smaxv size -= remain;
64038b2a665Smaxv
641e00a8e01Smaxv ret = nvmm_gpa_to_hva(mach, gpa, &hva, &prot);
64238b2a665Smaxv is_mmio = (ret == -1);
64338b2a665Smaxv
64438b2a665Smaxv if (is_mmio) {
645e6f32a58Smaxv mem.mach = mach;
646e6f32a58Smaxv mem.vcpu = vcpu;
647960d1f76Smaxv mem.data = data;
64838b2a665Smaxv mem.gpa = gpa;
64938b2a665Smaxv mem.write = true;
65038b2a665Smaxv mem.size = size;
651e6f32a58Smaxv (*vcpu->cbs.mem)(&mem);
65238b2a665Smaxv } else {
653e00a8e01Smaxv if (__predict_false(!(prot & NVMM_PROT_WRITE))) {
654e00a8e01Smaxv errno = EFAULT;
655e00a8e01Smaxv return -1;
656e00a8e01Smaxv }
65738b2a665Smaxv memcpy((uint8_t *)hva, data, size);
65838b2a665Smaxv }
65938b2a665Smaxv
66038b2a665Smaxv if (remain > 0) {
661e6f32a58Smaxv ret = write_guest_memory(mach, vcpu, gva + size,
66238b2a665Smaxv data + size, remain);
66338b2a665Smaxv } else {
66438b2a665Smaxv ret = 0;
66538b2a665Smaxv }
66638b2a665Smaxv
66738b2a665Smaxv return ret;
66838b2a665Smaxv }
66938b2a665Smaxv
67038b2a665Smaxv /* -------------------------------------------------------------------------- */
67138b2a665Smaxv
672e6f32a58Smaxv static int fetch_segment(struct nvmm_machine *, struct nvmm_vcpu *);
673579fb479Smaxv
67480932742Smaxv #define NVMM_IO_BATCH_SIZE 32
67580932742Smaxv
67680932742Smaxv static int
assist_io_batch(struct nvmm_machine * mach,struct nvmm_vcpu * vcpu,struct nvmm_io * io,gvaddr_t gva,uint64_t cnt)677e6f32a58Smaxv assist_io_batch(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu,
67880932742Smaxv struct nvmm_io *io, gvaddr_t gva, uint64_t cnt)
67980932742Smaxv {
68080932742Smaxv uint8_t iobuf[NVMM_IO_BATCH_SIZE];
68180932742Smaxv size_t i, iosize, iocnt;
68280932742Smaxv int ret;
68380932742Smaxv
68480932742Smaxv cnt = MIN(cnt, NVMM_IO_BATCH_SIZE);
68580932742Smaxv iosize = MIN(io->size * cnt, NVMM_IO_BATCH_SIZE);
68680932742Smaxv iocnt = iosize / io->size;
68780932742Smaxv
68880932742Smaxv io->data = iobuf;
68980932742Smaxv
69080932742Smaxv if (!io->in) {
691e6f32a58Smaxv ret = read_guest_memory(mach, vcpu, gva, iobuf, iosize);
69280932742Smaxv if (ret == -1)
69380932742Smaxv return -1;
69480932742Smaxv }
69580932742Smaxv
69680932742Smaxv for (i = 0; i < iocnt; i++) {
697e6f32a58Smaxv (*vcpu->cbs.io)(io);
69880932742Smaxv io->data += io->size;
69980932742Smaxv }
70080932742Smaxv
70180932742Smaxv if (io->in) {
702e6f32a58Smaxv ret = write_guest_memory(mach, vcpu, gva, iobuf, iosize);
70380932742Smaxv if (ret == -1)
70480932742Smaxv return -1;
70580932742Smaxv }
70680932742Smaxv
70780932742Smaxv return iocnt;
70880932742Smaxv }
70980932742Smaxv
7102760ca24Smaxv int
nvmm_assist_io(struct nvmm_machine * mach,struct nvmm_vcpu * vcpu)711d1002cd7Smaxv nvmm_assist_io(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu)
7122760ca24Smaxv {
713d1002cd7Smaxv struct nvmm_x64_state *state = vcpu->state;
714f9fb7866Smaxv struct nvmm_vcpu_exit *exit = vcpu->exit;
7152760ca24Smaxv struct nvmm_io io;
71680932742Smaxv uint64_t cnt = 0; /* GCC */
71780932742Smaxv uint8_t iobuf[8];
71880932742Smaxv int iocnt = 1;
7197ceb32d3Smaxv gvaddr_t gva = 0; /* GCC */
7203f62f34aSmaxv int reg = 0; /* GCC */
721579fb479Smaxv int ret, seg;
72280932742Smaxv bool psld = false;
7232760ca24Smaxv
724f9fb7866Smaxv if (__predict_false(exit->reason != NVMM_VCPU_EXIT_IO)) {
7252760ca24Smaxv errno = EINVAL;
7262760ca24Smaxv return -1;
7272760ca24Smaxv }
7282760ca24Smaxv
729e6f32a58Smaxv io.mach = mach;
730e6f32a58Smaxv io.vcpu = vcpu;
7312760ca24Smaxv io.port = exit->u.io.port;
732f9fb7866Smaxv io.in = exit->u.io.in;
7332760ca24Smaxv io.size = exit->u.io.operand_size;
73480932742Smaxv io.data = iobuf;
7352760ca24Smaxv
736d1002cd7Smaxv ret = nvmm_vcpu_getstate(mach, vcpu,
7372760ca24Smaxv NVMM_X64_STATE_GPRS | NVMM_X64_STATE_SEGS |
7382760ca24Smaxv NVMM_X64_STATE_CRS | NVMM_X64_STATE_MSRS);
7392760ca24Smaxv if (ret == -1)
7402760ca24Smaxv return -1;
7412760ca24Smaxv
74280932742Smaxv if (exit->u.io.rep) {
743d1002cd7Smaxv cnt = rep_get_cnt(state, exit->u.io.address_size);
74480932742Smaxv if (__predict_false(cnt == 0)) {
745d1002cd7Smaxv state->gprs[NVMM_X64_GPR_RIP] = exit->u.io.npc;
7467ceb32d3Smaxv goto out;
74780932742Smaxv }
74880932742Smaxv }
74980932742Smaxv
750d1002cd7Smaxv if (__predict_false(state->gprs[NVMM_X64_GPR_RFLAGS] & PSL_D)) {
75180932742Smaxv psld = true;
75280932742Smaxv }
75380932742Smaxv
75438b2a665Smaxv /*
75538b2a665Smaxv * Determine GVA.
75638b2a665Smaxv */
75738b2a665Smaxv if (exit->u.io.str) {
7583f62f34aSmaxv if (io.in) {
7593f62f34aSmaxv reg = NVMM_X64_GPR_RDI;
7603f62f34aSmaxv } else {
7613f62f34aSmaxv reg = NVMM_X64_GPR_RSI;
7623f62f34aSmaxv }
7632760ca24Smaxv
764d1002cd7Smaxv gva = state->gprs[reg];
7657ceb32d3Smaxv gva &= size_to_mask(exit->u.io.address_size);
7662760ca24Smaxv
767579fb479Smaxv if (exit->u.io.seg != -1) {
768579fb479Smaxv seg = exit->u.io.seg;
769579fb479Smaxv } else {
770579fb479Smaxv if (io.in) {
771579fb479Smaxv seg = NVMM_X64_SEG_ES;
772579fb479Smaxv } else {
773e6f32a58Smaxv seg = fetch_segment(mach, vcpu);
774579fb479Smaxv if (seg == -1)
775579fb479Smaxv return -1;
776579fb479Smaxv }
777579fb479Smaxv }
778579fb479Smaxv
779d1002cd7Smaxv if (__predict_true(is_long_mode(state))) {
7807ceb32d3Smaxv if (seg == NVMM_X64_SEG_GS || seg == NVMM_X64_SEG_FS) {
781d1002cd7Smaxv segment_apply(&state->segs[seg], &gva);
7827ceb32d3Smaxv }
7837ceb32d3Smaxv } else {
784d1002cd7Smaxv ret = segment_check(&state->segs[seg], gva, io.size);
7852760ca24Smaxv if (ret == -1)
7862760ca24Smaxv return -1;
787d1002cd7Smaxv segment_apply(&state->segs[seg], &gva);
7882760ca24Smaxv }
78980932742Smaxv
79080932742Smaxv if (exit->u.io.rep && !psld) {
791e6f32a58Smaxv iocnt = assist_io_batch(mach, vcpu, &io, gva, cnt);
79280932742Smaxv if (iocnt == -1)
79380932742Smaxv return -1;
79480932742Smaxv goto done;
79580932742Smaxv }
79638b2a665Smaxv }
7972760ca24Smaxv
79838b2a665Smaxv if (!io.in) {
79938b2a665Smaxv if (!exit->u.io.str) {
800d1002cd7Smaxv memcpy(io.data, &state->gprs[NVMM_X64_GPR_RAX], io.size);
80138b2a665Smaxv } else {
802e6f32a58Smaxv ret = read_guest_memory(mach, vcpu, gva, io.data,
80338b2a665Smaxv io.size);
8042760ca24Smaxv if (ret == -1)
8052760ca24Smaxv return -1;
8062760ca24Smaxv }
8072760ca24Smaxv }
8082760ca24Smaxv
809e6f32a58Smaxv (*vcpu->cbs.io)(&io);
81038b2a665Smaxv
8112760ca24Smaxv if (io.in) {
81238b2a665Smaxv if (!exit->u.io.str) {
813d1002cd7Smaxv memcpy(&state->gprs[NVMM_X64_GPR_RAX], io.data, io.size);
8147ceb32d3Smaxv if (io.size == 4) {
8157ceb32d3Smaxv /* Zero-extend to 64 bits. */
816d1002cd7Smaxv state->gprs[NVMM_X64_GPR_RAX] &= size_to_mask(4);
8177ceb32d3Smaxv }
8182760ca24Smaxv } else {
819e6f32a58Smaxv ret = write_guest_memory(mach, vcpu, gva, io.data,
82038b2a665Smaxv io.size);
82138b2a665Smaxv if (ret == -1)
82238b2a665Smaxv return -1;
8232760ca24Smaxv }
8242760ca24Smaxv }
8252760ca24Smaxv
82680932742Smaxv done:
8273f62f34aSmaxv if (exit->u.io.str) {
82880932742Smaxv if (__predict_false(psld)) {
829d1002cd7Smaxv state->gprs[reg] -= iocnt * io.size;
8303f62f34aSmaxv } else {
831d1002cd7Smaxv state->gprs[reg] += iocnt * io.size;
8323f62f34aSmaxv }
8333f62f34aSmaxv }
8343f62f34aSmaxv
8352760ca24Smaxv if (exit->u.io.rep) {
83680932742Smaxv cnt -= iocnt;
837d1002cd7Smaxv rep_set_cnt(state, exit->u.io.address_size, cnt);
83838b2a665Smaxv if (cnt == 0) {
839d1002cd7Smaxv state->gprs[NVMM_X64_GPR_RIP] = exit->u.io.npc;
8402760ca24Smaxv }
8412760ca24Smaxv } else {
842d1002cd7Smaxv state->gprs[NVMM_X64_GPR_RIP] = exit->u.io.npc;
8432760ca24Smaxv }
8442760ca24Smaxv
8457ceb32d3Smaxv out:
846d1002cd7Smaxv ret = nvmm_vcpu_setstate(mach, vcpu, NVMM_X64_STATE_GPRS);
8472760ca24Smaxv if (ret == -1)
8482760ca24Smaxv return -1;
8492760ca24Smaxv
8502760ca24Smaxv return 0;
8512760ca24Smaxv }
8522760ca24Smaxv
8532760ca24Smaxv /* -------------------------------------------------------------------------- */
8542760ca24Smaxv
85583ed0b5eSmaxv struct x86_emul {
856c496a7b1Smaxv bool readreg;
857c496a7b1Smaxv bool backprop;
85883ed0b5eSmaxv bool notouch;
859e6f32a58Smaxv void (*func)(struct nvmm_vcpu *, struct nvmm_mem *, uint64_t *);
86083ed0b5eSmaxv };
86183ed0b5eSmaxv
862e6f32a58Smaxv static void x86_func_or(struct nvmm_vcpu *, struct nvmm_mem *, uint64_t *);
863e6f32a58Smaxv static void x86_func_and(struct nvmm_vcpu *, struct nvmm_mem *, uint64_t *);
864e6f32a58Smaxv static void x86_func_xchg(struct nvmm_vcpu *, struct nvmm_mem *, uint64_t *);
865e6f32a58Smaxv static void x86_func_sub(struct nvmm_vcpu *, struct nvmm_mem *, uint64_t *);
866e6f32a58Smaxv static void x86_func_xor(struct nvmm_vcpu *, struct nvmm_mem *, uint64_t *);
867e6f32a58Smaxv static void x86_func_cmp(struct nvmm_vcpu *, struct nvmm_mem *, uint64_t *);
868e6f32a58Smaxv static void x86_func_test(struct nvmm_vcpu *, struct nvmm_mem *, uint64_t *);
869e6f32a58Smaxv static void x86_func_mov(struct nvmm_vcpu *, struct nvmm_mem *, uint64_t *);
870e6f32a58Smaxv static void x86_func_stos(struct nvmm_vcpu *, struct nvmm_mem *, uint64_t *);
871e6f32a58Smaxv static void x86_func_lods(struct nvmm_vcpu *, struct nvmm_mem *, uint64_t *);
87283ed0b5eSmaxv
87383ed0b5eSmaxv static const struct x86_emul x86_emul_or = {
874c496a7b1Smaxv .readreg = true,
87583ed0b5eSmaxv .func = x86_func_or
87683ed0b5eSmaxv };
87783ed0b5eSmaxv
87883ed0b5eSmaxv static const struct x86_emul x86_emul_and = {
879c496a7b1Smaxv .readreg = true,
88083ed0b5eSmaxv .func = x86_func_and
88183ed0b5eSmaxv };
88283ed0b5eSmaxv
883c496a7b1Smaxv static const struct x86_emul x86_emul_xchg = {
884c496a7b1Smaxv .readreg = true,
885c496a7b1Smaxv .backprop = true,
886c496a7b1Smaxv .func = x86_func_xchg
887c496a7b1Smaxv };
888c496a7b1Smaxv
88983ed0b5eSmaxv static const struct x86_emul x86_emul_sub = {
890c496a7b1Smaxv .readreg = true,
89183ed0b5eSmaxv .func = x86_func_sub
89283ed0b5eSmaxv };
89383ed0b5eSmaxv
89483ed0b5eSmaxv static const struct x86_emul x86_emul_xor = {
895c496a7b1Smaxv .readreg = true,
89683ed0b5eSmaxv .func = x86_func_xor
89783ed0b5eSmaxv };
89883ed0b5eSmaxv
89983ed0b5eSmaxv static const struct x86_emul x86_emul_cmp = {
90083ed0b5eSmaxv .notouch = true,
90183ed0b5eSmaxv .func = x86_func_cmp
90283ed0b5eSmaxv };
90383ed0b5eSmaxv
90483ed0b5eSmaxv static const struct x86_emul x86_emul_test = {
90583ed0b5eSmaxv .notouch = true,
90683ed0b5eSmaxv .func = x86_func_test
90783ed0b5eSmaxv };
90883ed0b5eSmaxv
90983ed0b5eSmaxv static const struct x86_emul x86_emul_mov = {
91083ed0b5eSmaxv .func = x86_func_mov
91183ed0b5eSmaxv };
91283ed0b5eSmaxv
91383ed0b5eSmaxv static const struct x86_emul x86_emul_stos = {
91483ed0b5eSmaxv .func = x86_func_stos
91583ed0b5eSmaxv };
91683ed0b5eSmaxv
91783ed0b5eSmaxv static const struct x86_emul x86_emul_lods = {
91883ed0b5eSmaxv .func = x86_func_lods
91983ed0b5eSmaxv };
92083ed0b5eSmaxv
92175c7df3cSmaxv /* Legacy prefixes. */
92275c7df3cSmaxv #define LEG_LOCK 0xF0
92375c7df3cSmaxv #define LEG_REPN 0xF2
92475c7df3cSmaxv #define LEG_REP 0xF3
92575c7df3cSmaxv #define LEG_OVR_CS 0x2E
92675c7df3cSmaxv #define LEG_OVR_SS 0x36
92775c7df3cSmaxv #define LEG_OVR_DS 0x3E
92875c7df3cSmaxv #define LEG_OVR_ES 0x26
92975c7df3cSmaxv #define LEG_OVR_FS 0x64
93075c7df3cSmaxv #define LEG_OVR_GS 0x65
93175c7df3cSmaxv #define LEG_OPR_OVR 0x66
93275c7df3cSmaxv #define LEG_ADR_OVR 0x67
9333f62f34aSmaxv
93475c7df3cSmaxv struct x86_legpref {
93575c7df3cSmaxv bool opr_ovr:1;
93675c7df3cSmaxv bool adr_ovr:1;
93775c7df3cSmaxv bool rep:1;
93875c7df3cSmaxv bool repn:1;
939*e6b71c14Sreinoud bool repe:1;
9404977f2ebSmaxv int8_t seg;
9413f62f34aSmaxv };
9423f62f34aSmaxv
9433f62f34aSmaxv struct x86_rexpref {
9444977f2ebSmaxv bool b:1;
9454977f2ebSmaxv bool x:1;
9464977f2ebSmaxv bool r:1;
9474977f2ebSmaxv bool w:1;
9484977f2ebSmaxv bool present:1;
9493f62f34aSmaxv };
9503f62f34aSmaxv
9513f62f34aSmaxv struct x86_reg {
9523f62f34aSmaxv int num; /* NVMM GPR state index */
9533f62f34aSmaxv uint64_t mask;
9543f62f34aSmaxv };
9553f62f34aSmaxv
956416eaf02Smaxv struct x86_dualreg {
957416eaf02Smaxv int reg1;
958416eaf02Smaxv int reg2;
959416eaf02Smaxv };
960416eaf02Smaxv
9613f62f34aSmaxv enum x86_disp_type {
9623f62f34aSmaxv DISP_NONE,
9633f62f34aSmaxv DISP_0,
9643f62f34aSmaxv DISP_1,
965416eaf02Smaxv DISP_2,
9663f62f34aSmaxv DISP_4
9673f62f34aSmaxv };
9683f62f34aSmaxv
9693f62f34aSmaxv struct x86_disp {
9703f62f34aSmaxv enum x86_disp_type type;
971960d1f76Smaxv uint64_t data; /* 4 bytes, but can be sign-extended */
9723f62f34aSmaxv };
9733f62f34aSmaxv
9743f62f34aSmaxv struct x86_regmodrm {
9754977f2ebSmaxv uint8_t mod:2;
9764977f2ebSmaxv uint8_t reg:3;
9774977f2ebSmaxv uint8_t rm:3;
9783f62f34aSmaxv };
9793f62f34aSmaxv
9803f62f34aSmaxv struct x86_immediate {
981960d1f76Smaxv uint64_t data;
9823f62f34aSmaxv };
9833f62f34aSmaxv
9843f62f34aSmaxv struct x86_sib {
9853f62f34aSmaxv uint8_t scale;
9863f62f34aSmaxv const struct x86_reg *idx;
9873f62f34aSmaxv const struct x86_reg *bas;
9883f62f34aSmaxv };
9893f62f34aSmaxv
9903f62f34aSmaxv enum x86_store_type {
9913f62f34aSmaxv STORE_NONE,
9923f62f34aSmaxv STORE_REG,
993416eaf02Smaxv STORE_DUALREG,
9943f62f34aSmaxv STORE_IMM,
9953f62f34aSmaxv STORE_SIB,
9963f62f34aSmaxv STORE_DMO
9973f62f34aSmaxv };
9983f62f34aSmaxv
9993f62f34aSmaxv struct x86_store {
10003f62f34aSmaxv enum x86_store_type type;
10013f62f34aSmaxv union {
10023f62f34aSmaxv const struct x86_reg *reg;
1003416eaf02Smaxv struct x86_dualreg dualreg;
10043f62f34aSmaxv struct x86_immediate imm;
10053f62f34aSmaxv struct x86_sib sib;
10063f62f34aSmaxv uint64_t dmo;
10073f62f34aSmaxv } u;
10083f62f34aSmaxv struct x86_disp disp;
100938b2a665Smaxv int hardseg;
10103f62f34aSmaxv };
10113f62f34aSmaxv
10123f62f34aSmaxv struct x86_instr {
10134977f2ebSmaxv uint8_t len;
101475c7df3cSmaxv struct x86_legpref legpref;
10153f62f34aSmaxv struct x86_rexpref rexpref;
10164977f2ebSmaxv struct x86_regmodrm regmodrm;
10174977f2ebSmaxv uint8_t operand_size;
10184977f2ebSmaxv uint8_t address_size;
101980932742Smaxv uint64_t zeroextend_mask;
10203f62f34aSmaxv
10213f62f34aSmaxv const struct x86_opcode *opcode;
10224977f2ebSmaxv const struct x86_emul *emul;
10233f62f34aSmaxv
10243f62f34aSmaxv struct x86_store src;
10253f62f34aSmaxv struct x86_store dst;
10263f62f34aSmaxv struct x86_store *strm;
10273f62f34aSmaxv };
10283f62f34aSmaxv
10293f62f34aSmaxv struct x86_decode_fsm {
10303f62f34aSmaxv /* vcpu */
10313f62f34aSmaxv bool is64bit;
10323f62f34aSmaxv bool is32bit;
10333f62f34aSmaxv bool is16bit;
10343f62f34aSmaxv
10353f62f34aSmaxv /* fsm */
10363f62f34aSmaxv int (*fn)(struct x86_decode_fsm *, struct x86_instr *);
10373f62f34aSmaxv uint8_t *buf;
10383f62f34aSmaxv uint8_t *end;
10393f62f34aSmaxv };
10403f62f34aSmaxv
10413f62f34aSmaxv struct x86_opcode {
10424977f2ebSmaxv bool valid:1;
10434977f2ebSmaxv bool regmodrm:1;
10444977f2ebSmaxv bool regtorm:1;
10454977f2ebSmaxv bool dmo:1;
10464977f2ebSmaxv bool todmo:1;
10474977f2ebSmaxv bool movs:1;
1048*e6b71c14Sreinoud bool cmps:1;
10494977f2ebSmaxv bool stos:1;
10504977f2ebSmaxv bool lods:1;
10514977f2ebSmaxv bool szoverride:1;
10524977f2ebSmaxv bool group1:1;
10534977f2ebSmaxv bool group3:1;
10544977f2ebSmaxv bool group11:1;
10554977f2ebSmaxv bool immediate:1;
10564977f2ebSmaxv uint8_t defsize;
10574977f2ebSmaxv uint8_t flags;
105883ed0b5eSmaxv const struct x86_emul *emul;
10593f62f34aSmaxv };
10603f62f34aSmaxv
10613f62f34aSmaxv struct x86_group_entry {
106283ed0b5eSmaxv const struct x86_emul *emul;
10633f62f34aSmaxv };
10643f62f34aSmaxv
10653f62f34aSmaxv #define OPSIZE_BYTE 0x01
10663f62f34aSmaxv #define OPSIZE_WORD 0x02 /* 2 bytes */
10673f62f34aSmaxv #define OPSIZE_DOUB 0x04 /* 4 bytes */
10683f62f34aSmaxv #define OPSIZE_QUAD 0x08 /* 8 bytes */
10693f62f34aSmaxv
1070960d1f76Smaxv #define FLAG_imm8 0x01
1071960d1f76Smaxv #define FLAG_immz 0x02
1072960d1f76Smaxv #define FLAG_ze 0x04
1073960d1f76Smaxv
10744977f2ebSmaxv static const struct x86_group_entry group1[8] __cacheline_aligned = {
107583ed0b5eSmaxv [1] = { .emul = &x86_emul_or },
107683ed0b5eSmaxv [4] = { .emul = &x86_emul_and },
107783ed0b5eSmaxv [6] = { .emul = &x86_emul_xor },
107883ed0b5eSmaxv [7] = { .emul = &x86_emul_cmp }
107983ed0b5eSmaxv };
108083ed0b5eSmaxv
10814977f2ebSmaxv static const struct x86_group_entry group3[8] __cacheline_aligned = {
108283ed0b5eSmaxv [0] = { .emul = &x86_emul_test },
108383ed0b5eSmaxv [1] = { .emul = &x86_emul_test }
1084960d1f76Smaxv };
10853f62f34aSmaxv
10864977f2ebSmaxv static const struct x86_group_entry group11[8] __cacheline_aligned = {
108783ed0b5eSmaxv [0] = { .emul = &x86_emul_mov }
10883f62f34aSmaxv };
10893f62f34aSmaxv
10904977f2ebSmaxv static const struct x86_opcode primary_opcode_table[256] __cacheline_aligned = {
10913f62f34aSmaxv /*
1092960d1f76Smaxv * Group1
1093960d1f76Smaxv */
10944977f2ebSmaxv [0x80] = {
109583ed0b5eSmaxv /* Eb, Ib */
10964977f2ebSmaxv .valid = true,
109783ed0b5eSmaxv .regmodrm = true,
109883ed0b5eSmaxv .regtorm = true,
109983ed0b5eSmaxv .szoverride = false,
110083ed0b5eSmaxv .defsize = OPSIZE_BYTE,
110183ed0b5eSmaxv .group1 = true,
110283ed0b5eSmaxv .immediate = true,
110383ed0b5eSmaxv .emul = NULL /* group1 */
110483ed0b5eSmaxv },
11054977f2ebSmaxv [0x81] = {
11067ceb32d3Smaxv /* Ev, Iz */
11074977f2ebSmaxv .valid = true,
11087ceb32d3Smaxv .regmodrm = true,
11097ceb32d3Smaxv .regtorm = true,
11107ceb32d3Smaxv .szoverride = true,
11117ceb32d3Smaxv .defsize = -1,
11127ceb32d3Smaxv .group1 = true,
11137ceb32d3Smaxv .immediate = true,
11147ceb32d3Smaxv .flags = FLAG_immz,
11157ceb32d3Smaxv .emul = NULL /* group1 */
11167ceb32d3Smaxv },
11174977f2ebSmaxv [0x83] = {
1118960d1f76Smaxv /* Ev, Ib */
11194977f2ebSmaxv .valid = true,
1120960d1f76Smaxv .regmodrm = true,
1121960d1f76Smaxv .regtorm = true,
1122960d1f76Smaxv .szoverride = true,
1123960d1f76Smaxv .defsize = -1,
1124960d1f76Smaxv .group1 = true,
1125960d1f76Smaxv .immediate = true,
1126960d1f76Smaxv .flags = FLAG_imm8,
1127960d1f76Smaxv .emul = NULL /* group1 */
1128960d1f76Smaxv },
1129960d1f76Smaxv
1130960d1f76Smaxv /*
113183ed0b5eSmaxv * Group3
113283ed0b5eSmaxv */
11334977f2ebSmaxv [0xF6] = {
113483ed0b5eSmaxv /* Eb, Ib */
11354977f2ebSmaxv .valid = true,
113683ed0b5eSmaxv .regmodrm = true,
113783ed0b5eSmaxv .regtorm = true,
113883ed0b5eSmaxv .szoverride = false,
113983ed0b5eSmaxv .defsize = OPSIZE_BYTE,
114083ed0b5eSmaxv .group3 = true,
114183ed0b5eSmaxv .immediate = true,
114283ed0b5eSmaxv .emul = NULL /* group3 */
114383ed0b5eSmaxv },
11444977f2ebSmaxv [0xF7] = {
114583ed0b5eSmaxv /* Ev, Iz */
11464977f2ebSmaxv .valid = true,
114783ed0b5eSmaxv .regmodrm = true,
114883ed0b5eSmaxv .regtorm = true,
114983ed0b5eSmaxv .szoverride = true,
115083ed0b5eSmaxv .defsize = -1,
115183ed0b5eSmaxv .group3 = true,
115283ed0b5eSmaxv .immediate = true,
115383ed0b5eSmaxv .flags = FLAG_immz,
115483ed0b5eSmaxv .emul = NULL /* group3 */
115583ed0b5eSmaxv },
115683ed0b5eSmaxv
115783ed0b5eSmaxv /*
11583f62f34aSmaxv * Group11
11593f62f34aSmaxv */
11604977f2ebSmaxv [0xC6] = {
1161960d1f76Smaxv /* Eb, Ib */
11624977f2ebSmaxv .valid = true,
11633f62f34aSmaxv .regmodrm = true,
11643f62f34aSmaxv .regtorm = true,
11653f62f34aSmaxv .szoverride = false,
11663f62f34aSmaxv .defsize = OPSIZE_BYTE,
11673f62f34aSmaxv .group11 = true,
11683f62f34aSmaxv .immediate = true,
11693f62f34aSmaxv .emul = NULL /* group11 */
11703f62f34aSmaxv },
11714977f2ebSmaxv [0xC7] = {
1172960d1f76Smaxv /* Ev, Iz */
11734977f2ebSmaxv .valid = true,
11743f62f34aSmaxv .regmodrm = true,
11753f62f34aSmaxv .regtorm = true,
11763f62f34aSmaxv .szoverride = true,
11773f62f34aSmaxv .defsize = -1,
11783f62f34aSmaxv .group11 = true,
11793f62f34aSmaxv .immediate = true,
1180960d1f76Smaxv .flags = FLAG_immz,
11813f62f34aSmaxv .emul = NULL /* group11 */
11823f62f34aSmaxv },
11833f62f34aSmaxv
11843f62f34aSmaxv /*
11853f62f34aSmaxv * OR
11863f62f34aSmaxv */
11874977f2ebSmaxv [0x08] = {
11883f62f34aSmaxv /* Eb, Gb */
11894977f2ebSmaxv .valid = true,
11903f62f34aSmaxv .regmodrm = true,
11913f62f34aSmaxv .regtorm = true,
11923f62f34aSmaxv .szoverride = false,
11933f62f34aSmaxv .defsize = OPSIZE_BYTE,
119483ed0b5eSmaxv .emul = &x86_emul_or
11953f62f34aSmaxv },
11964977f2ebSmaxv [0x09] = {
11973f62f34aSmaxv /* Ev, Gv */
11984977f2ebSmaxv .valid = true,
11993f62f34aSmaxv .regmodrm = true,
12003f62f34aSmaxv .regtorm = true,
12013f62f34aSmaxv .szoverride = true,
12023f62f34aSmaxv .defsize = -1,
120383ed0b5eSmaxv .emul = &x86_emul_or
12043f62f34aSmaxv },
12054977f2ebSmaxv [0x0A] = {
12063f62f34aSmaxv /* Gb, Eb */
12074977f2ebSmaxv .valid = true,
12083f62f34aSmaxv .regmodrm = true,
12093f62f34aSmaxv .regtorm = false,
12103f62f34aSmaxv .szoverride = false,
12113f62f34aSmaxv .defsize = OPSIZE_BYTE,
121283ed0b5eSmaxv .emul = &x86_emul_or
12133f62f34aSmaxv },
12144977f2ebSmaxv [0x0B] = {
12153f62f34aSmaxv /* Gv, Ev */
12164977f2ebSmaxv .valid = true,
12173f62f34aSmaxv .regmodrm = true,
12183f62f34aSmaxv .regtorm = false,
12193f62f34aSmaxv .szoverride = true,
12203f62f34aSmaxv .defsize = -1,
122183ed0b5eSmaxv .emul = &x86_emul_or
12223f62f34aSmaxv },
12233f62f34aSmaxv
12243f62f34aSmaxv /*
12253f62f34aSmaxv * AND
12263f62f34aSmaxv */
12274977f2ebSmaxv [0x20] = {
12283f62f34aSmaxv /* Eb, Gb */
12294977f2ebSmaxv .valid = true,
12303f62f34aSmaxv .regmodrm = true,
12313f62f34aSmaxv .regtorm = true,
12323f62f34aSmaxv .szoverride = false,
12333f62f34aSmaxv .defsize = OPSIZE_BYTE,
123483ed0b5eSmaxv .emul = &x86_emul_and
12353f62f34aSmaxv },
12364977f2ebSmaxv [0x21] = {
12373f62f34aSmaxv /* Ev, Gv */
12384977f2ebSmaxv .valid = true,
12393f62f34aSmaxv .regmodrm = true,
12403f62f34aSmaxv .regtorm = true,
12413f62f34aSmaxv .szoverride = true,
12423f62f34aSmaxv .defsize = -1,
124383ed0b5eSmaxv .emul = &x86_emul_and
12443f62f34aSmaxv },
12454977f2ebSmaxv [0x22] = {
12463f62f34aSmaxv /* Gb, Eb */
12474977f2ebSmaxv .valid = true,
12483f62f34aSmaxv .regmodrm = true,
12493f62f34aSmaxv .regtorm = false,
12503f62f34aSmaxv .szoverride = false,
12513f62f34aSmaxv .defsize = OPSIZE_BYTE,
125283ed0b5eSmaxv .emul = &x86_emul_and
12533f62f34aSmaxv },
12544977f2ebSmaxv [0x23] = {
12553f62f34aSmaxv /* Gv, Ev */
12564977f2ebSmaxv .valid = true,
12573f62f34aSmaxv .regmodrm = true,
12583f62f34aSmaxv .regtorm = false,
12593f62f34aSmaxv .szoverride = true,
12603f62f34aSmaxv .defsize = -1,
126183ed0b5eSmaxv .emul = &x86_emul_and
126283ed0b5eSmaxv },
126383ed0b5eSmaxv
126483ed0b5eSmaxv /*
126583ed0b5eSmaxv * SUB
126683ed0b5eSmaxv */
12674977f2ebSmaxv [0x28] = {
126883ed0b5eSmaxv /* Eb, Gb */
12694977f2ebSmaxv .valid = true,
127083ed0b5eSmaxv .regmodrm = true,
127183ed0b5eSmaxv .regtorm = true,
127283ed0b5eSmaxv .szoverride = false,
127383ed0b5eSmaxv .defsize = OPSIZE_BYTE,
127483ed0b5eSmaxv .emul = &x86_emul_sub
127583ed0b5eSmaxv },
12764977f2ebSmaxv [0x29] = {
127783ed0b5eSmaxv /* Ev, Gv */
12784977f2ebSmaxv .valid = true,
127983ed0b5eSmaxv .regmodrm = true,
128083ed0b5eSmaxv .regtorm = true,
128183ed0b5eSmaxv .szoverride = true,
128283ed0b5eSmaxv .defsize = -1,
128383ed0b5eSmaxv .emul = &x86_emul_sub
128483ed0b5eSmaxv },
12854977f2ebSmaxv [0x2A] = {
128683ed0b5eSmaxv /* Gb, Eb */
12874977f2ebSmaxv .valid = true,
128883ed0b5eSmaxv .regmodrm = true,
128983ed0b5eSmaxv .regtorm = false,
129083ed0b5eSmaxv .szoverride = false,
129183ed0b5eSmaxv .defsize = OPSIZE_BYTE,
129283ed0b5eSmaxv .emul = &x86_emul_sub
129383ed0b5eSmaxv },
12944977f2ebSmaxv [0x2B] = {
129583ed0b5eSmaxv /* Gv, Ev */
12964977f2ebSmaxv .valid = true,
129783ed0b5eSmaxv .regmodrm = true,
129883ed0b5eSmaxv .regtorm = false,
129983ed0b5eSmaxv .szoverride = true,
130083ed0b5eSmaxv .defsize = -1,
130183ed0b5eSmaxv .emul = &x86_emul_sub
13023f62f34aSmaxv },
13033f62f34aSmaxv
13043f62f34aSmaxv /*
13053f62f34aSmaxv * XOR
13063f62f34aSmaxv */
13074977f2ebSmaxv [0x30] = {
13083f62f34aSmaxv /* Eb, Gb */
13094977f2ebSmaxv .valid = true,
13103f62f34aSmaxv .regmodrm = true,
13113f62f34aSmaxv .regtorm = true,
13123f62f34aSmaxv .szoverride = false,
13133f62f34aSmaxv .defsize = OPSIZE_BYTE,
131483ed0b5eSmaxv .emul = &x86_emul_xor
13153f62f34aSmaxv },
13164977f2ebSmaxv [0x31] = {
13173f62f34aSmaxv /* Ev, Gv */
13184977f2ebSmaxv .valid = true,
13193f62f34aSmaxv .regmodrm = true,
13203f62f34aSmaxv .regtorm = true,
13213f62f34aSmaxv .szoverride = true,
13223f62f34aSmaxv .defsize = -1,
132383ed0b5eSmaxv .emul = &x86_emul_xor
13243f62f34aSmaxv },
13254977f2ebSmaxv [0x32] = {
13263f62f34aSmaxv /* Gb, Eb */
13274977f2ebSmaxv .valid = true,
13283f62f34aSmaxv .regmodrm = true,
13293f62f34aSmaxv .regtorm = false,
13303f62f34aSmaxv .szoverride = false,
13313f62f34aSmaxv .defsize = OPSIZE_BYTE,
133283ed0b5eSmaxv .emul = &x86_emul_xor
13333f62f34aSmaxv },
13344977f2ebSmaxv [0x33] = {
13353f62f34aSmaxv /* Gv, Ev */
13364977f2ebSmaxv .valid = true,
13373f62f34aSmaxv .regmodrm = true,
13383f62f34aSmaxv .regtorm = false,
13393f62f34aSmaxv .szoverride = true,
13403f62f34aSmaxv .defsize = -1,
134183ed0b5eSmaxv .emul = &x86_emul_xor
13423f62f34aSmaxv },
13433f62f34aSmaxv
13443f62f34aSmaxv /*
1345c496a7b1Smaxv * XCHG
1346c496a7b1Smaxv */
1347c496a7b1Smaxv [0x86] = {
1348c496a7b1Smaxv /* Eb, Gb */
1349c496a7b1Smaxv .valid = true,
1350c496a7b1Smaxv .regmodrm = true,
1351c496a7b1Smaxv .regtorm = true,
1352c496a7b1Smaxv .szoverride = false,
1353c496a7b1Smaxv .defsize = OPSIZE_BYTE,
1354c496a7b1Smaxv .emul = &x86_emul_xchg
1355c496a7b1Smaxv },
1356c496a7b1Smaxv [0x87] = {
1357c496a7b1Smaxv /* Ev, Gv */
1358c496a7b1Smaxv .valid = true,
1359c496a7b1Smaxv .regmodrm = true,
1360c496a7b1Smaxv .regtorm = true,
1361c496a7b1Smaxv .szoverride = true,
1362c496a7b1Smaxv .defsize = -1,
1363c496a7b1Smaxv .emul = &x86_emul_xchg
1364c496a7b1Smaxv },
1365c496a7b1Smaxv
1366c496a7b1Smaxv /*
13673f62f34aSmaxv * MOV
13683f62f34aSmaxv */
13694977f2ebSmaxv [0x88] = {
13703f62f34aSmaxv /* Eb, Gb */
13714977f2ebSmaxv .valid = true,
13723f62f34aSmaxv .regmodrm = true,
13733f62f34aSmaxv .regtorm = true,
13743f62f34aSmaxv .szoverride = false,
13753f62f34aSmaxv .defsize = OPSIZE_BYTE,
137683ed0b5eSmaxv .emul = &x86_emul_mov
13773f62f34aSmaxv },
13784977f2ebSmaxv [0x89] = {
13793f62f34aSmaxv /* Ev, Gv */
13804977f2ebSmaxv .valid = true,
13813f62f34aSmaxv .regmodrm = true,
13823f62f34aSmaxv .regtorm = true,
13833f62f34aSmaxv .szoverride = true,
13843f62f34aSmaxv .defsize = -1,
138583ed0b5eSmaxv .emul = &x86_emul_mov
13863f62f34aSmaxv },
13874977f2ebSmaxv [0x8A] = {
13883f62f34aSmaxv /* Gb, Eb */
13894977f2ebSmaxv .valid = true,
13903f62f34aSmaxv .regmodrm = true,
13913f62f34aSmaxv .regtorm = false,
13923f62f34aSmaxv .szoverride = false,
13933f62f34aSmaxv .defsize = OPSIZE_BYTE,
139483ed0b5eSmaxv .emul = &x86_emul_mov
13953f62f34aSmaxv },
13964977f2ebSmaxv [0x8B] = {
13973f62f34aSmaxv /* Gv, Ev */
13984977f2ebSmaxv .valid = true,
13993f62f34aSmaxv .regmodrm = true,
14003f62f34aSmaxv .regtorm = false,
14013f62f34aSmaxv .szoverride = true,
14023f62f34aSmaxv .defsize = -1,
140383ed0b5eSmaxv .emul = &x86_emul_mov
14043f62f34aSmaxv },
14054977f2ebSmaxv [0xA0] = {
14063f62f34aSmaxv /* AL, Ob */
14074977f2ebSmaxv .valid = true,
14083f62f34aSmaxv .dmo = true,
14093f62f34aSmaxv .todmo = false,
14103f62f34aSmaxv .szoverride = false,
14113f62f34aSmaxv .defsize = OPSIZE_BYTE,
141283ed0b5eSmaxv .emul = &x86_emul_mov
14133f62f34aSmaxv },
14144977f2ebSmaxv [0xA1] = {
14153f62f34aSmaxv /* rAX, Ov */
14164977f2ebSmaxv .valid = true,
14173f62f34aSmaxv .dmo = true,
14183f62f34aSmaxv .todmo = false,
14193f62f34aSmaxv .szoverride = true,
14203f62f34aSmaxv .defsize = -1,
142183ed0b5eSmaxv .emul = &x86_emul_mov
14223f62f34aSmaxv },
14234977f2ebSmaxv [0xA2] = {
14243f62f34aSmaxv /* Ob, AL */
14254977f2ebSmaxv .valid = true,
14263f62f34aSmaxv .dmo = true,
14273f62f34aSmaxv .todmo = true,
14283f62f34aSmaxv .szoverride = false,
14293f62f34aSmaxv .defsize = OPSIZE_BYTE,
143083ed0b5eSmaxv .emul = &x86_emul_mov
14313f62f34aSmaxv },
14324977f2ebSmaxv [0xA3] = {
14333f62f34aSmaxv /* Ov, rAX */
14344977f2ebSmaxv .valid = true,
14353f62f34aSmaxv .dmo = true,
14363f62f34aSmaxv .todmo = true,
14373f62f34aSmaxv .szoverride = true,
14383f62f34aSmaxv .defsize = -1,
143983ed0b5eSmaxv .emul = &x86_emul_mov
14403f62f34aSmaxv },
14413f62f34aSmaxv
14423f62f34aSmaxv /*
144338b2a665Smaxv * MOVS
144438b2a665Smaxv */
14454977f2ebSmaxv [0xA4] = {
144638b2a665Smaxv /* Yb, Xb */
14474977f2ebSmaxv .valid = true,
144838b2a665Smaxv .movs = true,
144938b2a665Smaxv .szoverride = false,
145038b2a665Smaxv .defsize = OPSIZE_BYTE,
1451*e6b71c14Sreinoud .emul = NULL
145238b2a665Smaxv },
14534977f2ebSmaxv [0xA5] = {
145438b2a665Smaxv /* Yv, Xv */
14554977f2ebSmaxv .valid = true,
145638b2a665Smaxv .movs = true,
145738b2a665Smaxv .szoverride = true,
145838b2a665Smaxv .defsize = -1,
1459*e6b71c14Sreinoud .emul = NULL
1460*e6b71c14Sreinoud },
1461*e6b71c14Sreinoud
1462*e6b71c14Sreinoud /*
1463*e6b71c14Sreinoud * CMPS
1464*e6b71c14Sreinoud */
1465*e6b71c14Sreinoud [0xA6] = {
1466*e6b71c14Sreinoud /* Yb, Xb */
1467*e6b71c14Sreinoud .valid = true,
1468*e6b71c14Sreinoud .cmps = true,
1469*e6b71c14Sreinoud .szoverride = false,
1470*e6b71c14Sreinoud .defsize = OPSIZE_BYTE,
1471*e6b71c14Sreinoud .emul = NULL
1472*e6b71c14Sreinoud },
1473*e6b71c14Sreinoud [0xA7] = {
1474*e6b71c14Sreinoud /* Yv, Xv */
1475*e6b71c14Sreinoud .valid = true,
1476*e6b71c14Sreinoud .cmps = true,
1477*e6b71c14Sreinoud .szoverride = true,
1478*e6b71c14Sreinoud .defsize = -1,
1479*e6b71c14Sreinoud .emul = NULL
148038b2a665Smaxv },
148138b2a665Smaxv
148238b2a665Smaxv /*
14833f62f34aSmaxv * STOS
14843f62f34aSmaxv */
14854977f2ebSmaxv [0xAA] = {
14863f62f34aSmaxv /* Yb, AL */
14874977f2ebSmaxv .valid = true,
14883f62f34aSmaxv .stos = true,
14893f62f34aSmaxv .szoverride = false,
14903f62f34aSmaxv .defsize = OPSIZE_BYTE,
149183ed0b5eSmaxv .emul = &x86_emul_stos
14923f62f34aSmaxv },
14934977f2ebSmaxv [0xAB] = {
14943f62f34aSmaxv /* Yv, rAX */
14954977f2ebSmaxv .valid = true,
14963f62f34aSmaxv .stos = true,
14973f62f34aSmaxv .szoverride = true,
14983f62f34aSmaxv .defsize = -1,
149983ed0b5eSmaxv .emul = &x86_emul_stos
15003f62f34aSmaxv },
15013f62f34aSmaxv
15023f62f34aSmaxv /*
15033f62f34aSmaxv * LODS
15043f62f34aSmaxv */
15054977f2ebSmaxv [0xAC] = {
15063f62f34aSmaxv /* AL, Xb */
15074977f2ebSmaxv .valid = true,
15083f62f34aSmaxv .lods = true,
15093f62f34aSmaxv .szoverride = false,
15103f62f34aSmaxv .defsize = OPSIZE_BYTE,
151183ed0b5eSmaxv .emul = &x86_emul_lods
15123f62f34aSmaxv },
15134977f2ebSmaxv [0xAD] = {
15143f62f34aSmaxv /* rAX, Xv */
15154977f2ebSmaxv .valid = true,
15163f62f34aSmaxv .lods = true,
15173f62f34aSmaxv .szoverride = true,
15183f62f34aSmaxv .defsize = -1,
151983ed0b5eSmaxv .emul = &x86_emul_lods
15203f62f34aSmaxv },
15213f62f34aSmaxv };
15223f62f34aSmaxv
15234977f2ebSmaxv static const struct x86_opcode secondary_opcode_table[256] __cacheline_aligned = {
152480932742Smaxv /*
152580932742Smaxv * MOVZX
152680932742Smaxv */
15274977f2ebSmaxv [0xB6] = {
152880932742Smaxv /* Gv, Eb */
15294977f2ebSmaxv .valid = true,
153080932742Smaxv .regmodrm = true,
153180932742Smaxv .regtorm = false,
153280932742Smaxv .szoverride = true,
153380932742Smaxv .defsize = OPSIZE_BYTE,
1534960d1f76Smaxv .flags = FLAG_ze,
153583ed0b5eSmaxv .emul = &x86_emul_mov
153680932742Smaxv },
15374977f2ebSmaxv [0xB7] = {
153880932742Smaxv /* Gv, Ew */
15394977f2ebSmaxv .valid = true,
154080932742Smaxv .regmodrm = true,
154180932742Smaxv .regtorm = false,
154280932742Smaxv .szoverride = true,
154380932742Smaxv .defsize = OPSIZE_WORD,
1544960d1f76Smaxv .flags = FLAG_ze,
154583ed0b5eSmaxv .emul = &x86_emul_mov
154680932742Smaxv },
154780932742Smaxv };
154880932742Smaxv
15493f62f34aSmaxv static const struct x86_reg gpr_map__rip = { NVMM_X64_GPR_RIP, 0xFFFFFFFFFFFFFFFF };
15503f62f34aSmaxv
15513f62f34aSmaxv /* [REX-present][enc][opsize] */
15524977f2ebSmaxv static const struct x86_reg gpr_map__special[2][4][8] __cacheline_aligned = {
15533f62f34aSmaxv [false] = {
15543f62f34aSmaxv /* No REX prefix. */
15553f62f34aSmaxv [0b00] = {
15563f62f34aSmaxv [0] = { NVMM_X64_GPR_RAX, 0x000000000000FF00 }, /* AH */
15573f62f34aSmaxv [1] = { NVMM_X64_GPR_RSP, 0x000000000000FFFF }, /* SP */
15583f62f34aSmaxv [2] = { -1, 0 },
15593f62f34aSmaxv [3] = { NVMM_X64_GPR_RSP, 0x00000000FFFFFFFF }, /* ESP */
15603f62f34aSmaxv [4] = { -1, 0 },
15613f62f34aSmaxv [5] = { -1, 0 },
15623f62f34aSmaxv [6] = { -1, 0 },
15633f62f34aSmaxv [7] = { -1, 0 },
15643f62f34aSmaxv },
15653f62f34aSmaxv [0b01] = {
15663f62f34aSmaxv [0] = { NVMM_X64_GPR_RCX, 0x000000000000FF00 }, /* CH */
15673f62f34aSmaxv [1] = { NVMM_X64_GPR_RBP, 0x000000000000FFFF }, /* BP */
15683f62f34aSmaxv [2] = { -1, 0 },
15693f62f34aSmaxv [3] = { NVMM_X64_GPR_RBP, 0x00000000FFFFFFFF }, /* EBP */
15703f62f34aSmaxv [4] = { -1, 0 },
15713f62f34aSmaxv [5] = { -1, 0 },
15723f62f34aSmaxv [6] = { -1, 0 },
15733f62f34aSmaxv [7] = { -1, 0 },
15743f62f34aSmaxv },
15753f62f34aSmaxv [0b10] = {
15763f62f34aSmaxv [0] = { NVMM_X64_GPR_RDX, 0x000000000000FF00 }, /* DH */
15773f62f34aSmaxv [1] = { NVMM_X64_GPR_RSI, 0x000000000000FFFF }, /* SI */
15783f62f34aSmaxv [2] = { -1, 0 },
15793f62f34aSmaxv [3] = { NVMM_X64_GPR_RSI, 0x00000000FFFFFFFF }, /* ESI */
15803f62f34aSmaxv [4] = { -1, 0 },
15813f62f34aSmaxv [5] = { -1, 0 },
15823f62f34aSmaxv [6] = { -1, 0 },
15833f62f34aSmaxv [7] = { -1, 0 },
15843f62f34aSmaxv },
15853f62f34aSmaxv [0b11] = {
15863f62f34aSmaxv [0] = { NVMM_X64_GPR_RBX, 0x000000000000FF00 }, /* BH */
15873f62f34aSmaxv [1] = { NVMM_X64_GPR_RDI, 0x000000000000FFFF }, /* DI */
15883f62f34aSmaxv [2] = { -1, 0 },
15893f62f34aSmaxv [3] = { NVMM_X64_GPR_RDI, 0x00000000FFFFFFFF }, /* EDI */
15903f62f34aSmaxv [4] = { -1, 0 },
15913f62f34aSmaxv [5] = { -1, 0 },
15923f62f34aSmaxv [6] = { -1, 0 },
15933f62f34aSmaxv [7] = { -1, 0 },
15943f62f34aSmaxv }
15953f62f34aSmaxv },
15963f62f34aSmaxv [true] = {
15973f62f34aSmaxv /* Has REX prefix. */
15983f62f34aSmaxv [0b00] = {
15993f62f34aSmaxv [0] = { NVMM_X64_GPR_RSP, 0x00000000000000FF }, /* SPL */
16003f62f34aSmaxv [1] = { NVMM_X64_GPR_RSP, 0x000000000000FFFF }, /* SP */
16013f62f34aSmaxv [2] = { -1, 0 },
16023f62f34aSmaxv [3] = { NVMM_X64_GPR_RSP, 0x00000000FFFFFFFF }, /* ESP */
16033f62f34aSmaxv [4] = { -1, 0 },
16043f62f34aSmaxv [5] = { -1, 0 },
16053f62f34aSmaxv [6] = { -1, 0 },
16063f62f34aSmaxv [7] = { NVMM_X64_GPR_RSP, 0xFFFFFFFFFFFFFFFF }, /* RSP */
16073f62f34aSmaxv },
16083f62f34aSmaxv [0b01] = {
16093f62f34aSmaxv [0] = { NVMM_X64_GPR_RBP, 0x00000000000000FF }, /* BPL */
16103f62f34aSmaxv [1] = { NVMM_X64_GPR_RBP, 0x000000000000FFFF }, /* BP */
16113f62f34aSmaxv [2] = { -1, 0 },
16123f62f34aSmaxv [3] = { NVMM_X64_GPR_RBP, 0x00000000FFFFFFFF }, /* EBP */
16133f62f34aSmaxv [4] = { -1, 0 },
16143f62f34aSmaxv [5] = { -1, 0 },
16153f62f34aSmaxv [6] = { -1, 0 },
16163f62f34aSmaxv [7] = { NVMM_X64_GPR_RBP, 0xFFFFFFFFFFFFFFFF }, /* RBP */
16173f62f34aSmaxv },
16183f62f34aSmaxv [0b10] = {
16193f62f34aSmaxv [0] = { NVMM_X64_GPR_RSI, 0x00000000000000FF }, /* SIL */
16203f62f34aSmaxv [1] = { NVMM_X64_GPR_RSI, 0x000000000000FFFF }, /* SI */
16213f62f34aSmaxv [2] = { -1, 0 },
16223f62f34aSmaxv [3] = { NVMM_X64_GPR_RSI, 0x00000000FFFFFFFF }, /* ESI */
16233f62f34aSmaxv [4] = { -1, 0 },
16243f62f34aSmaxv [5] = { -1, 0 },
16253f62f34aSmaxv [6] = { -1, 0 },
16263f62f34aSmaxv [7] = { NVMM_X64_GPR_RSI, 0xFFFFFFFFFFFFFFFF }, /* RSI */
16273f62f34aSmaxv },
16283f62f34aSmaxv [0b11] = {
16293f62f34aSmaxv [0] = { NVMM_X64_GPR_RDI, 0x00000000000000FF }, /* DIL */
16303f62f34aSmaxv [1] = { NVMM_X64_GPR_RDI, 0x000000000000FFFF }, /* DI */
16313f62f34aSmaxv [2] = { -1, 0 },
16323f62f34aSmaxv [3] = { NVMM_X64_GPR_RDI, 0x00000000FFFFFFFF }, /* EDI */
16333f62f34aSmaxv [4] = { -1, 0 },
16343f62f34aSmaxv [5] = { -1, 0 },
16353f62f34aSmaxv [6] = { -1, 0 },
16363f62f34aSmaxv [7] = { NVMM_X64_GPR_RDI, 0xFFFFFFFFFFFFFFFF }, /* RDI */
16373f62f34aSmaxv }
16383f62f34aSmaxv }
16393f62f34aSmaxv };
16403f62f34aSmaxv
16413f62f34aSmaxv /* [depends][enc][size] */
16424977f2ebSmaxv static const struct x86_reg gpr_map[2][8][8] __cacheline_aligned = {
16433f62f34aSmaxv [false] = {
16443f62f34aSmaxv /* Not extended. */
16453f62f34aSmaxv [0b000] = {
16463f62f34aSmaxv [0] = { NVMM_X64_GPR_RAX, 0x00000000000000FF }, /* AL */
16473f62f34aSmaxv [1] = { NVMM_X64_GPR_RAX, 0x000000000000FFFF }, /* AX */
16483f62f34aSmaxv [2] = { -1, 0 },
16493f62f34aSmaxv [3] = { NVMM_X64_GPR_RAX, 0x00000000FFFFFFFF }, /* EAX */
16503f62f34aSmaxv [4] = { -1, 0 },
16513f62f34aSmaxv [5] = { -1, 0 },
16523f62f34aSmaxv [6] = { -1, 0 },
16532089a381Smaxv [7] = { NVMM_X64_GPR_RAX, 0xFFFFFFFFFFFFFFFF }, /* RAX */
16543f62f34aSmaxv },
16553f62f34aSmaxv [0b001] = {
16563f62f34aSmaxv [0] = { NVMM_X64_GPR_RCX, 0x00000000000000FF }, /* CL */
16573f62f34aSmaxv [1] = { NVMM_X64_GPR_RCX, 0x000000000000FFFF }, /* CX */
16583f62f34aSmaxv [2] = { -1, 0 },
16593f62f34aSmaxv [3] = { NVMM_X64_GPR_RCX, 0x00000000FFFFFFFF }, /* ECX */
16603f62f34aSmaxv [4] = { -1, 0 },
16613f62f34aSmaxv [5] = { -1, 0 },
16623f62f34aSmaxv [6] = { -1, 0 },
16632089a381Smaxv [7] = { NVMM_X64_GPR_RCX, 0xFFFFFFFFFFFFFFFF }, /* RCX */
16643f62f34aSmaxv },
16653f62f34aSmaxv [0b010] = {
16663f62f34aSmaxv [0] = { NVMM_X64_GPR_RDX, 0x00000000000000FF }, /* DL */
16673f62f34aSmaxv [1] = { NVMM_X64_GPR_RDX, 0x000000000000FFFF }, /* DX */
16683f62f34aSmaxv [2] = { -1, 0 },
16693f62f34aSmaxv [3] = { NVMM_X64_GPR_RDX, 0x00000000FFFFFFFF }, /* EDX */
16703f62f34aSmaxv [4] = { -1, 0 },
16713f62f34aSmaxv [5] = { -1, 0 },
16723f62f34aSmaxv [6] = { -1, 0 },
16732089a381Smaxv [7] = { NVMM_X64_GPR_RDX, 0xFFFFFFFFFFFFFFFF }, /* RDX */
16743f62f34aSmaxv },
16753f62f34aSmaxv [0b011] = {
16763f62f34aSmaxv [0] = { NVMM_X64_GPR_RBX, 0x00000000000000FF }, /* BL */
16773f62f34aSmaxv [1] = { NVMM_X64_GPR_RBX, 0x000000000000FFFF }, /* BX */
16783f62f34aSmaxv [2] = { -1, 0 },
16793f62f34aSmaxv [3] = { NVMM_X64_GPR_RBX, 0x00000000FFFFFFFF }, /* EBX */
16803f62f34aSmaxv [4] = { -1, 0 },
16813f62f34aSmaxv [5] = { -1, 0 },
16823f62f34aSmaxv [6] = { -1, 0 },
16832089a381Smaxv [7] = { NVMM_X64_GPR_RBX, 0xFFFFFFFFFFFFFFFF }, /* RBX */
16843f62f34aSmaxv },
16853f62f34aSmaxv [0b100] = {
16863f62f34aSmaxv [0] = { -1, 0 }, /* SPECIAL */
16873f62f34aSmaxv [1] = { -1, 0 }, /* SPECIAL */
16883f62f34aSmaxv [2] = { -1, 0 },
16893f62f34aSmaxv [3] = { -1, 0 }, /* SPECIAL */
16903f62f34aSmaxv [4] = { -1, 0 },
16913f62f34aSmaxv [5] = { -1, 0 },
16923f62f34aSmaxv [6] = { -1, 0 },
16933f62f34aSmaxv [7] = { -1, 0 }, /* SPECIAL */
16943f62f34aSmaxv },
16953f62f34aSmaxv [0b101] = {
16963f62f34aSmaxv [0] = { -1, 0 }, /* SPECIAL */
16973f62f34aSmaxv [1] = { -1, 0 }, /* SPECIAL */
16983f62f34aSmaxv [2] = { -1, 0 },
16993f62f34aSmaxv [3] = { -1, 0 }, /* SPECIAL */
17003f62f34aSmaxv [4] = { -1, 0 },
17013f62f34aSmaxv [5] = { -1, 0 },
17023f62f34aSmaxv [6] = { -1, 0 },
17033f62f34aSmaxv [7] = { -1, 0 }, /* SPECIAL */
17043f62f34aSmaxv },
17053f62f34aSmaxv [0b110] = {
17063f62f34aSmaxv [0] = { -1, 0 }, /* SPECIAL */
17073f62f34aSmaxv [1] = { -1, 0 }, /* SPECIAL */
17083f62f34aSmaxv [2] = { -1, 0 },
17093f62f34aSmaxv [3] = { -1, 0 }, /* SPECIAL */
17103f62f34aSmaxv [4] = { -1, 0 },
17113f62f34aSmaxv [5] = { -1, 0 },
17123f62f34aSmaxv [6] = { -1, 0 },
17133f62f34aSmaxv [7] = { -1, 0 }, /* SPECIAL */
17143f62f34aSmaxv },
17153f62f34aSmaxv [0b111] = {
17163f62f34aSmaxv [0] = { -1, 0 }, /* SPECIAL */
17173f62f34aSmaxv [1] = { -1, 0 }, /* SPECIAL */
17183f62f34aSmaxv [2] = { -1, 0 },
17193f62f34aSmaxv [3] = { -1, 0 }, /* SPECIAL */
17203f62f34aSmaxv [4] = { -1, 0 },
17213f62f34aSmaxv [5] = { -1, 0 },
17223f62f34aSmaxv [6] = { -1, 0 },
17233f62f34aSmaxv [7] = { -1, 0 }, /* SPECIAL */
17243f62f34aSmaxv },
17253f62f34aSmaxv },
17263f62f34aSmaxv [true] = {
17273f62f34aSmaxv /* Extended. */
17283f62f34aSmaxv [0b000] = {
17293f62f34aSmaxv [0] = { NVMM_X64_GPR_R8, 0x00000000000000FF }, /* R8B */
17303f62f34aSmaxv [1] = { NVMM_X64_GPR_R8, 0x000000000000FFFF }, /* R8W */
17313f62f34aSmaxv [2] = { -1, 0 },
17323f62f34aSmaxv [3] = { NVMM_X64_GPR_R8, 0x00000000FFFFFFFF }, /* R8D */
17333f62f34aSmaxv [4] = { -1, 0 },
17343f62f34aSmaxv [5] = { -1, 0 },
17353f62f34aSmaxv [6] = { -1, 0 },
17362089a381Smaxv [7] = { NVMM_X64_GPR_R8, 0xFFFFFFFFFFFFFFFF }, /* R8 */
17373f62f34aSmaxv },
17383f62f34aSmaxv [0b001] = {
17393f62f34aSmaxv [0] = { NVMM_X64_GPR_R9, 0x00000000000000FF }, /* R9B */
17403f62f34aSmaxv [1] = { NVMM_X64_GPR_R9, 0x000000000000FFFF }, /* R9W */
17413f62f34aSmaxv [2] = { -1, 0 },
17423f62f34aSmaxv [3] = { NVMM_X64_GPR_R9, 0x00000000FFFFFFFF }, /* R9D */
17433f62f34aSmaxv [4] = { -1, 0 },
17443f62f34aSmaxv [5] = { -1, 0 },
17453f62f34aSmaxv [6] = { -1, 0 },
17462089a381Smaxv [7] = { NVMM_X64_GPR_R9, 0xFFFFFFFFFFFFFFFF }, /* R9 */
17473f62f34aSmaxv },
17483f62f34aSmaxv [0b010] = {
17493f62f34aSmaxv [0] = { NVMM_X64_GPR_R10, 0x00000000000000FF }, /* R10B */
17503f62f34aSmaxv [1] = { NVMM_X64_GPR_R10, 0x000000000000FFFF }, /* R10W */
17513f62f34aSmaxv [2] = { -1, 0 },
17523f62f34aSmaxv [3] = { NVMM_X64_GPR_R10, 0x00000000FFFFFFFF }, /* R10D */
17533f62f34aSmaxv [4] = { -1, 0 },
17543f62f34aSmaxv [5] = { -1, 0 },
17553f62f34aSmaxv [6] = { -1, 0 },
17562089a381Smaxv [7] = { NVMM_X64_GPR_R10, 0xFFFFFFFFFFFFFFFF }, /* R10 */
17573f62f34aSmaxv },
17583f62f34aSmaxv [0b011] = {
17593f62f34aSmaxv [0] = { NVMM_X64_GPR_R11, 0x00000000000000FF }, /* R11B */
17603f62f34aSmaxv [1] = { NVMM_X64_GPR_R11, 0x000000000000FFFF }, /* R11W */
17613f62f34aSmaxv [2] = { -1, 0 },
17623f62f34aSmaxv [3] = { NVMM_X64_GPR_R11, 0x00000000FFFFFFFF }, /* R11D */
17633f62f34aSmaxv [4] = { -1, 0 },
17643f62f34aSmaxv [5] = { -1, 0 },
17653f62f34aSmaxv [6] = { -1, 0 },
17662089a381Smaxv [7] = { NVMM_X64_GPR_R11, 0xFFFFFFFFFFFFFFFF }, /* R11 */
17673f62f34aSmaxv },
17683f62f34aSmaxv [0b100] = {
17693f62f34aSmaxv [0] = { NVMM_X64_GPR_R12, 0x00000000000000FF }, /* R12B */
17703f62f34aSmaxv [1] = { NVMM_X64_GPR_R12, 0x000000000000FFFF }, /* R12W */
17713f62f34aSmaxv [2] = { -1, 0 },
17723f62f34aSmaxv [3] = { NVMM_X64_GPR_R12, 0x00000000FFFFFFFF }, /* R12D */
17733f62f34aSmaxv [4] = { -1, 0 },
17743f62f34aSmaxv [5] = { -1, 0 },
17753f62f34aSmaxv [6] = { -1, 0 },
17762089a381Smaxv [7] = { NVMM_X64_GPR_R12, 0xFFFFFFFFFFFFFFFF }, /* R12 */
17773f62f34aSmaxv },
17783f62f34aSmaxv [0b101] = {
17793f62f34aSmaxv [0] = { NVMM_X64_GPR_R13, 0x00000000000000FF }, /* R13B */
17803f62f34aSmaxv [1] = { NVMM_X64_GPR_R13, 0x000000000000FFFF }, /* R13W */
17813f62f34aSmaxv [2] = { -1, 0 },
17823f62f34aSmaxv [3] = { NVMM_X64_GPR_R13, 0x00000000FFFFFFFF }, /* R13D */
17833f62f34aSmaxv [4] = { -1, 0 },
17843f62f34aSmaxv [5] = { -1, 0 },
17853f62f34aSmaxv [6] = { -1, 0 },
17862089a381Smaxv [7] = { NVMM_X64_GPR_R13, 0xFFFFFFFFFFFFFFFF }, /* R13 */
17873f62f34aSmaxv },
17883f62f34aSmaxv [0b110] = {
17893f62f34aSmaxv [0] = { NVMM_X64_GPR_R14, 0x00000000000000FF }, /* R14B */
17903f62f34aSmaxv [1] = { NVMM_X64_GPR_R14, 0x000000000000FFFF }, /* R14W */
17913f62f34aSmaxv [2] = { -1, 0 },
17923f62f34aSmaxv [3] = { NVMM_X64_GPR_R14, 0x00000000FFFFFFFF }, /* R14D */
17933f62f34aSmaxv [4] = { -1, 0 },
17943f62f34aSmaxv [5] = { -1, 0 },
17953f62f34aSmaxv [6] = { -1, 0 },
17962089a381Smaxv [7] = { NVMM_X64_GPR_R14, 0xFFFFFFFFFFFFFFFF }, /* R14 */
17973f62f34aSmaxv },
17983f62f34aSmaxv [0b111] = {
17993f62f34aSmaxv [0] = { NVMM_X64_GPR_R15, 0x00000000000000FF }, /* R15B */
18003f62f34aSmaxv [1] = { NVMM_X64_GPR_R15, 0x000000000000FFFF }, /* R15W */
18013f62f34aSmaxv [2] = { -1, 0 },
18023f62f34aSmaxv [3] = { NVMM_X64_GPR_R15, 0x00000000FFFFFFFF }, /* R15D */
18033f62f34aSmaxv [4] = { -1, 0 },
18043f62f34aSmaxv [5] = { -1, 0 },
18053f62f34aSmaxv [6] = { -1, 0 },
18062089a381Smaxv [7] = { NVMM_X64_GPR_R15, 0xFFFFFFFFFFFFFFFF }, /* R15 */
18073f62f34aSmaxv },
18083f62f34aSmaxv }
18093f62f34aSmaxv };
18103f62f34aSmaxv
1811416eaf02Smaxv /* [enc] */
1812416eaf02Smaxv static const int gpr_dual_reg1_rm[8] __cacheline_aligned = {
1813416eaf02Smaxv [0b000] = NVMM_X64_GPR_RBX, /* BX (+SI) */
1814416eaf02Smaxv [0b001] = NVMM_X64_GPR_RBX, /* BX (+DI) */
1815416eaf02Smaxv [0b010] = NVMM_X64_GPR_RBP, /* BP (+SI) */
1816416eaf02Smaxv [0b011] = NVMM_X64_GPR_RBP, /* BP (+DI) */
1817416eaf02Smaxv [0b100] = NVMM_X64_GPR_RSI, /* SI */
1818416eaf02Smaxv [0b101] = NVMM_X64_GPR_RDI, /* DI */
1819416eaf02Smaxv [0b110] = NVMM_X64_GPR_RBP, /* BP */
1820416eaf02Smaxv [0b111] = NVMM_X64_GPR_RBX, /* BX */
1821416eaf02Smaxv };
1822416eaf02Smaxv
18233f62f34aSmaxv static int
node_overflow(struct x86_decode_fsm * fsm,struct x86_instr * instr)18243f62f34aSmaxv node_overflow(struct x86_decode_fsm *fsm, struct x86_instr *instr)
18253f62f34aSmaxv {
18263f62f34aSmaxv fsm->fn = NULL;
18273f62f34aSmaxv return -1;
18283f62f34aSmaxv }
18293f62f34aSmaxv
18303f62f34aSmaxv static int
fsm_read(struct x86_decode_fsm * fsm,uint8_t * bytes,size_t n)18313f62f34aSmaxv fsm_read(struct x86_decode_fsm *fsm, uint8_t *bytes, size_t n)
18323f62f34aSmaxv {
18333f62f34aSmaxv if (fsm->buf + n > fsm->end) {
18343f62f34aSmaxv return -1;
18353f62f34aSmaxv }
18363f62f34aSmaxv memcpy(bytes, fsm->buf, n);
18373f62f34aSmaxv return 0;
18383f62f34aSmaxv }
18393f62f34aSmaxv
18404977f2ebSmaxv static inline void
fsm_advance(struct x86_decode_fsm * fsm,size_t n,int (* fn)(struct x86_decode_fsm *,struct x86_instr *))18413f62f34aSmaxv fsm_advance(struct x86_decode_fsm *fsm, size_t n,
18423f62f34aSmaxv int (*fn)(struct x86_decode_fsm *, struct x86_instr *))
18433f62f34aSmaxv {
18443f62f34aSmaxv fsm->buf += n;
18453f62f34aSmaxv if (fsm->buf > fsm->end) {
18463f62f34aSmaxv fsm->fn = node_overflow;
18473f62f34aSmaxv } else {
18483f62f34aSmaxv fsm->fn = fn;
18493f62f34aSmaxv }
18503f62f34aSmaxv }
18513f62f34aSmaxv
18523f62f34aSmaxv static const struct x86_reg *
resolve_special_register(struct x86_instr * instr,uint8_t enc,size_t regsize)18533f62f34aSmaxv resolve_special_register(struct x86_instr *instr, uint8_t enc, size_t regsize)
18543f62f34aSmaxv {
18553f62f34aSmaxv enc &= 0b11;
18563f62f34aSmaxv if (regsize == 8) {
18573f62f34aSmaxv /* May be 64bit without REX */
18583f62f34aSmaxv return &gpr_map__special[1][enc][regsize-1];
18593f62f34aSmaxv }
18603f62f34aSmaxv return &gpr_map__special[instr->rexpref.present][enc][regsize-1];
18613f62f34aSmaxv }
18623f62f34aSmaxv
18633f62f34aSmaxv /*
186438b2a665Smaxv * Special node, for MOVS. Fake two displacements of zero on the source and
186538b2a665Smaxv * destination registers.
186638b2a665Smaxv */
186738b2a665Smaxv static int
node_movs(struct x86_decode_fsm * fsm,struct x86_instr * instr)186838b2a665Smaxv node_movs(struct x86_decode_fsm *fsm, struct x86_instr *instr)
186938b2a665Smaxv {
187038b2a665Smaxv size_t adrsize;
187138b2a665Smaxv
187238b2a665Smaxv adrsize = instr->address_size;
187338b2a665Smaxv
187438b2a665Smaxv /* DS:RSI */
187538b2a665Smaxv instr->src.type = STORE_REG;
187638b2a665Smaxv instr->src.u.reg = &gpr_map__special[1][2][adrsize-1];
187738b2a665Smaxv instr->src.disp.type = DISP_0;
187838b2a665Smaxv
187938b2a665Smaxv /* ES:RDI, force ES */
188038b2a665Smaxv instr->dst.type = STORE_REG;
188138b2a665Smaxv instr->dst.u.reg = &gpr_map__special[1][3][adrsize-1];
188238b2a665Smaxv instr->dst.disp.type = DISP_0;
188338b2a665Smaxv instr->dst.hardseg = NVMM_X64_SEG_ES;
188438b2a665Smaxv
188538b2a665Smaxv fsm_advance(fsm, 0, NULL);
188638b2a665Smaxv
188738b2a665Smaxv return 0;
188838b2a665Smaxv }
188938b2a665Smaxv
189038b2a665Smaxv /*
1891*e6b71c14Sreinoud * Special node, for CMPS. Fake two displacements of zero on the source and
1892*e6b71c14Sreinoud * destination registers.
1893*e6b71c14Sreinoud * XXX coded as clone of movs as its similar in register usage
1894*e6b71c14Sreinoud * XXX might be merged with node_movs()
1895*e6b71c14Sreinoud */
1896*e6b71c14Sreinoud static int
node_cmps(struct x86_decode_fsm * fsm,struct x86_instr * instr)1897*e6b71c14Sreinoud node_cmps(struct x86_decode_fsm *fsm, struct x86_instr *instr)
1898*e6b71c14Sreinoud {
1899*e6b71c14Sreinoud size_t adrsize;
1900*e6b71c14Sreinoud
1901*e6b71c14Sreinoud adrsize = instr->address_size;
1902*e6b71c14Sreinoud
1903*e6b71c14Sreinoud /* DS:RSI */
1904*e6b71c14Sreinoud instr->src.type = STORE_REG;
1905*e6b71c14Sreinoud instr->src.u.reg = &gpr_map__special[1][2][adrsize-1];
1906*e6b71c14Sreinoud instr->src.disp.type = DISP_0;
1907*e6b71c14Sreinoud
1908*e6b71c14Sreinoud /* ES:RDI, force ES */
1909*e6b71c14Sreinoud instr->dst.type = STORE_REG;
1910*e6b71c14Sreinoud instr->dst.u.reg = &gpr_map__special[1][3][adrsize-1];
1911*e6b71c14Sreinoud instr->dst.disp.type = DISP_0;
1912*e6b71c14Sreinoud instr->dst.hardseg = NVMM_X64_SEG_ES;
1913*e6b71c14Sreinoud
1914*e6b71c14Sreinoud fsm_advance(fsm, 0, NULL);
1915*e6b71c14Sreinoud
1916*e6b71c14Sreinoud return 0;
1917*e6b71c14Sreinoud }
1918*e6b71c14Sreinoud
1919*e6b71c14Sreinoud /*
19203f62f34aSmaxv * Special node, for STOS and LODS. Fake a displacement of zero on the
19213f62f34aSmaxv * destination register.
19223f62f34aSmaxv */
19233f62f34aSmaxv static int
node_stlo(struct x86_decode_fsm * fsm,struct x86_instr * instr)19243f62f34aSmaxv node_stlo(struct x86_decode_fsm *fsm, struct x86_instr *instr)
19253f62f34aSmaxv {
19263f62f34aSmaxv const struct x86_opcode *opcode = instr->opcode;
19273f62f34aSmaxv struct x86_store *stlo, *streg;
19283f62f34aSmaxv size_t adrsize, regsize;
19293f62f34aSmaxv
19303f62f34aSmaxv adrsize = instr->address_size;
19313f62f34aSmaxv regsize = instr->operand_size;
19323f62f34aSmaxv
19333f62f34aSmaxv if (opcode->stos) {
19343f62f34aSmaxv streg = &instr->src;
19353f62f34aSmaxv stlo = &instr->dst;
19363f62f34aSmaxv } else {
19373f62f34aSmaxv streg = &instr->dst;
19383f62f34aSmaxv stlo = &instr->src;
19393f62f34aSmaxv }
19403f62f34aSmaxv
19413f62f34aSmaxv streg->type = STORE_REG;
19423f62f34aSmaxv streg->u.reg = &gpr_map[0][0][regsize-1]; /* ?AX */
19433f62f34aSmaxv
19443f62f34aSmaxv stlo->type = STORE_REG;
19453f62f34aSmaxv if (opcode->stos) {
19463f62f34aSmaxv /* ES:RDI, force ES */
19473f62f34aSmaxv stlo->u.reg = &gpr_map__special[1][3][adrsize-1];
194838b2a665Smaxv stlo->hardseg = NVMM_X64_SEG_ES;
19493f62f34aSmaxv } else {
19503f62f34aSmaxv /* DS:RSI */
19513f62f34aSmaxv stlo->u.reg = &gpr_map__special[1][2][adrsize-1];
19523f62f34aSmaxv }
19533f62f34aSmaxv stlo->disp.type = DISP_0;
19543f62f34aSmaxv
19553f62f34aSmaxv fsm_advance(fsm, 0, NULL);
19563f62f34aSmaxv
19573f62f34aSmaxv return 0;
19583f62f34aSmaxv }
19593f62f34aSmaxv
19603f62f34aSmaxv static int
node_dmo(struct x86_decode_fsm * fsm,struct x86_instr * instr)19613f62f34aSmaxv node_dmo(struct x86_decode_fsm *fsm, struct x86_instr *instr)
19623f62f34aSmaxv {
19633f62f34aSmaxv const struct x86_opcode *opcode = instr->opcode;
19643f62f34aSmaxv struct x86_store *stdmo, *streg;
19653f62f34aSmaxv size_t adrsize, regsize;
19663f62f34aSmaxv
19673f62f34aSmaxv adrsize = instr->address_size;
19683f62f34aSmaxv regsize = instr->operand_size;
19693f62f34aSmaxv
19703f62f34aSmaxv if (opcode->todmo) {
19713f62f34aSmaxv streg = &instr->src;
19723f62f34aSmaxv stdmo = &instr->dst;
19733f62f34aSmaxv } else {
19743f62f34aSmaxv streg = &instr->dst;
19753f62f34aSmaxv stdmo = &instr->src;
19763f62f34aSmaxv }
19773f62f34aSmaxv
19783f62f34aSmaxv streg->type = STORE_REG;
19793f62f34aSmaxv streg->u.reg = &gpr_map[0][0][regsize-1]; /* ?AX */
19803f62f34aSmaxv
19813f62f34aSmaxv stdmo->type = STORE_DMO;
19823f62f34aSmaxv if (fsm_read(fsm, (uint8_t *)&stdmo->u.dmo, adrsize) == -1) {
19833f62f34aSmaxv return -1;
19843f62f34aSmaxv }
19853f62f34aSmaxv fsm_advance(fsm, adrsize, NULL);
19863f62f34aSmaxv
19873f62f34aSmaxv return 0;
19883f62f34aSmaxv }
19893f62f34aSmaxv
19907ceb32d3Smaxv static inline uint64_t
sign_extend(uint64_t val,int size)1991960d1f76Smaxv sign_extend(uint64_t val, int size)
1992960d1f76Smaxv {
1993960d1f76Smaxv if (size == 1) {
1994960d1f76Smaxv if (val & __BIT(7))
1995960d1f76Smaxv val |= 0xFFFFFFFFFFFFFF00;
1996960d1f76Smaxv } else if (size == 2) {
1997960d1f76Smaxv if (val & __BIT(15))
1998960d1f76Smaxv val |= 0xFFFFFFFFFFFF0000;
1999960d1f76Smaxv } else if (size == 4) {
2000960d1f76Smaxv if (val & __BIT(31))
2001960d1f76Smaxv val |= 0xFFFFFFFF00000000;
2002960d1f76Smaxv }
2003960d1f76Smaxv return val;
2004960d1f76Smaxv }
2005960d1f76Smaxv
20063f62f34aSmaxv static int
node_immediate(struct x86_decode_fsm * fsm,struct x86_instr * instr)20073f62f34aSmaxv node_immediate(struct x86_decode_fsm *fsm, struct x86_instr *instr)
20083f62f34aSmaxv {
20093f62f34aSmaxv const struct x86_opcode *opcode = instr->opcode;
20103f62f34aSmaxv struct x86_store *store;
20113f62f34aSmaxv uint8_t immsize;
2012960d1f76Smaxv size_t sesize = 0;
20133f62f34aSmaxv
20143f62f34aSmaxv /* The immediate is the source */
20153f62f34aSmaxv store = &instr->src;
20163f62f34aSmaxv immsize = instr->operand_size;
20173f62f34aSmaxv
2018960d1f76Smaxv if (opcode->flags & FLAG_imm8) {
2019960d1f76Smaxv sesize = immsize;
2020960d1f76Smaxv immsize = 1;
2021960d1f76Smaxv } else if ((opcode->flags & FLAG_immz) && (immsize == 8)) {
2022960d1f76Smaxv sesize = immsize;
20233f62f34aSmaxv immsize = 4;
20243f62f34aSmaxv }
20253f62f34aSmaxv
20263f62f34aSmaxv store->type = STORE_IMM;
2027960d1f76Smaxv if (fsm_read(fsm, (uint8_t *)&store->u.imm.data, immsize) == -1) {
20283f62f34aSmaxv return -1;
20293f62f34aSmaxv }
20307ceb32d3Smaxv fsm_advance(fsm, immsize, NULL);
20313f62f34aSmaxv
2032960d1f76Smaxv if (sesize != 0) {
2033960d1f76Smaxv store->u.imm.data = sign_extend(store->u.imm.data, sesize);
2034960d1f76Smaxv }
2035960d1f76Smaxv
20363f62f34aSmaxv return 0;
20373f62f34aSmaxv }
20383f62f34aSmaxv
20393f62f34aSmaxv static int
node_disp(struct x86_decode_fsm * fsm,struct x86_instr * instr)20403f62f34aSmaxv node_disp(struct x86_decode_fsm *fsm, struct x86_instr *instr)
20413f62f34aSmaxv {
20423f62f34aSmaxv const struct x86_opcode *opcode = instr->opcode;
2043960d1f76Smaxv uint64_t data = 0;
20443f62f34aSmaxv size_t n;
20453f62f34aSmaxv
20463f62f34aSmaxv if (instr->strm->disp.type == DISP_1) {
20473f62f34aSmaxv n = 1;
2048416eaf02Smaxv } else if (instr->strm->disp.type == DISP_2) {
2049416eaf02Smaxv n = 2;
2050416eaf02Smaxv } else if (instr->strm->disp.type == DISP_4) {
20513f62f34aSmaxv n = 4;
2052416eaf02Smaxv } else {
2053416eaf02Smaxv DISASSEMBLER_BUG();
20543f62f34aSmaxv }
20553f62f34aSmaxv
2056960d1f76Smaxv if (fsm_read(fsm, (uint8_t *)&data, n) == -1) {
20573f62f34aSmaxv return -1;
20583f62f34aSmaxv }
20593f62f34aSmaxv
2060960d1f76Smaxv if (__predict_true(fsm->is64bit)) {
2061960d1f76Smaxv data = sign_extend(data, n);
2062960d1f76Smaxv }
2063960d1f76Smaxv
2064960d1f76Smaxv instr->strm->disp.data = data;
2065960d1f76Smaxv
20663f62f34aSmaxv if (opcode->immediate) {
20673f62f34aSmaxv fsm_advance(fsm, n, node_immediate);
20683f62f34aSmaxv } else {
20693f62f34aSmaxv fsm_advance(fsm, n, NULL);
20703f62f34aSmaxv }
20713f62f34aSmaxv
20723f62f34aSmaxv return 0;
20733f62f34aSmaxv }
20743f62f34aSmaxv
2075416eaf02Smaxv /*
2076416eaf02Smaxv * Special node to handle 16bit addressing encoding, which can reference two
2077416eaf02Smaxv * registers at once.
2078416eaf02Smaxv */
2079416eaf02Smaxv static int
node_dual(struct x86_decode_fsm * fsm,struct x86_instr * instr)2080416eaf02Smaxv node_dual(struct x86_decode_fsm *fsm, struct x86_instr *instr)
2081416eaf02Smaxv {
2082416eaf02Smaxv int reg1, reg2;
2083416eaf02Smaxv
2084416eaf02Smaxv reg1 = gpr_dual_reg1_rm[instr->regmodrm.rm];
2085416eaf02Smaxv
2086416eaf02Smaxv if (instr->regmodrm.rm == 0b000 ||
2087416eaf02Smaxv instr->regmodrm.rm == 0b010) {
2088416eaf02Smaxv reg2 = NVMM_X64_GPR_RSI;
2089416eaf02Smaxv } else if (instr->regmodrm.rm == 0b001 ||
2090416eaf02Smaxv instr->regmodrm.rm == 0b011) {
2091416eaf02Smaxv reg2 = NVMM_X64_GPR_RDI;
2092416eaf02Smaxv } else {
2093416eaf02Smaxv DISASSEMBLER_BUG();
2094416eaf02Smaxv }
2095416eaf02Smaxv
2096416eaf02Smaxv instr->strm->type = STORE_DUALREG;
2097416eaf02Smaxv instr->strm->u.dualreg.reg1 = reg1;
2098416eaf02Smaxv instr->strm->u.dualreg.reg2 = reg2;
2099416eaf02Smaxv
2100416eaf02Smaxv if (instr->strm->disp.type == DISP_NONE) {
2101416eaf02Smaxv DISASSEMBLER_BUG();
2102416eaf02Smaxv } else if (instr->strm->disp.type == DISP_0) {
2103416eaf02Smaxv /* Indirect register addressing mode */
2104416eaf02Smaxv if (instr->opcode->immediate) {
2105416eaf02Smaxv fsm_advance(fsm, 1, node_immediate);
2106416eaf02Smaxv } else {
2107416eaf02Smaxv fsm_advance(fsm, 1, NULL);
2108416eaf02Smaxv }
2109416eaf02Smaxv } else {
2110416eaf02Smaxv fsm_advance(fsm, 1, node_disp);
2111416eaf02Smaxv }
2112416eaf02Smaxv
2113416eaf02Smaxv return 0;
2114416eaf02Smaxv }
2115416eaf02Smaxv
21163f62f34aSmaxv static const struct x86_reg *
get_register_idx(struct x86_instr * instr,uint8_t index)21173f62f34aSmaxv get_register_idx(struct x86_instr *instr, uint8_t index)
21183f62f34aSmaxv {
21193f62f34aSmaxv uint8_t enc = index;
21203f62f34aSmaxv const struct x86_reg *reg;
21213f62f34aSmaxv size_t regsize;
21223f62f34aSmaxv
21233f62f34aSmaxv regsize = instr->address_size;
21243f62f34aSmaxv reg = &gpr_map[instr->rexpref.x][enc][regsize-1];
21253f62f34aSmaxv
21263f62f34aSmaxv if (reg->num == -1) {
21273f62f34aSmaxv reg = resolve_special_register(instr, enc, regsize);
21283f62f34aSmaxv }
21293f62f34aSmaxv
21303f62f34aSmaxv return reg;
21313f62f34aSmaxv }
21323f62f34aSmaxv
21333f62f34aSmaxv static const struct x86_reg *
get_register_bas(struct x86_instr * instr,uint8_t base)21343f62f34aSmaxv get_register_bas(struct x86_instr *instr, uint8_t base)
21353f62f34aSmaxv {
21363f62f34aSmaxv uint8_t enc = base;
21373f62f34aSmaxv const struct x86_reg *reg;
21383f62f34aSmaxv size_t regsize;
21393f62f34aSmaxv
21403f62f34aSmaxv regsize = instr->address_size;
21413f62f34aSmaxv reg = &gpr_map[instr->rexpref.b][enc][regsize-1];
21423f62f34aSmaxv if (reg->num == -1) {
21433f62f34aSmaxv reg = resolve_special_register(instr, enc, regsize);
21443f62f34aSmaxv }
21453f62f34aSmaxv
21463f62f34aSmaxv return reg;
21473f62f34aSmaxv }
21483f62f34aSmaxv
21493f62f34aSmaxv static int
node_sib(struct x86_decode_fsm * fsm,struct x86_instr * instr)21503f62f34aSmaxv node_sib(struct x86_decode_fsm *fsm, struct x86_instr *instr)
21513f62f34aSmaxv {
21523f62f34aSmaxv const struct x86_opcode *opcode;
21533f62f34aSmaxv uint8_t scale, index, base;
21543f62f34aSmaxv bool noindex, nobase;
21553f62f34aSmaxv uint8_t byte;
21563f62f34aSmaxv
21573f62f34aSmaxv if (fsm_read(fsm, &byte, sizeof(byte)) == -1) {
21583f62f34aSmaxv return -1;
21593f62f34aSmaxv }
21603f62f34aSmaxv
21613f62f34aSmaxv scale = ((byte & 0b11000000) >> 6);
21623f62f34aSmaxv index = ((byte & 0b00111000) >> 3);
21633f62f34aSmaxv base = ((byte & 0b00000111) >> 0);
21643f62f34aSmaxv
21653f62f34aSmaxv opcode = instr->opcode;
21663f62f34aSmaxv
21673f62f34aSmaxv noindex = false;
21683f62f34aSmaxv nobase = false;
21693f62f34aSmaxv
21703f62f34aSmaxv if (index == 0b100 && !instr->rexpref.x) {
21713f62f34aSmaxv /* Special case: the index is null */
21723f62f34aSmaxv noindex = true;
21733f62f34aSmaxv }
21743f62f34aSmaxv
21753f62f34aSmaxv if (instr->regmodrm.mod == 0b00 && base == 0b101) {
21763f62f34aSmaxv /* Special case: the base is null + disp32 */
21773f62f34aSmaxv instr->strm->disp.type = DISP_4;
21783f62f34aSmaxv nobase = true;
21793f62f34aSmaxv }
21803f62f34aSmaxv
21813f62f34aSmaxv instr->strm->type = STORE_SIB;
21823f62f34aSmaxv instr->strm->u.sib.scale = (1 << scale);
21833f62f34aSmaxv if (!noindex)
21843f62f34aSmaxv instr->strm->u.sib.idx = get_register_idx(instr, index);
21853f62f34aSmaxv if (!nobase)
21863f62f34aSmaxv instr->strm->u.sib.bas = get_register_bas(instr, base);
21873f62f34aSmaxv
21883f62f34aSmaxv /* May have a displacement, or an immediate */
2189416eaf02Smaxv if (instr->strm->disp.type == DISP_1 ||
2190416eaf02Smaxv instr->strm->disp.type == DISP_2 ||
2191416eaf02Smaxv instr->strm->disp.type == DISP_4) {
21923f62f34aSmaxv fsm_advance(fsm, 1, node_disp);
21933f62f34aSmaxv } else if (opcode->immediate) {
21943f62f34aSmaxv fsm_advance(fsm, 1, node_immediate);
21953f62f34aSmaxv } else {
21963f62f34aSmaxv fsm_advance(fsm, 1, NULL);
21973f62f34aSmaxv }
21983f62f34aSmaxv
21993f62f34aSmaxv return 0;
22003f62f34aSmaxv }
22013f62f34aSmaxv
22023f62f34aSmaxv static const struct x86_reg *
get_register_reg(struct x86_instr * instr,const struct x86_opcode * opcode)22033f62f34aSmaxv get_register_reg(struct x86_instr *instr, const struct x86_opcode *opcode)
22043f62f34aSmaxv {
22053f62f34aSmaxv uint8_t enc = instr->regmodrm.reg;
22063f62f34aSmaxv const struct x86_reg *reg;
22073f62f34aSmaxv size_t regsize;
22083f62f34aSmaxv
22093f62f34aSmaxv regsize = instr->operand_size;
22103f62f34aSmaxv
22113f62f34aSmaxv reg = &gpr_map[instr->rexpref.r][enc][regsize-1];
22123f62f34aSmaxv if (reg->num == -1) {
22133f62f34aSmaxv reg = resolve_special_register(instr, enc, regsize);
22143f62f34aSmaxv }
22153f62f34aSmaxv
22163f62f34aSmaxv return reg;
22173f62f34aSmaxv }
22183f62f34aSmaxv
22193f62f34aSmaxv static const struct x86_reg *
get_register_rm(struct x86_instr * instr,const struct x86_opcode * opcode)22203f62f34aSmaxv get_register_rm(struct x86_instr *instr, const struct x86_opcode *opcode)
22213f62f34aSmaxv {
22223f62f34aSmaxv uint8_t enc = instr->regmodrm.rm;
22233f62f34aSmaxv const struct x86_reg *reg;
22243f62f34aSmaxv size_t regsize;
22253f62f34aSmaxv
22263f62f34aSmaxv if (instr->strm->disp.type == DISP_NONE) {
22273f62f34aSmaxv regsize = instr->operand_size;
22283f62f34aSmaxv } else {
22293f62f34aSmaxv /* Indirect access, the size is that of the address. */
22303f62f34aSmaxv regsize = instr->address_size;
22313f62f34aSmaxv }
22323f62f34aSmaxv
22333f62f34aSmaxv reg = &gpr_map[instr->rexpref.b][enc][regsize-1];
22343f62f34aSmaxv if (reg->num == -1) {
22353f62f34aSmaxv reg = resolve_special_register(instr, enc, regsize);
22363f62f34aSmaxv }
22373f62f34aSmaxv
22383f62f34aSmaxv return reg;
22393f62f34aSmaxv }
22403f62f34aSmaxv
22413f62f34aSmaxv static inline bool
has_sib(struct x86_instr * instr)22423f62f34aSmaxv has_sib(struct x86_instr *instr)
22433f62f34aSmaxv {
2244416eaf02Smaxv return (instr->address_size != 2 && /* no SIB in 16bit addressing */
2245416eaf02Smaxv instr->regmodrm.mod != 0b11 &&
2246416eaf02Smaxv instr->regmodrm.rm == 0b100);
22473f62f34aSmaxv }
22483f62f34aSmaxv
22493f62f34aSmaxv static inline bool
is_rip_relative(struct x86_decode_fsm * fsm,struct x86_instr * instr)22502e9744b3Smaxv is_rip_relative(struct x86_decode_fsm *fsm, struct x86_instr *instr)
22513f62f34aSmaxv {
2252416eaf02Smaxv return (fsm->is64bit && /* RIP-relative only in 64bit mode */
2253416eaf02Smaxv instr->regmodrm.mod == 0b00 &&
2254416eaf02Smaxv instr->regmodrm.rm == 0b101);
22552e9744b3Smaxv }
22562e9744b3Smaxv
22572e9744b3Smaxv static inline bool
is_disp32_only(struct x86_decode_fsm * fsm,struct x86_instr * instr)22582e9744b3Smaxv is_disp32_only(struct x86_decode_fsm *fsm, struct x86_instr *instr)
22592e9744b3Smaxv {
2260416eaf02Smaxv return (!fsm->is64bit && /* no disp32-only in 64bit mode */
2261416eaf02Smaxv instr->address_size != 2 && /* no disp32-only in 16bit addressing */
2262416eaf02Smaxv instr->regmodrm.mod == 0b00 &&
2263416eaf02Smaxv instr->regmodrm.rm == 0b101);
2264416eaf02Smaxv }
2265416eaf02Smaxv
2266416eaf02Smaxv static inline bool
is_disp16_only(struct x86_decode_fsm * fsm,struct x86_instr * instr)2267416eaf02Smaxv is_disp16_only(struct x86_decode_fsm *fsm, struct x86_instr *instr)
2268416eaf02Smaxv {
2269416eaf02Smaxv return (instr->address_size == 2 && /* disp16-only only in 16bit addr */
2270416eaf02Smaxv instr->regmodrm.mod == 0b00 &&
2271416eaf02Smaxv instr->regmodrm.rm == 0b110);
2272416eaf02Smaxv }
2273416eaf02Smaxv
2274416eaf02Smaxv static inline bool
is_dual(struct x86_decode_fsm * fsm,struct x86_instr * instr)2275416eaf02Smaxv is_dual(struct x86_decode_fsm *fsm, struct x86_instr *instr)
2276416eaf02Smaxv {
2277416eaf02Smaxv return (instr->address_size == 2 &&
2278416eaf02Smaxv instr->regmodrm.mod != 0b11 &&
2279416eaf02Smaxv instr->regmodrm.rm <= 0b011);
22803f62f34aSmaxv }
22813f62f34aSmaxv
22823f62f34aSmaxv static enum x86_disp_type
get_disp_type(struct x86_instr * instr)22833f62f34aSmaxv get_disp_type(struct x86_instr *instr)
22843f62f34aSmaxv {
22853f62f34aSmaxv switch (instr->regmodrm.mod) {
2286416eaf02Smaxv case 0b00: /* indirect */
22873f62f34aSmaxv return DISP_0;
2288416eaf02Smaxv case 0b01: /* indirect+1 */
22893f62f34aSmaxv return DISP_1;
2290416eaf02Smaxv case 0b10: /* indirect+{2,4} */
2291416eaf02Smaxv if (__predict_false(instr->address_size == 2)) {
2292416eaf02Smaxv return DISP_2;
2293416eaf02Smaxv }
22943f62f34aSmaxv return DISP_4;
2295416eaf02Smaxv case 0b11: /* direct */
2296e1d43b1eSmaxv default: /* llvm */
22973f62f34aSmaxv return DISP_NONE;
22983f62f34aSmaxv }
22997e53a6c0Sjoerg __unreachable();
23003f62f34aSmaxv }
23013f62f34aSmaxv
23023f62f34aSmaxv static int
node_regmodrm(struct x86_decode_fsm * fsm,struct x86_instr * instr)23033f62f34aSmaxv node_regmodrm(struct x86_decode_fsm *fsm, struct x86_instr *instr)
23043f62f34aSmaxv {
23053f62f34aSmaxv struct x86_store *strg, *strm;
23063f62f34aSmaxv const struct x86_opcode *opcode;
23073f62f34aSmaxv const struct x86_reg *reg;
23083f62f34aSmaxv uint8_t byte;
23093f62f34aSmaxv
23103f62f34aSmaxv if (fsm_read(fsm, &byte, sizeof(byte)) == -1) {
23113f62f34aSmaxv return -1;
23123f62f34aSmaxv }
23133f62f34aSmaxv
23143f62f34aSmaxv opcode = instr->opcode;
23153f62f34aSmaxv
23163f62f34aSmaxv instr->regmodrm.rm = ((byte & 0b00000111) >> 0);
23174977f2ebSmaxv instr->regmodrm.reg = ((byte & 0b00111000) >> 3);
23184977f2ebSmaxv instr->regmodrm.mod = ((byte & 0b11000000) >> 6);
23193f62f34aSmaxv
23203f62f34aSmaxv if (opcode->regtorm) {
23213f62f34aSmaxv strg = &instr->src;
23223f62f34aSmaxv strm = &instr->dst;
23233f62f34aSmaxv } else { /* RM to REG */
23243f62f34aSmaxv strm = &instr->src;
23253f62f34aSmaxv strg = &instr->dst;
23263f62f34aSmaxv }
23273f62f34aSmaxv
23283f62f34aSmaxv /* Save for later use. */
23293f62f34aSmaxv instr->strm = strm;
23303f62f34aSmaxv
23313f62f34aSmaxv /*
23323f62f34aSmaxv * Special cases: Groups. The REG field of REGMODRM is the index in
23333f62f34aSmaxv * the group. op1 gets overwritten in the Immediate node, if any.
23343f62f34aSmaxv */
2335960d1f76Smaxv if (opcode->group1) {
2336960d1f76Smaxv if (group1[instr->regmodrm.reg].emul == NULL) {
2337960d1f76Smaxv return -1;
2338960d1f76Smaxv }
2339960d1f76Smaxv instr->emul = group1[instr->regmodrm.reg].emul;
234083ed0b5eSmaxv } else if (opcode->group3) {
234183ed0b5eSmaxv if (group3[instr->regmodrm.reg].emul == NULL) {
234283ed0b5eSmaxv return -1;
234383ed0b5eSmaxv }
234483ed0b5eSmaxv instr->emul = group3[instr->regmodrm.reg].emul;
2345960d1f76Smaxv } else if (opcode->group11) {
23463f62f34aSmaxv if (group11[instr->regmodrm.reg].emul == NULL) {
23473f62f34aSmaxv return -1;
23483f62f34aSmaxv }
23493f62f34aSmaxv instr->emul = group11[instr->regmodrm.reg].emul;
23503f62f34aSmaxv }
23513f62f34aSmaxv
2352c07836beSmaxv if (!opcode->immediate) {
23533f62f34aSmaxv reg = get_register_reg(instr, opcode);
23543f62f34aSmaxv if (reg == NULL) {
23553f62f34aSmaxv return -1;
23563f62f34aSmaxv }
23573f62f34aSmaxv strg->type = STORE_REG;
23583f62f34aSmaxv strg->u.reg = reg;
2359c07836beSmaxv }
23603f62f34aSmaxv
23614cdf419dSmaxv /* The displacement applies to RM. */
23624cdf419dSmaxv strm->disp.type = get_disp_type(instr);
23634cdf419dSmaxv
23643f62f34aSmaxv if (has_sib(instr)) {
23653f62f34aSmaxv /* Overwrites RM */
23663f62f34aSmaxv fsm_advance(fsm, 1, node_sib);
23673f62f34aSmaxv return 0;
23683f62f34aSmaxv }
23693f62f34aSmaxv
23702e9744b3Smaxv if (is_rip_relative(fsm, instr)) {
23713f62f34aSmaxv /* Overwrites RM */
23723f62f34aSmaxv strm->type = STORE_REG;
23733f62f34aSmaxv strm->u.reg = &gpr_map__rip;
23743f62f34aSmaxv strm->disp.type = DISP_4;
23753f62f34aSmaxv fsm_advance(fsm, 1, node_disp);
23763f62f34aSmaxv return 0;
23773f62f34aSmaxv }
23783f62f34aSmaxv
23792e9744b3Smaxv if (is_disp32_only(fsm, instr)) {
23802e9744b3Smaxv /* Overwrites RM */
23812e9744b3Smaxv strm->type = STORE_REG;
23822e9744b3Smaxv strm->u.reg = NULL;
23832e9744b3Smaxv strm->disp.type = DISP_4;
23842e9744b3Smaxv fsm_advance(fsm, 1, node_disp);
23852e9744b3Smaxv return 0;
23862e9744b3Smaxv }
23872e9744b3Smaxv
2388416eaf02Smaxv if (__predict_false(is_disp16_only(fsm, instr))) {
2389416eaf02Smaxv /* Overwrites RM */
2390416eaf02Smaxv strm->type = STORE_REG;
2391416eaf02Smaxv strm->u.reg = NULL;
2392416eaf02Smaxv strm->disp.type = DISP_2;
2393416eaf02Smaxv fsm_advance(fsm, 1, node_disp);
2394416eaf02Smaxv return 0;
2395416eaf02Smaxv }
2396416eaf02Smaxv
2397416eaf02Smaxv if (__predict_false(is_dual(fsm, instr))) {
2398416eaf02Smaxv /* Overwrites RM */
2399416eaf02Smaxv fsm_advance(fsm, 0, node_dual);
2400416eaf02Smaxv return 0;
2401416eaf02Smaxv }
2402416eaf02Smaxv
24033f62f34aSmaxv reg = get_register_rm(instr, opcode);
24043f62f34aSmaxv if (reg == NULL) {
24053f62f34aSmaxv return -1;
24063f62f34aSmaxv }
24073f62f34aSmaxv strm->type = STORE_REG;
24083f62f34aSmaxv strm->u.reg = reg;
24093f62f34aSmaxv
24103f62f34aSmaxv if (strm->disp.type == DISP_NONE) {
24113f62f34aSmaxv /* Direct register addressing mode */
24123f62f34aSmaxv if (opcode->immediate) {
24133f62f34aSmaxv fsm_advance(fsm, 1, node_immediate);
24143f62f34aSmaxv } else {
24153f62f34aSmaxv fsm_advance(fsm, 1, NULL);
24163f62f34aSmaxv }
24173f62f34aSmaxv } else if (strm->disp.type == DISP_0) {
24183f62f34aSmaxv /* Indirect register addressing mode */
24193f62f34aSmaxv if (opcode->immediate) {
24203f62f34aSmaxv fsm_advance(fsm, 1, node_immediate);
24213f62f34aSmaxv } else {
24223f62f34aSmaxv fsm_advance(fsm, 1, NULL);
24233f62f34aSmaxv }
24243f62f34aSmaxv } else {
24253f62f34aSmaxv fsm_advance(fsm, 1, node_disp);
24263f62f34aSmaxv }
24273f62f34aSmaxv
24283f62f34aSmaxv return 0;
24293f62f34aSmaxv }
24303f62f34aSmaxv
24313f62f34aSmaxv static size_t
get_operand_size(struct x86_decode_fsm * fsm,struct x86_instr * instr)24323f62f34aSmaxv get_operand_size(struct x86_decode_fsm *fsm, struct x86_instr *instr)
24333f62f34aSmaxv {
24343f62f34aSmaxv const struct x86_opcode *opcode = instr->opcode;
24353f62f34aSmaxv int opsize;
24363f62f34aSmaxv
24373f62f34aSmaxv /* Get the opsize */
24383f62f34aSmaxv if (!opcode->szoverride) {
24393f62f34aSmaxv opsize = opcode->defsize;
24403f62f34aSmaxv } else if (instr->rexpref.present && instr->rexpref.w) {
24413f62f34aSmaxv opsize = 8;
24423f62f34aSmaxv } else {
24433f62f34aSmaxv if (!fsm->is16bit) {
244475c7df3cSmaxv if (instr->legpref.opr_ovr) {
24453f62f34aSmaxv opsize = 2;
24463f62f34aSmaxv } else {
24473f62f34aSmaxv opsize = 4;
24483f62f34aSmaxv }
24493f62f34aSmaxv } else { /* 16bit */
245075c7df3cSmaxv if (instr->legpref.opr_ovr) {
24513f62f34aSmaxv opsize = 4;
24523f62f34aSmaxv } else {
24533f62f34aSmaxv opsize = 2;
24543f62f34aSmaxv }
24553f62f34aSmaxv }
24563f62f34aSmaxv }
24573f62f34aSmaxv
24583f62f34aSmaxv return opsize;
24593f62f34aSmaxv }
24603f62f34aSmaxv
24613f62f34aSmaxv static size_t
get_address_size(struct x86_decode_fsm * fsm,struct x86_instr * instr)24623f62f34aSmaxv get_address_size(struct x86_decode_fsm *fsm, struct x86_instr *instr)
24633f62f34aSmaxv {
24643f62f34aSmaxv if (fsm->is64bit) {
246575c7df3cSmaxv if (__predict_false(instr->legpref.adr_ovr)) {
24663f62f34aSmaxv return 4;
24673f62f34aSmaxv }
24683f62f34aSmaxv return 8;
24693f62f34aSmaxv }
24703f62f34aSmaxv
24713f62f34aSmaxv if (fsm->is32bit) {
247275c7df3cSmaxv if (__predict_false(instr->legpref.adr_ovr)) {
24733f62f34aSmaxv return 2;
24743f62f34aSmaxv }
24753f62f34aSmaxv return 4;
24763f62f34aSmaxv }
24773f62f34aSmaxv
24783f62f34aSmaxv /* 16bit. */
247975c7df3cSmaxv if (__predict_false(instr->legpref.adr_ovr)) {
24803f62f34aSmaxv return 4;
24813f62f34aSmaxv }
24823f62f34aSmaxv return 2;
24833f62f34aSmaxv }
24843f62f34aSmaxv
24853f62f34aSmaxv static int
node_primary_opcode(struct x86_decode_fsm * fsm,struct x86_instr * instr)24863f62f34aSmaxv node_primary_opcode(struct x86_decode_fsm *fsm, struct x86_instr *instr)
24873f62f34aSmaxv {
24883f62f34aSmaxv const struct x86_opcode *opcode;
24893f62f34aSmaxv uint8_t byte;
24903f62f34aSmaxv
24913f62f34aSmaxv if (fsm_read(fsm, &byte, sizeof(byte)) == -1) {
24923f62f34aSmaxv return -1;
24933f62f34aSmaxv }
24943f62f34aSmaxv
24954977f2ebSmaxv opcode = &primary_opcode_table[byte];
24964977f2ebSmaxv if (__predict_false(!opcode->valid)) {
24973f62f34aSmaxv return -1;
24983f62f34aSmaxv }
24993f62f34aSmaxv
25003f62f34aSmaxv instr->opcode = opcode;
25013f62f34aSmaxv instr->emul = opcode->emul;
25023f62f34aSmaxv instr->operand_size = get_operand_size(fsm, instr);
25033f62f34aSmaxv instr->address_size = get_address_size(fsm, instr);
25043f62f34aSmaxv
25057ceb32d3Smaxv if (fsm->is64bit && (instr->operand_size == 4)) {
25067ceb32d3Smaxv /* Zero-extend to 64 bits. */
25077ceb32d3Smaxv instr->zeroextend_mask = ~size_to_mask(4);
25087ceb32d3Smaxv }
25097ceb32d3Smaxv
25103f62f34aSmaxv if (opcode->regmodrm) {
25113f62f34aSmaxv fsm_advance(fsm, 1, node_regmodrm);
25123f62f34aSmaxv } else if (opcode->dmo) {
25133f62f34aSmaxv /* Direct-Memory Offsets */
25143f62f34aSmaxv fsm_advance(fsm, 1, node_dmo);
25153f62f34aSmaxv } else if (opcode->stos || opcode->lods) {
25163f62f34aSmaxv fsm_advance(fsm, 1, node_stlo);
251738b2a665Smaxv } else if (opcode->movs) {
251838b2a665Smaxv fsm_advance(fsm, 1, node_movs);
2519*e6b71c14Sreinoud } else if (opcode->cmps) {
2520*e6b71c14Sreinoud fsm_advance(fsm, 1, node_cmps);
25213f62f34aSmaxv } else {
25223f62f34aSmaxv return -1;
25233f62f34aSmaxv }
25243f62f34aSmaxv
25253f62f34aSmaxv return 0;
25263f62f34aSmaxv }
25273f62f34aSmaxv
252880932742Smaxv static int
node_secondary_opcode(struct x86_decode_fsm * fsm,struct x86_instr * instr)252980932742Smaxv node_secondary_opcode(struct x86_decode_fsm *fsm, struct x86_instr *instr)
253080932742Smaxv {
253180932742Smaxv const struct x86_opcode *opcode;
253280932742Smaxv uint8_t byte;
253380932742Smaxv
253480932742Smaxv if (fsm_read(fsm, &byte, sizeof(byte)) == -1) {
253580932742Smaxv return -1;
253680932742Smaxv }
253780932742Smaxv
25384977f2ebSmaxv opcode = &secondary_opcode_table[byte];
25394977f2ebSmaxv if (__predict_false(!opcode->valid)) {
254080932742Smaxv return -1;
254180932742Smaxv }
254280932742Smaxv
254380932742Smaxv instr->opcode = opcode;
254480932742Smaxv instr->emul = opcode->emul;
254580932742Smaxv instr->operand_size = get_operand_size(fsm, instr);
254680932742Smaxv instr->address_size = get_address_size(fsm, instr);
254780932742Smaxv
25482089a381Smaxv if (fsm->is64bit && (instr->operand_size == 4)) {
25492089a381Smaxv /* Zero-extend to 64 bits. */
25502089a381Smaxv instr->zeroextend_mask = ~size_to_mask(4);
25512089a381Smaxv }
25522089a381Smaxv
2553960d1f76Smaxv if (opcode->flags & FLAG_ze) {
255480932742Smaxv /*
255580932742Smaxv * Compute the mask for zero-extend. Update the operand size,
255680932742Smaxv * we move fewer bytes.
255780932742Smaxv */
25582089a381Smaxv instr->zeroextend_mask |= size_to_mask(instr->operand_size);
255980932742Smaxv instr->zeroextend_mask &= ~size_to_mask(opcode->defsize);
256080932742Smaxv instr->operand_size = opcode->defsize;
256180932742Smaxv }
256280932742Smaxv
256380932742Smaxv if (opcode->regmodrm) {
256480932742Smaxv fsm_advance(fsm, 1, node_regmodrm);
256580932742Smaxv } else {
256680932742Smaxv return -1;
256780932742Smaxv }
256880932742Smaxv
256980932742Smaxv return 0;
257080932742Smaxv }
257180932742Smaxv
25723f62f34aSmaxv static int
node_main(struct x86_decode_fsm * fsm,struct x86_instr * instr)25733f62f34aSmaxv node_main(struct x86_decode_fsm *fsm, struct x86_instr *instr)
25743f62f34aSmaxv {
25753f62f34aSmaxv uint8_t byte;
25763f62f34aSmaxv
25773f62f34aSmaxv #define ESCAPE 0x0F
25783f62f34aSmaxv #define VEX_1 0xC5
25793f62f34aSmaxv #define VEX_2 0xC4
25803f62f34aSmaxv #define XOP 0x8F
25813f62f34aSmaxv
25823f62f34aSmaxv if (fsm_read(fsm, &byte, sizeof(byte)) == -1) {
25833f62f34aSmaxv return -1;
25843f62f34aSmaxv }
25853f62f34aSmaxv
25863f62f34aSmaxv /*
25873f62f34aSmaxv * We don't take XOP. It is AMD-specific, and it was removed shortly
25883f62f34aSmaxv * after being introduced.
25893f62f34aSmaxv */
25903f62f34aSmaxv if (byte == ESCAPE) {
259180932742Smaxv fsm_advance(fsm, 1, node_secondary_opcode);
25923f62f34aSmaxv } else if (!instr->rexpref.present) {
25933f62f34aSmaxv if (byte == VEX_1) {
25943f62f34aSmaxv return -1;
25953f62f34aSmaxv } else if (byte == VEX_2) {
25963f62f34aSmaxv return -1;
25973f62f34aSmaxv } else {
25983f62f34aSmaxv fsm->fn = node_primary_opcode;
25993f62f34aSmaxv }
26003f62f34aSmaxv } else {
26013f62f34aSmaxv fsm->fn = node_primary_opcode;
26023f62f34aSmaxv }
26033f62f34aSmaxv
26043f62f34aSmaxv return 0;
26053f62f34aSmaxv }
26063f62f34aSmaxv
26073f62f34aSmaxv static int
node_rex_prefix(struct x86_decode_fsm * fsm,struct x86_instr * instr)26083f62f34aSmaxv node_rex_prefix(struct x86_decode_fsm *fsm, struct x86_instr *instr)
26093f62f34aSmaxv {
26103f62f34aSmaxv struct x86_rexpref *rexpref = &instr->rexpref;
26113f62f34aSmaxv uint8_t byte;
26123f62f34aSmaxv size_t n = 0;
26133f62f34aSmaxv
26143f62f34aSmaxv if (fsm_read(fsm, &byte, sizeof(byte)) == -1) {
26153f62f34aSmaxv return -1;
26163f62f34aSmaxv }
26173f62f34aSmaxv
26183f62f34aSmaxv if (byte >= 0x40 && byte <= 0x4F) {
26193f62f34aSmaxv if (__predict_false(!fsm->is64bit)) {
26203f62f34aSmaxv return -1;
26213f62f34aSmaxv }
26223f62f34aSmaxv rexpref->b = ((byte & 0x1) != 0);
26234977f2ebSmaxv rexpref->x = ((byte & 0x2) != 0);
26244977f2ebSmaxv rexpref->r = ((byte & 0x4) != 0);
26254977f2ebSmaxv rexpref->w = ((byte & 0x8) != 0);
26264977f2ebSmaxv rexpref->present = true;
26273f62f34aSmaxv n = 1;
26283f62f34aSmaxv }
26293f62f34aSmaxv
26303f62f34aSmaxv fsm_advance(fsm, n, node_main);
26313f62f34aSmaxv return 0;
26323f62f34aSmaxv }
26333f62f34aSmaxv
26343f62f34aSmaxv static int
node_legacy_prefix(struct x86_decode_fsm * fsm,struct x86_instr * instr)26353f62f34aSmaxv node_legacy_prefix(struct x86_decode_fsm *fsm, struct x86_instr *instr)
26363f62f34aSmaxv {
26373f62f34aSmaxv uint8_t byte;
26383f62f34aSmaxv
26393f62f34aSmaxv if (fsm_read(fsm, &byte, sizeof(byte)) == -1) {
26403f62f34aSmaxv return -1;
26413f62f34aSmaxv }
26423f62f34aSmaxv
264375c7df3cSmaxv if (byte == LEG_OPR_OVR) {
264475c7df3cSmaxv instr->legpref.opr_ovr = 1;
264575c7df3cSmaxv } else if (byte == LEG_OVR_DS) {
264675c7df3cSmaxv instr->legpref.seg = NVMM_X64_SEG_DS;
264775c7df3cSmaxv } else if (byte == LEG_OVR_ES) {
264875c7df3cSmaxv instr->legpref.seg = NVMM_X64_SEG_ES;
264975c7df3cSmaxv } else if (byte == LEG_REP) {
265075c7df3cSmaxv instr->legpref.rep = 1;
265175c7df3cSmaxv } else if (byte == LEG_OVR_GS) {
265275c7df3cSmaxv instr->legpref.seg = NVMM_X64_SEG_GS;
265375c7df3cSmaxv } else if (byte == LEG_OVR_FS) {
265475c7df3cSmaxv instr->legpref.seg = NVMM_X64_SEG_FS;
265575c7df3cSmaxv } else if (byte == LEG_ADR_OVR) {
265675c7df3cSmaxv instr->legpref.adr_ovr = 1;
265775c7df3cSmaxv } else if (byte == LEG_OVR_CS) {
265875c7df3cSmaxv instr->legpref.seg = NVMM_X64_SEG_CS;
265975c7df3cSmaxv } else if (byte == LEG_OVR_SS) {
266075c7df3cSmaxv instr->legpref.seg = NVMM_X64_SEG_SS;
266175c7df3cSmaxv } else if (byte == LEG_REPN) {
266275c7df3cSmaxv instr->legpref.repn = 1;
266375c7df3cSmaxv } else if (byte == LEG_LOCK) {
266475c7df3cSmaxv /* ignore */
26653f62f34aSmaxv } else {
266675c7df3cSmaxv /* not a legacy prefix */
266775c7df3cSmaxv fsm_advance(fsm, 0, node_rex_prefix);
266875c7df3cSmaxv return 0;
26693f62f34aSmaxv }
26703f62f34aSmaxv
267175c7df3cSmaxv fsm_advance(fsm, 1, node_legacy_prefix);
26723f62f34aSmaxv return 0;
26733f62f34aSmaxv }
26743f62f34aSmaxv
26753f62f34aSmaxv static int
x86_decode(uint8_t * inst_bytes,size_t inst_len,struct x86_instr * instr,struct nvmm_x64_state * state)26763f62f34aSmaxv x86_decode(uint8_t *inst_bytes, size_t inst_len, struct x86_instr *instr,
26773f62f34aSmaxv struct nvmm_x64_state *state)
26783f62f34aSmaxv {
26793f62f34aSmaxv struct x86_decode_fsm fsm;
26803f62f34aSmaxv int ret;
26813f62f34aSmaxv
26823f62f34aSmaxv memset(instr, 0, sizeof(*instr));
268375c7df3cSmaxv instr->legpref.seg = -1;
26848d8eb34bSmaxv instr->src.hardseg = -1;
26858d8eb34bSmaxv instr->dst.hardseg = -1;
26863f62f34aSmaxv
26873f62f34aSmaxv fsm.is64bit = is_64bit(state);
26883f62f34aSmaxv fsm.is32bit = is_32bit(state);
26893f62f34aSmaxv fsm.is16bit = is_16bit(state);
26903f62f34aSmaxv
26913f62f34aSmaxv fsm.fn = node_legacy_prefix;
26923f62f34aSmaxv fsm.buf = inst_bytes;
26933f62f34aSmaxv fsm.end = inst_bytes + inst_len;
26943f62f34aSmaxv
26953f62f34aSmaxv while (fsm.fn != NULL) {
26963f62f34aSmaxv ret = (*fsm.fn)(&fsm, instr);
2697*e6b71c14Sreinoud if (ret == -1) {
2698*e6b71c14Sreinoud #ifdef NVMM_DEBUG
2699*e6b71c14Sreinoud printf("\n%s debug: unrecognized instruction found " \
2700*e6b71c14Sreinoud "with max length %ld : [ ", __func__, inst_len);
2701*e6b71c14Sreinoud for (uint i = 0; i < inst_len; i++)
2702*e6b71c14Sreinoud printf("%02x ", inst_bytes[i]);
2703*e6b71c14Sreinoud printf("]\n");
2704*e6b71c14Sreinoud fflush(stdout);
2705*e6b71c14Sreinoud #endif
27063f62f34aSmaxv return -1;
27073f62f34aSmaxv }
2708*e6b71c14Sreinoud }
27093f62f34aSmaxv
27103f62f34aSmaxv instr->len = fsm.buf - inst_bytes;
27113f62f34aSmaxv
27123f62f34aSmaxv return 0;
27133f62f34aSmaxv }
27143f62f34aSmaxv
27153f62f34aSmaxv /* -------------------------------------------------------------------------- */
27163f62f34aSmaxv
271783ed0b5eSmaxv #define EXEC_INSTR(sz, instr) \
271883ed0b5eSmaxv static uint##sz##_t \
271912f8b8a2Schristos exec_##instr##sz(uint##sz##_t op1, uint##sz##_t op2, uint64_t *rflags) \
272083ed0b5eSmaxv { \
272183ed0b5eSmaxv uint##sz##_t res; \
272283ed0b5eSmaxv __asm __volatile ( \
272383ed0b5eSmaxv #instr" %2, %3;" \
272483ed0b5eSmaxv "mov %3, %1;" \
272583ed0b5eSmaxv "pushfq;" \
272683ed0b5eSmaxv "popq %0" \
272783ed0b5eSmaxv : "=r" (*rflags), "=r" (res) \
272883ed0b5eSmaxv : "r" (op1), "r" (op2)); \
272983ed0b5eSmaxv return res; \
27303f62f34aSmaxv }
27313f62f34aSmaxv
273283ed0b5eSmaxv #define EXEC_DISPATCHER(instr) \
273383ed0b5eSmaxv static uint64_t \
273483ed0b5eSmaxv exec_##instr(uint64_t op1, uint64_t op2, uint64_t *rflags, size_t opsize) \
273583ed0b5eSmaxv { \
273683ed0b5eSmaxv switch (opsize) { \
273783ed0b5eSmaxv case 1: \
273883ed0b5eSmaxv return exec_##instr##8(op1, op2, rflags); \
273983ed0b5eSmaxv case 2: \
274083ed0b5eSmaxv return exec_##instr##16(op1, op2, rflags); \
274183ed0b5eSmaxv case 4: \
274283ed0b5eSmaxv return exec_##instr##32(op1, op2, rflags); \
274383ed0b5eSmaxv default: \
274483ed0b5eSmaxv return exec_##instr##64(op1, op2, rflags); \
274583ed0b5eSmaxv } \
274683ed0b5eSmaxv }
274783ed0b5eSmaxv
274883ed0b5eSmaxv /* SUB: ret = op1 - op2 */
274983ed0b5eSmaxv #define PSL_SUB_MASK (PSL_V|PSL_C|PSL_Z|PSL_N|PSL_PF|PSL_AF)
275083ed0b5eSmaxv EXEC_INSTR(8, sub)
275183ed0b5eSmaxv EXEC_INSTR(16, sub)
275283ed0b5eSmaxv EXEC_INSTR(32, sub)
275383ed0b5eSmaxv EXEC_INSTR(64, sub)
EXEC_DISPATCHER(sub)275483ed0b5eSmaxv EXEC_DISPATCHER(sub)
275583ed0b5eSmaxv
275683ed0b5eSmaxv /* OR: ret = op1 | op2 */
275783ed0b5eSmaxv #define PSL_OR_MASK (PSL_V|PSL_C|PSL_Z|PSL_N|PSL_PF)
275883ed0b5eSmaxv EXEC_INSTR(8, or)
275983ed0b5eSmaxv EXEC_INSTR(16, or)
276083ed0b5eSmaxv EXEC_INSTR(32, or)
276183ed0b5eSmaxv EXEC_INSTR(64, or)
276283ed0b5eSmaxv EXEC_DISPATCHER(or)
276383ed0b5eSmaxv
276483ed0b5eSmaxv /* AND: ret = op1 & op2 */
276583ed0b5eSmaxv #define PSL_AND_MASK (PSL_V|PSL_C|PSL_Z|PSL_N|PSL_PF)
276683ed0b5eSmaxv EXEC_INSTR(8, and)
276783ed0b5eSmaxv EXEC_INSTR(16, and)
276883ed0b5eSmaxv EXEC_INSTR(32, and)
276983ed0b5eSmaxv EXEC_INSTR(64, and)
277083ed0b5eSmaxv EXEC_DISPATCHER(and)
277183ed0b5eSmaxv
277283ed0b5eSmaxv /* XOR: ret = op1 ^ op2 */
277383ed0b5eSmaxv #define PSL_XOR_MASK (PSL_V|PSL_C|PSL_Z|PSL_N|PSL_PF)
277483ed0b5eSmaxv EXEC_INSTR(8, xor)
277583ed0b5eSmaxv EXEC_INSTR(16, xor)
277683ed0b5eSmaxv EXEC_INSTR(32, xor)
277783ed0b5eSmaxv EXEC_INSTR(64, xor)
277883ed0b5eSmaxv EXEC_DISPATCHER(xor)
277983ed0b5eSmaxv
278083ed0b5eSmaxv /* -------------------------------------------------------------------------- */
278183ed0b5eSmaxv
278283ed0b5eSmaxv /*
278383ed0b5eSmaxv * Emulation functions. We don't care about the order of the operands, except
278483ed0b5eSmaxv * for SUB, CMP and TEST. For these ones we look at mem->write to determine who
278583ed0b5eSmaxv * is op1 and who is op2.
278683ed0b5eSmaxv */
278783ed0b5eSmaxv
27883f62f34aSmaxv static void
2789e6f32a58Smaxv x86_func_or(struct nvmm_vcpu *vcpu, struct nvmm_mem *mem, uint64_t *gprs)
27903f62f34aSmaxv {
279183ed0b5eSmaxv uint64_t *retval = (uint64_t *)mem->data;
27923f62f34aSmaxv const bool write = mem->write;
279383ed0b5eSmaxv uint64_t *op1, op2, fl, ret;
27943f62f34aSmaxv
279583ed0b5eSmaxv op1 = (uint64_t *)mem->data;
279683ed0b5eSmaxv op2 = 0;
27973f62f34aSmaxv
279883ed0b5eSmaxv /* Fetch the value to be OR'ed (op2). */
279983ed0b5eSmaxv mem->data = (uint8_t *)&op2;
28003f62f34aSmaxv mem->write = false;
2801e6f32a58Smaxv (*vcpu->cbs.mem)(mem);
28023f62f34aSmaxv
28033f62f34aSmaxv /* Perform the OR. */
280483ed0b5eSmaxv ret = exec_or(*op1, op2, &fl, mem->size);
28053f62f34aSmaxv
28063f62f34aSmaxv if (write) {
28073f62f34aSmaxv /* Write back the result. */
280883ed0b5eSmaxv mem->data = (uint8_t *)&ret;
28093f62f34aSmaxv mem->write = true;
2810e6f32a58Smaxv (*vcpu->cbs.mem)(mem);
281183ed0b5eSmaxv } else {
281283ed0b5eSmaxv /* Return data to the caller. */
281383ed0b5eSmaxv *retval = ret;
28143f62f34aSmaxv }
28153f62f34aSmaxv
281683ed0b5eSmaxv gprs[NVMM_X64_GPR_RFLAGS] &= ~PSL_OR_MASK;
281783ed0b5eSmaxv gprs[NVMM_X64_GPR_RFLAGS] |= (fl & PSL_OR_MASK);
28183f62f34aSmaxv }
28193f62f34aSmaxv
28203f62f34aSmaxv static void
x86_func_and(struct nvmm_vcpu * vcpu,struct nvmm_mem * mem,uint64_t * gprs)2821e6f32a58Smaxv x86_func_and(struct nvmm_vcpu *vcpu, struct nvmm_mem *mem, uint64_t *gprs)
28223f62f34aSmaxv {
282383ed0b5eSmaxv uint64_t *retval = (uint64_t *)mem->data;
28243f62f34aSmaxv const bool write = mem->write;
282583ed0b5eSmaxv uint64_t *op1, op2, fl, ret;
28263f62f34aSmaxv
282783ed0b5eSmaxv op1 = (uint64_t *)mem->data;
282883ed0b5eSmaxv op2 = 0;
28293f62f34aSmaxv
283083ed0b5eSmaxv /* Fetch the value to be AND'ed (op2). */
283183ed0b5eSmaxv mem->data = (uint8_t *)&op2;
28323f62f34aSmaxv mem->write = false;
2833e6f32a58Smaxv (*vcpu->cbs.mem)(mem);
28343f62f34aSmaxv
28353f62f34aSmaxv /* Perform the AND. */
283683ed0b5eSmaxv ret = exec_and(*op1, op2, &fl, mem->size);
28373f62f34aSmaxv
28383f62f34aSmaxv if (write) {
28393f62f34aSmaxv /* Write back the result. */
284083ed0b5eSmaxv mem->data = (uint8_t *)&ret;
28413f62f34aSmaxv mem->write = true;
2842e6f32a58Smaxv (*vcpu->cbs.mem)(mem);
284383ed0b5eSmaxv } else {
284483ed0b5eSmaxv /* Return data to the caller. */
284583ed0b5eSmaxv *retval = ret;
28463f62f34aSmaxv }
28473f62f34aSmaxv
284883ed0b5eSmaxv gprs[NVMM_X64_GPR_RFLAGS] &= ~PSL_AND_MASK;
284983ed0b5eSmaxv gprs[NVMM_X64_GPR_RFLAGS] |= (fl & PSL_AND_MASK);
28503f62f34aSmaxv }
28513f62f34aSmaxv
28523f62f34aSmaxv static void
x86_func_xchg(struct nvmm_vcpu * vcpu,struct nvmm_mem * mem,uint64_t * gprs)2853e6f32a58Smaxv x86_func_xchg(struct nvmm_vcpu *vcpu, struct nvmm_mem *mem, uint64_t *gprs)
2854c496a7b1Smaxv {
2855c496a7b1Smaxv uint64_t *op1, op2;
2856c496a7b1Smaxv
2857c496a7b1Smaxv op1 = (uint64_t *)mem->data;
2858c496a7b1Smaxv op2 = 0;
2859c496a7b1Smaxv
2860c496a7b1Smaxv /* Fetch op2. */
2861c496a7b1Smaxv mem->data = (uint8_t *)&op2;
2862c496a7b1Smaxv mem->write = false;
2863e6f32a58Smaxv (*vcpu->cbs.mem)(mem);
2864c496a7b1Smaxv
2865c496a7b1Smaxv /* Write op1 in op2. */
2866c496a7b1Smaxv mem->data = (uint8_t *)op1;
2867c496a7b1Smaxv mem->write = true;
2868e6f32a58Smaxv (*vcpu->cbs.mem)(mem);
2869c496a7b1Smaxv
2870c496a7b1Smaxv /* Write op2 in op1. */
2871c496a7b1Smaxv *op1 = op2;
2872c496a7b1Smaxv }
2873c496a7b1Smaxv
2874c496a7b1Smaxv static void
x86_func_sub(struct nvmm_vcpu * vcpu,struct nvmm_mem * mem,uint64_t * gprs)2875e6f32a58Smaxv x86_func_sub(struct nvmm_vcpu *vcpu, struct nvmm_mem *mem, uint64_t *gprs)
28763f62f34aSmaxv {
287783ed0b5eSmaxv uint64_t *retval = (uint64_t *)mem->data;
28783f62f34aSmaxv const bool write = mem->write;
287983ed0b5eSmaxv uint64_t *op1, *op2, fl, ret;
288083ed0b5eSmaxv uint64_t tmp;
288183ed0b5eSmaxv bool memop1;
28823f62f34aSmaxv
288383ed0b5eSmaxv memop1 = !mem->write;
288483ed0b5eSmaxv op1 = memop1 ? &tmp : (uint64_t *)mem->data;
288583ed0b5eSmaxv op2 = memop1 ? (uint64_t *)mem->data : &tmp;
28863f62f34aSmaxv
288783ed0b5eSmaxv /* Fetch the value to be SUB'ed (op1 or op2). */
288883ed0b5eSmaxv mem->data = (uint8_t *)&tmp;
28893f62f34aSmaxv mem->write = false;
2890e6f32a58Smaxv (*vcpu->cbs.mem)(mem);
289183ed0b5eSmaxv
289283ed0b5eSmaxv /* Perform the SUB. */
289383ed0b5eSmaxv ret = exec_sub(*op1, *op2, &fl, mem->size);
289483ed0b5eSmaxv
289583ed0b5eSmaxv if (write) {
289683ed0b5eSmaxv /* Write back the result. */
289783ed0b5eSmaxv mem->data = (uint8_t *)&ret;
289883ed0b5eSmaxv mem->write = true;
2899e6f32a58Smaxv (*vcpu->cbs.mem)(mem);
290083ed0b5eSmaxv } else {
290183ed0b5eSmaxv /* Return data to the caller. */
290283ed0b5eSmaxv *retval = ret;
290383ed0b5eSmaxv }
290483ed0b5eSmaxv
290583ed0b5eSmaxv gprs[NVMM_X64_GPR_RFLAGS] &= ~PSL_SUB_MASK;
290683ed0b5eSmaxv gprs[NVMM_X64_GPR_RFLAGS] |= (fl & PSL_SUB_MASK);
290783ed0b5eSmaxv }
290883ed0b5eSmaxv
290983ed0b5eSmaxv static void
x86_func_xor(struct nvmm_vcpu * vcpu,struct nvmm_mem * mem,uint64_t * gprs)2910e6f32a58Smaxv x86_func_xor(struct nvmm_vcpu *vcpu, struct nvmm_mem *mem, uint64_t *gprs)
291183ed0b5eSmaxv {
291283ed0b5eSmaxv uint64_t *retval = (uint64_t *)mem->data;
291383ed0b5eSmaxv const bool write = mem->write;
291483ed0b5eSmaxv uint64_t *op1, op2, fl, ret;
291583ed0b5eSmaxv
291683ed0b5eSmaxv op1 = (uint64_t *)mem->data;
291783ed0b5eSmaxv op2 = 0;
291883ed0b5eSmaxv
291983ed0b5eSmaxv /* Fetch the value to be XOR'ed (op2). */
292083ed0b5eSmaxv mem->data = (uint8_t *)&op2;
292183ed0b5eSmaxv mem->write = false;
2922e6f32a58Smaxv (*vcpu->cbs.mem)(mem);
29233f62f34aSmaxv
29243f62f34aSmaxv /* Perform the XOR. */
292583ed0b5eSmaxv ret = exec_xor(*op1, op2, &fl, mem->size);
29263f62f34aSmaxv
29273f62f34aSmaxv if (write) {
29283f62f34aSmaxv /* Write back the result. */
292983ed0b5eSmaxv mem->data = (uint8_t *)&ret;
29303f62f34aSmaxv mem->write = true;
2931e6f32a58Smaxv (*vcpu->cbs.mem)(mem);
293283ed0b5eSmaxv } else {
293383ed0b5eSmaxv /* Return data to the caller. */
293483ed0b5eSmaxv *retval = ret;
29353f62f34aSmaxv }
29363f62f34aSmaxv
293783ed0b5eSmaxv gprs[NVMM_X64_GPR_RFLAGS] &= ~PSL_XOR_MASK;
293883ed0b5eSmaxv gprs[NVMM_X64_GPR_RFLAGS] |= (fl & PSL_XOR_MASK);
29393f62f34aSmaxv }
29403f62f34aSmaxv
29413f62f34aSmaxv static void
x86_func_cmp(struct nvmm_vcpu * vcpu,struct nvmm_mem * mem,uint64_t * gprs)2942e6f32a58Smaxv x86_func_cmp(struct nvmm_vcpu *vcpu, struct nvmm_mem *mem, uint64_t *gprs)
294383ed0b5eSmaxv {
294483ed0b5eSmaxv uint64_t *op1, *op2, fl;
294583ed0b5eSmaxv uint64_t tmp;
294683ed0b5eSmaxv bool memop1;
294783ed0b5eSmaxv
294883ed0b5eSmaxv memop1 = !mem->write;
294983ed0b5eSmaxv op1 = memop1 ? &tmp : (uint64_t *)mem->data;
295083ed0b5eSmaxv op2 = memop1 ? (uint64_t *)mem->data : &tmp;
295183ed0b5eSmaxv
295283ed0b5eSmaxv /* Fetch the value to be CMP'ed (op1 or op2). */
295383ed0b5eSmaxv mem->data = (uint8_t *)&tmp;
295483ed0b5eSmaxv mem->write = false;
2955e6f32a58Smaxv (*vcpu->cbs.mem)(mem);
295683ed0b5eSmaxv
295783ed0b5eSmaxv /* Perform the CMP. */
295883ed0b5eSmaxv exec_sub(*op1, *op2, &fl, mem->size);
295983ed0b5eSmaxv
296083ed0b5eSmaxv gprs[NVMM_X64_GPR_RFLAGS] &= ~PSL_SUB_MASK;
296183ed0b5eSmaxv gprs[NVMM_X64_GPR_RFLAGS] |= (fl & PSL_SUB_MASK);
296283ed0b5eSmaxv }
296383ed0b5eSmaxv
296483ed0b5eSmaxv static void
x86_func_test(struct nvmm_vcpu * vcpu,struct nvmm_mem * mem,uint64_t * gprs)2965e6f32a58Smaxv x86_func_test(struct nvmm_vcpu *vcpu, struct nvmm_mem *mem, uint64_t *gprs)
296683ed0b5eSmaxv {
296783ed0b5eSmaxv uint64_t *op1, *op2, fl;
296883ed0b5eSmaxv uint64_t tmp;
296983ed0b5eSmaxv bool memop1;
297083ed0b5eSmaxv
297183ed0b5eSmaxv memop1 = !mem->write;
297283ed0b5eSmaxv op1 = memop1 ? &tmp : (uint64_t *)mem->data;
297383ed0b5eSmaxv op2 = memop1 ? (uint64_t *)mem->data : &tmp;
297483ed0b5eSmaxv
297583ed0b5eSmaxv /* Fetch the value to be TEST'ed (op1 or op2). */
297683ed0b5eSmaxv mem->data = (uint8_t *)&tmp;
297783ed0b5eSmaxv mem->write = false;
2978e6f32a58Smaxv (*vcpu->cbs.mem)(mem);
297983ed0b5eSmaxv
298083ed0b5eSmaxv /* Perform the TEST. */
298183ed0b5eSmaxv exec_and(*op1, *op2, &fl, mem->size);
298283ed0b5eSmaxv
298383ed0b5eSmaxv gprs[NVMM_X64_GPR_RFLAGS] &= ~PSL_AND_MASK;
298483ed0b5eSmaxv gprs[NVMM_X64_GPR_RFLAGS] |= (fl & PSL_AND_MASK);
298583ed0b5eSmaxv }
298683ed0b5eSmaxv
298783ed0b5eSmaxv static void
x86_func_mov(struct nvmm_vcpu * vcpu,struct nvmm_mem * mem,uint64_t * gprs)2988e6f32a58Smaxv x86_func_mov(struct nvmm_vcpu *vcpu, struct nvmm_mem *mem, uint64_t *gprs)
29893f62f34aSmaxv {
29903f62f34aSmaxv /*
29913f62f34aSmaxv * Nothing special, just move without emulation.
29923f62f34aSmaxv */
2993e6f32a58Smaxv (*vcpu->cbs.mem)(mem);
29943f62f34aSmaxv }
29953f62f34aSmaxv
29963f62f34aSmaxv static void
x86_func_stos(struct nvmm_vcpu * vcpu,struct nvmm_mem * mem,uint64_t * gprs)2997e6f32a58Smaxv x86_func_stos(struct nvmm_vcpu *vcpu, struct nvmm_mem *mem, uint64_t *gprs)
29983f62f34aSmaxv {
29993f62f34aSmaxv /*
30003f62f34aSmaxv * Just move, and update RDI.
30013f62f34aSmaxv */
3002e6f32a58Smaxv (*vcpu->cbs.mem)(mem);
30033f62f34aSmaxv
30043f62f34aSmaxv if (gprs[NVMM_X64_GPR_RFLAGS] & PSL_D) {
30053f62f34aSmaxv gprs[NVMM_X64_GPR_RDI] -= mem->size;
30063f62f34aSmaxv } else {
30073f62f34aSmaxv gprs[NVMM_X64_GPR_RDI] += mem->size;
30083f62f34aSmaxv }
30093f62f34aSmaxv }
30103f62f34aSmaxv
30113f62f34aSmaxv static void
x86_func_lods(struct nvmm_vcpu * vcpu,struct nvmm_mem * mem,uint64_t * gprs)3012e6f32a58Smaxv x86_func_lods(struct nvmm_vcpu *vcpu, struct nvmm_mem *mem, uint64_t *gprs)
30133f62f34aSmaxv {
30143f62f34aSmaxv /*
30153f62f34aSmaxv * Just move, and update RSI.
30163f62f34aSmaxv */
3017e6f32a58Smaxv (*vcpu->cbs.mem)(mem);
30183f62f34aSmaxv
30193f62f34aSmaxv if (gprs[NVMM_X64_GPR_RFLAGS] & PSL_D) {
30203f62f34aSmaxv gprs[NVMM_X64_GPR_RSI] -= mem->size;
30213f62f34aSmaxv } else {
30223f62f34aSmaxv gprs[NVMM_X64_GPR_RSI] += mem->size;
30233f62f34aSmaxv }
30243f62f34aSmaxv }
30253f62f34aSmaxv
30263f62f34aSmaxv /* -------------------------------------------------------------------------- */
30273f62f34aSmaxv
30283f62f34aSmaxv static inline uint64_t
gpr_read_address(struct x86_instr * instr,struct nvmm_x64_state * state,int gpr)30293f62f34aSmaxv gpr_read_address(struct x86_instr *instr, struct nvmm_x64_state *state, int gpr)
30303f62f34aSmaxv {
30313f62f34aSmaxv uint64_t val;
30323f62f34aSmaxv
30333f62f34aSmaxv val = state->gprs[gpr];
30347ceb32d3Smaxv val &= size_to_mask(instr->address_size);
30353f62f34aSmaxv
30363f62f34aSmaxv return val;
30373f62f34aSmaxv }
30383f62f34aSmaxv
30393f62f34aSmaxv static int
store_to_gva(struct nvmm_x64_state * state,struct x86_instr * instr,struct x86_store * store,gvaddr_t * gvap,size_t size)304038b2a665Smaxv store_to_gva(struct nvmm_x64_state *state, struct x86_instr *instr,
304138b2a665Smaxv struct x86_store *store, gvaddr_t *gvap, size_t size)
30423f62f34aSmaxv {
30433f62f34aSmaxv struct x86_sib *sib;
304438b2a665Smaxv gvaddr_t gva = 0;
30453f62f34aSmaxv uint64_t reg;
30463f62f34aSmaxv int ret, seg;
30473f62f34aSmaxv
30483f62f34aSmaxv if (store->type == STORE_SIB) {
30493f62f34aSmaxv sib = &store->u.sib;
30503f62f34aSmaxv if (sib->bas != NULL)
30513f62f34aSmaxv gva += gpr_read_address(instr, state, sib->bas->num);
30523f62f34aSmaxv if (sib->idx != NULL) {
30533f62f34aSmaxv reg = gpr_read_address(instr, state, sib->idx->num);
30543f62f34aSmaxv gva += sib->scale * reg;
30553f62f34aSmaxv }
30563f62f34aSmaxv } else if (store->type == STORE_REG) {
30572e9744b3Smaxv if (store->u.reg == NULL) {
3058416eaf02Smaxv /* The base is null. Happens with disp32-only and
3059416eaf02Smaxv * disp16-only. */
30602e9744b3Smaxv } else {
30613f62f34aSmaxv gva = gpr_read_address(instr, state, store->u.reg->num);
30622e9744b3Smaxv }
3063416eaf02Smaxv } else if (store->type == STORE_DUALREG) {
3064416eaf02Smaxv gva = gpr_read_address(instr, state, store->u.dualreg.reg1) +
3065416eaf02Smaxv gpr_read_address(instr, state, store->u.dualreg.reg2);
30663f62f34aSmaxv } else {
30673f62f34aSmaxv gva = store->u.dmo;
30683f62f34aSmaxv }
30693f62f34aSmaxv
30703f62f34aSmaxv if (store->disp.type != DISP_NONE) {
3071960d1f76Smaxv gva += store->disp.data;
30723f62f34aSmaxv }
30733f62f34aSmaxv
30748d8eb34bSmaxv if (store->hardseg != -1) {
307538b2a665Smaxv seg = store->hardseg;
307638b2a665Smaxv } else {
307775c7df3cSmaxv if (__predict_false(instr->legpref.seg != -1)) {
307875c7df3cSmaxv seg = instr->legpref.seg;
30793f62f34aSmaxv } else {
30803f62f34aSmaxv seg = NVMM_X64_SEG_DS;
30813f62f34aSmaxv }
308238b2a665Smaxv }
30833f62f34aSmaxv
30847ceb32d3Smaxv if (__predict_true(is_long_mode(state))) {
30857ceb32d3Smaxv if (seg == NVMM_X64_SEG_GS || seg == NVMM_X64_SEG_FS) {
30867ceb32d3Smaxv segment_apply(&state->segs[seg], &gva);
30877ceb32d3Smaxv }
30887ceb32d3Smaxv } else {
30897ceb32d3Smaxv ret = segment_check(&state->segs[seg], gva, size);
30903f62f34aSmaxv if (ret == -1)
30913f62f34aSmaxv return -1;
30927ceb32d3Smaxv segment_apply(&state->segs[seg], &gva);
30933f62f34aSmaxv }
30943f62f34aSmaxv
309538b2a665Smaxv *gvap = gva;
309638b2a665Smaxv return 0;
309738b2a665Smaxv }
309838b2a665Smaxv
309938b2a665Smaxv static int
fetch_segment(struct nvmm_machine * mach,struct nvmm_vcpu * vcpu)3100e6f32a58Smaxv fetch_segment(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu)
3101579fb479Smaxv {
3102e6f32a58Smaxv struct nvmm_x64_state *state = vcpu->state;
3103f911f1c1Smaxv uint8_t inst_bytes[5], byte;
310475c7df3cSmaxv size_t i, fetchsize;
3105579fb479Smaxv gvaddr_t gva;
3106579fb479Smaxv int ret, seg;
3107579fb479Smaxv
3108579fb479Smaxv fetchsize = sizeof(inst_bytes);
3109579fb479Smaxv
3110579fb479Smaxv gva = state->gprs[NVMM_X64_GPR_RIP];
31117ceb32d3Smaxv if (__predict_false(!is_long_mode(state))) {
31127ceb32d3Smaxv ret = segment_check(&state->segs[NVMM_X64_SEG_CS], gva,
3113579fb479Smaxv fetchsize);
3114579fb479Smaxv if (ret == -1)
3115579fb479Smaxv return -1;
31167ceb32d3Smaxv segment_apply(&state->segs[NVMM_X64_SEG_CS], &gva);
3117579fb479Smaxv }
3118579fb479Smaxv
3119e6f32a58Smaxv ret = read_guest_memory(mach, vcpu, gva, inst_bytes, fetchsize);
3120579fb479Smaxv if (ret == -1)
3121579fb479Smaxv return -1;
3122579fb479Smaxv
3123579fb479Smaxv seg = NVMM_X64_SEG_DS;
312475c7df3cSmaxv for (i = 0; i < fetchsize; i++) {
312575c7df3cSmaxv byte = inst_bytes[i];
312675c7df3cSmaxv
312775c7df3cSmaxv if (byte == LEG_OVR_DS) {
312875c7df3cSmaxv seg = NVMM_X64_SEG_DS;
312975c7df3cSmaxv } else if (byte == LEG_OVR_ES) {
313075c7df3cSmaxv seg = NVMM_X64_SEG_ES;
313175c7df3cSmaxv } else if (byte == LEG_OVR_GS) {
313275c7df3cSmaxv seg = NVMM_X64_SEG_GS;
313375c7df3cSmaxv } else if (byte == LEG_OVR_FS) {
313475c7df3cSmaxv seg = NVMM_X64_SEG_FS;
313575c7df3cSmaxv } else if (byte == LEG_OVR_CS) {
313675c7df3cSmaxv seg = NVMM_X64_SEG_CS;
313775c7df3cSmaxv } else if (byte == LEG_OVR_SS) {
313875c7df3cSmaxv seg = NVMM_X64_SEG_SS;
313975c7df3cSmaxv } else if (byte == LEG_OPR_OVR) {
314075c7df3cSmaxv /* nothing */
314175c7df3cSmaxv } else if (byte == LEG_ADR_OVR) {
314275c7df3cSmaxv /* nothing */
314375c7df3cSmaxv } else if (byte == LEG_REP) {
314475c7df3cSmaxv /* nothing */
314575c7df3cSmaxv } else if (byte == LEG_REPN) {
314675c7df3cSmaxv /* nothing */
314775c7df3cSmaxv } else if (byte == LEG_LOCK) {
314875c7df3cSmaxv /* nothing */
314975c7df3cSmaxv } else {
315075c7df3cSmaxv return seg;
3151579fb479Smaxv }
3152579fb479Smaxv }
3153579fb479Smaxv
3154579fb479Smaxv return seg;
3155579fb479Smaxv }
3156579fb479Smaxv
3157579fb479Smaxv static int
fetch_instruction(struct nvmm_machine * mach,struct nvmm_vcpu * vcpu,struct nvmm_vcpu_exit * exit)3158e6f32a58Smaxv fetch_instruction(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu,
3159f9fb7866Smaxv struct nvmm_vcpu_exit *exit)
31603f62f34aSmaxv {
3161e6f32a58Smaxv struct nvmm_x64_state *state = vcpu->state;
316238b2a665Smaxv size_t fetchsize;
316338b2a665Smaxv gvaddr_t gva;
31643f62f34aSmaxv int ret;
31653f62f34aSmaxv
31663f62f34aSmaxv fetchsize = sizeof(exit->u.mem.inst_bytes);
31673f62f34aSmaxv
31683f62f34aSmaxv gva = state->gprs[NVMM_X64_GPR_RIP];
31697ceb32d3Smaxv if (__predict_false(!is_long_mode(state))) {
31707ceb32d3Smaxv ret = segment_check(&state->segs[NVMM_X64_SEG_CS], gva,
31713f62f34aSmaxv fetchsize);
31723f62f34aSmaxv if (ret == -1)
31733f62f34aSmaxv return -1;
31747ceb32d3Smaxv segment_apply(&state->segs[NVMM_X64_SEG_CS], &gva);
31753f62f34aSmaxv }
31763f62f34aSmaxv
3177e6f32a58Smaxv ret = read_guest_memory(mach, vcpu, gva, exit->u.mem.inst_bytes,
317838b2a665Smaxv fetchsize);
31793f62f34aSmaxv if (ret == -1)
31803f62f34aSmaxv return -1;
31813f62f34aSmaxv
31823f62f34aSmaxv exit->u.mem.inst_len = fetchsize;
318338b2a665Smaxv
318438b2a665Smaxv return 0;
31853f62f34aSmaxv }
31863f62f34aSmaxv
318738b2a665Smaxv static int
assist_mem_movs(struct nvmm_machine * mach,struct nvmm_vcpu * vcpu,struct x86_instr * instr)3188*e6b71c14Sreinoud assist_mem_movs(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu,
318938b2a665Smaxv struct x86_instr *instr)
319038b2a665Smaxv {
3191e6f32a58Smaxv struct nvmm_x64_state *state = vcpu->state;
3192*e6b71c14Sreinoud uint64_t *gprs;
319338b2a665Smaxv uint8_t data[8];
319438b2a665Smaxv gvaddr_t gva;
319538b2a665Smaxv size_t size;
319638b2a665Smaxv int ret;
319738b2a665Smaxv
319838b2a665Smaxv size = instr->operand_size;
3199*e6b71c14Sreinoud gprs = state->gprs;
320038b2a665Smaxv
320138b2a665Smaxv /* Source. */
320238b2a665Smaxv ret = store_to_gva(state, instr, &instr->src, &gva, size);
320338b2a665Smaxv if (ret == -1)
320438b2a665Smaxv return -1;
3205e6f32a58Smaxv ret = read_guest_memory(mach, vcpu, gva, data, size);
320638b2a665Smaxv if (ret == -1)
320738b2a665Smaxv return -1;
320838b2a665Smaxv
320938b2a665Smaxv /* Destination. */
321038b2a665Smaxv ret = store_to_gva(state, instr, &instr->dst, &gva, size);
321138b2a665Smaxv if (ret == -1)
321238b2a665Smaxv return -1;
3213e6f32a58Smaxv ret = write_guest_memory(mach, vcpu, gva, data, size);
321438b2a665Smaxv if (ret == -1)
321538b2a665Smaxv return -1;
321638b2a665Smaxv
3217*e6b71c14Sreinoud /*
3218*e6b71c14Sreinoud * Inlined x86_func_movs() call
3219*e6b71c14Sreinoud * (*instr->emul->func)(vcpu, &mem, state->gprs);
3220*e6b71c14Sreinoud */
3221*e6b71c14Sreinoud
3222*e6b71c14Sreinoud if (gprs[NVMM_X64_GPR_RFLAGS] & PSL_D) {
3223*e6b71c14Sreinoud gprs[NVMM_X64_GPR_RSI] -= size;
3224*e6b71c14Sreinoud gprs[NVMM_X64_GPR_RDI] -= size;
3225*e6b71c14Sreinoud } else {
3226*e6b71c14Sreinoud gprs[NVMM_X64_GPR_RSI] += size;
3227*e6b71c14Sreinoud gprs[NVMM_X64_GPR_RDI] += size;
3228*e6b71c14Sreinoud }
3229*e6b71c14Sreinoud
3230*e6b71c14Sreinoud return 0;
3231*e6b71c14Sreinoud }
3232*e6b71c14Sreinoud
3233*e6b71c14Sreinoud static int
assist_mem_cmps(struct nvmm_machine * mach,struct nvmm_vcpu * vcpu,struct x86_instr * instr)3234*e6b71c14Sreinoud assist_mem_cmps(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu,
3235*e6b71c14Sreinoud struct x86_instr *instr)
3236*e6b71c14Sreinoud {
3237*e6b71c14Sreinoud struct nvmm_x64_state *state = vcpu->state;
3238*e6b71c14Sreinoud uint64_t *gprs, op1, op2, fl;
3239*e6b71c14Sreinoud uint8_t data1[8], data2[8];
3240*e6b71c14Sreinoud gvaddr_t gva;
3241*e6b71c14Sreinoud size_t size;
3242*e6b71c14Sreinoud int ret;
3243*e6b71c14Sreinoud
3244*e6b71c14Sreinoud size = instr->operand_size;
3245*e6b71c14Sreinoud gprs = state->gprs;
3246*e6b71c14Sreinoud
3247*e6b71c14Sreinoud /* Source 1. */
3248*e6b71c14Sreinoud ret = store_to_gva(state, instr, &instr->src, &gva, size);
3249*e6b71c14Sreinoud if (ret == -1)
3250*e6b71c14Sreinoud return -1;
3251*e6b71c14Sreinoud ret = read_guest_memory(mach, vcpu, gva, data1, size);
3252*e6b71c14Sreinoud if (ret == -1)
3253*e6b71c14Sreinoud return -1;
3254*e6b71c14Sreinoud
3255*e6b71c14Sreinoud /* Source 2. */
3256*e6b71c14Sreinoud ret = store_to_gva(state, instr, &instr->dst, &gva, size);
3257*e6b71c14Sreinoud if (ret == -1)
3258*e6b71c14Sreinoud return -1;
3259*e6b71c14Sreinoud ret = read_guest_memory(mach, vcpu, gva, data2, size);
3260*e6b71c14Sreinoud if (ret == -1)
3261*e6b71c14Sreinoud return -1;
3262*e6b71c14Sreinoud
3263*e6b71c14Sreinoud /*
3264*e6b71c14Sreinoud * Inlined x86_func_cmps() call
3265*e6b71c14Sreinoud * (*instr->emul->func)(vcpu, &mem, state->gprs);
3266*e6b71c14Sreinoud */
3267*e6b71c14Sreinoud
3268*e6b71c14Sreinoud /* Perform the CMP. */
3269*e6b71c14Sreinoud op1 = *((uint64_t *) data1);
3270*e6b71c14Sreinoud op2 = *((uint64_t *) data2);
3271*e6b71c14Sreinoud exec_sub(op1, op2, &fl, size);
3272*e6b71c14Sreinoud
3273*e6b71c14Sreinoud gprs[NVMM_X64_GPR_RFLAGS] &= ~PSL_SUB_MASK;
3274*e6b71c14Sreinoud gprs[NVMM_X64_GPR_RFLAGS] |= (fl & PSL_SUB_MASK);
3275*e6b71c14Sreinoud
3276*e6b71c14Sreinoud if (gprs[NVMM_X64_GPR_RFLAGS] & PSL_D) {
3277*e6b71c14Sreinoud gprs[NVMM_X64_GPR_RSI] -= size;
3278*e6b71c14Sreinoud gprs[NVMM_X64_GPR_RDI] -= size;
3279*e6b71c14Sreinoud } else {
3280*e6b71c14Sreinoud gprs[NVMM_X64_GPR_RSI] += size;
3281*e6b71c14Sreinoud gprs[NVMM_X64_GPR_RDI] += size;
3282*e6b71c14Sreinoud }
328338b2a665Smaxv
32843f62f34aSmaxv return 0;
32853f62f34aSmaxv }
32863f62f34aSmaxv
328738b2a665Smaxv static int
assist_mem_single(struct nvmm_machine * mach,struct nvmm_vcpu * vcpu,struct x86_instr * instr)3288e6f32a58Smaxv assist_mem_single(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu,
3289e6f32a58Smaxv struct x86_instr *instr)
329038b2a665Smaxv {
3291e6f32a58Smaxv struct nvmm_x64_state *state = vcpu->state;
3292e6f32a58Smaxv struct nvmm_vcpu_exit *exit = vcpu->exit;
329338b2a665Smaxv struct nvmm_mem mem;
329480932742Smaxv uint8_t membuf[8];
329538b2a665Smaxv uint64_t val;
329638b2a665Smaxv
3297960d1f76Smaxv memset(membuf, 0, sizeof(membuf));
329804b8bfbfSmaxv
3299e6f32a58Smaxv mem.mach = mach;
3300e6f32a58Smaxv mem.vcpu = vcpu;
330104b8bfbfSmaxv mem.gpa = exit->u.mem.gpa;
330204b8bfbfSmaxv mem.size = instr->operand_size;
330380932742Smaxv mem.data = membuf;
330438b2a665Smaxv
330504b8bfbfSmaxv /* Determine the direction. */
330638b2a665Smaxv switch (instr->src.type) {
330738b2a665Smaxv case STORE_REG:
330838b2a665Smaxv if (instr->src.disp.type != DISP_NONE) {
330938b2a665Smaxv /* Indirect access. */
331038b2a665Smaxv mem.write = false;
331138b2a665Smaxv } else {
331238b2a665Smaxv /* Direct access. */
331338b2a665Smaxv mem.write = true;
331404b8bfbfSmaxv }
331504b8bfbfSmaxv break;
3316416eaf02Smaxv case STORE_DUALREG:
3317416eaf02Smaxv if (instr->src.disp.type == DISP_NONE) {
3318416eaf02Smaxv DISASSEMBLER_BUG();
3319416eaf02Smaxv }
3320416eaf02Smaxv mem.write = false;
3321416eaf02Smaxv break;
332204b8bfbfSmaxv case STORE_IMM:
332304b8bfbfSmaxv mem.write = true;
332404b8bfbfSmaxv break;
332504b8bfbfSmaxv case STORE_SIB:
332604b8bfbfSmaxv mem.write = false;
332704b8bfbfSmaxv break;
332804b8bfbfSmaxv case STORE_DMO:
332904b8bfbfSmaxv mem.write = false;
333004b8bfbfSmaxv break;
333104b8bfbfSmaxv default:
333204b8bfbfSmaxv DISASSEMBLER_BUG();
333304b8bfbfSmaxv }
333404b8bfbfSmaxv
333504b8bfbfSmaxv if (mem.write) {
333604b8bfbfSmaxv switch (instr->src.type) {
333704b8bfbfSmaxv case STORE_REG:
3338c496a7b1Smaxv /* The instruction was "reg -> mem". Fetch the register
3339c496a7b1Smaxv * in membuf. */
3340c496a7b1Smaxv if (__predict_false(instr->src.disp.type != DISP_NONE)) {
334104b8bfbfSmaxv DISASSEMBLER_BUG();
334204b8bfbfSmaxv }
334338b2a665Smaxv val = state->gprs[instr->src.u.reg->num];
334438b2a665Smaxv val = __SHIFTOUT(val, instr->src.u.reg->mask);
334538b2a665Smaxv memcpy(mem.data, &val, mem.size);
334638b2a665Smaxv break;
334738b2a665Smaxv case STORE_IMM:
3348c496a7b1Smaxv /* The instruction was "imm -> mem". Fetch the immediate
3349c496a7b1Smaxv * in membuf. */
3350960d1f76Smaxv memcpy(mem.data, &instr->src.u.imm.data, mem.size);
335138b2a665Smaxv break;
335238b2a665Smaxv default:
335338b2a665Smaxv DISASSEMBLER_BUG();
335438b2a665Smaxv }
3355c496a7b1Smaxv } else if (instr->emul->readreg) {
3356c496a7b1Smaxv /* The instruction was "mem -> reg", but the value of the
3357c496a7b1Smaxv * register matters for the emul func. Fetch it in membuf. */
3358c496a7b1Smaxv if (__predict_false(instr->dst.type != STORE_REG)) {
335904b8bfbfSmaxv DISASSEMBLER_BUG();
336004b8bfbfSmaxv }
3361c496a7b1Smaxv if (__predict_false(instr->dst.disp.type != DISP_NONE)) {
336283ed0b5eSmaxv DISASSEMBLER_BUG();
336383ed0b5eSmaxv }
336483ed0b5eSmaxv val = state->gprs[instr->dst.u.reg->num];
336583ed0b5eSmaxv val = __SHIFTOUT(val, instr->dst.u.reg->mask);
336683ed0b5eSmaxv memcpy(mem.data, &val, mem.size);
336783ed0b5eSmaxv }
336883ed0b5eSmaxv
3369e6f32a58Smaxv (*instr->emul->func)(vcpu, &mem, state->gprs);
337083ed0b5eSmaxv
3371c496a7b1Smaxv if (instr->emul->notouch) {
3372c496a7b1Smaxv /* We're done. */
3373c496a7b1Smaxv return 0;
3374c496a7b1Smaxv }
3375c496a7b1Smaxv
3376c496a7b1Smaxv if (!mem.write) {
3377c496a7b1Smaxv /* The instruction was "mem -> reg". The emul func has filled
3378c496a7b1Smaxv * membuf with the memory content. Install membuf in the
3379c496a7b1Smaxv * register. */
3380c496a7b1Smaxv if (__predict_false(instr->dst.type != STORE_REG)) {
3381c496a7b1Smaxv DISASSEMBLER_BUG();
3382c496a7b1Smaxv }
3383c496a7b1Smaxv if (__predict_false(instr->dst.disp.type != DISP_NONE)) {
338483ed0b5eSmaxv DISASSEMBLER_BUG();
338583ed0b5eSmaxv }
338683ed0b5eSmaxv memcpy(&val, membuf, sizeof(uint64_t));
338738b2a665Smaxv val = __SHIFTIN(val, instr->dst.u.reg->mask);
338838b2a665Smaxv state->gprs[instr->dst.u.reg->num] &= ~instr->dst.u.reg->mask;
338938b2a665Smaxv state->gprs[instr->dst.u.reg->num] |= val;
339080932742Smaxv state->gprs[instr->dst.u.reg->num] &= ~instr->zeroextend_mask;
3391c496a7b1Smaxv } else if (instr->emul->backprop) {
3392c496a7b1Smaxv /* The instruction was "reg -> mem", but the memory must be
3393c496a7b1Smaxv * back-propagated to the register. Install membuf in the
3394c496a7b1Smaxv * register. */
3395c496a7b1Smaxv if (__predict_false(instr->src.type != STORE_REG)) {
3396c496a7b1Smaxv DISASSEMBLER_BUG();
3397c496a7b1Smaxv }
3398c496a7b1Smaxv if (__predict_false(instr->src.disp.type != DISP_NONE)) {
3399c496a7b1Smaxv DISASSEMBLER_BUG();
3400c496a7b1Smaxv }
3401c496a7b1Smaxv memcpy(&val, membuf, sizeof(uint64_t));
3402c496a7b1Smaxv val = __SHIFTIN(val, instr->src.u.reg->mask);
3403c496a7b1Smaxv state->gprs[instr->src.u.reg->num] &= ~instr->src.u.reg->mask;
3404c496a7b1Smaxv state->gprs[instr->src.u.reg->num] |= val;
3405c496a7b1Smaxv state->gprs[instr->src.u.reg->num] &= ~instr->zeroextend_mask;
340638b2a665Smaxv }
340738b2a665Smaxv
340838b2a665Smaxv return 0;
340938b2a665Smaxv }
341038b2a665Smaxv
34112760ca24Smaxv int
nvmm_assist_mem(struct nvmm_machine * mach,struct nvmm_vcpu * vcpu)3412d1002cd7Smaxv nvmm_assist_mem(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu)
34132760ca24Smaxv {
3414d1002cd7Smaxv struct nvmm_x64_state *state = vcpu->state;
3415f9fb7866Smaxv struct nvmm_vcpu_exit *exit = vcpu->exit;
34163f62f34aSmaxv struct x86_instr instr;
34177ceb32d3Smaxv uint64_t cnt = 0; /* GCC */
34183f62f34aSmaxv int ret;
34193f62f34aSmaxv
3420f9fb7866Smaxv if (__predict_false(exit->reason != NVMM_VCPU_EXIT_MEMORY)) {
34212760ca24Smaxv errno = EINVAL;
34222760ca24Smaxv return -1;
34232760ca24Smaxv }
34242760ca24Smaxv
3425d1002cd7Smaxv ret = nvmm_vcpu_getstate(mach, vcpu,
34267ceb32d3Smaxv NVMM_X64_STATE_GPRS | NVMM_X64_STATE_SEGS |
34277ceb32d3Smaxv NVMM_X64_STATE_CRS | NVMM_X64_STATE_MSRS);
34283f62f34aSmaxv if (ret == -1)
34292760ca24Smaxv return -1;
34303f62f34aSmaxv
34313f62f34aSmaxv if (exit->u.mem.inst_len == 0) {
34323f62f34aSmaxv /*
34333f62f34aSmaxv * The instruction was not fetched from the kernel. Fetch
34343f62f34aSmaxv * it ourselves.
34353f62f34aSmaxv */
3436e6f32a58Smaxv ret = fetch_instruction(mach, vcpu, exit);
34373f62f34aSmaxv if (ret == -1)
34383f62f34aSmaxv return -1;
34393f62f34aSmaxv }
34403f62f34aSmaxv
34413f62f34aSmaxv ret = x86_decode(exit->u.mem.inst_bytes, exit->u.mem.inst_len,
3442d1002cd7Smaxv &instr, state);
34433f62f34aSmaxv if (ret == -1) {
34443f62f34aSmaxv errno = ENODEV;
34453f62f34aSmaxv return -1;
34463f62f34aSmaxv }
34473f62f34aSmaxv
34487ceb32d3Smaxv if (instr.legpref.rep || instr.legpref.repn) {
3449d1002cd7Smaxv cnt = rep_get_cnt(state, instr.address_size);
34507ceb32d3Smaxv if (__predict_false(cnt == 0)) {
3451d1002cd7Smaxv state->gprs[NVMM_X64_GPR_RIP] += instr.len;
34527ceb32d3Smaxv goto out;
34537ceb32d3Smaxv }
34547ceb32d3Smaxv }
34557ceb32d3Smaxv
345638b2a665Smaxv if (instr.opcode->movs) {
3457*e6b71c14Sreinoud ret = assist_mem_movs(mach, vcpu, &instr);
3458*e6b71c14Sreinoud } else if (instr.opcode->cmps) {
3459*e6b71c14Sreinoud instr.legpref.repe = !instr.legpref.repn;
3460*e6b71c14Sreinoud ret = assist_mem_cmps(mach, vcpu, &instr);
34613f62f34aSmaxv } else {
3462e6f32a58Smaxv ret = assist_mem_single(mach, vcpu, &instr);
34633f62f34aSmaxv }
346438b2a665Smaxv if (ret == -1) {
346538b2a665Smaxv errno = ENODEV;
34663f62f34aSmaxv return -1;
34673f62f34aSmaxv }
34683f62f34aSmaxv
346906484a82Smaxv if (instr.legpref.rep || instr.legpref.repn) {
34707ceb32d3Smaxv cnt -= 1;
3471d1002cd7Smaxv rep_set_cnt(state, instr.address_size, cnt);
347238b2a665Smaxv if (cnt == 0) {
3473d1002cd7Smaxv state->gprs[NVMM_X64_GPR_RIP] += instr.len;
347406484a82Smaxv } else if (__predict_false(instr.legpref.repn)) {
3475*e6b71c14Sreinoud /* repn */
3476d1002cd7Smaxv if (state->gprs[NVMM_X64_GPR_RFLAGS] & PSL_Z) {
3477d1002cd7Smaxv state->gprs[NVMM_X64_GPR_RIP] += instr.len;
347806484a82Smaxv }
3479*e6b71c14Sreinoud } else if (__predict_false(instr.legpref.repe)) {
3480*e6b71c14Sreinoud /* repe */
3481*e6b71c14Sreinoud if ((state->gprs[NVMM_X64_GPR_RFLAGS] & PSL_Z) == 0) {
3482*e6b71c14Sreinoud state->gprs[NVMM_X64_GPR_RIP] += instr.len;
3483*e6b71c14Sreinoud }
34843f62f34aSmaxv }
34853f62f34aSmaxv } else {
3486d1002cd7Smaxv state->gprs[NVMM_X64_GPR_RIP] += instr.len;
34873f62f34aSmaxv }
34883f62f34aSmaxv
34897ceb32d3Smaxv out:
3490d1002cd7Smaxv ret = nvmm_vcpu_setstate(mach, vcpu, NVMM_X64_STATE_GPRS);
34913f62f34aSmaxv if (ret == -1)
34923f62f34aSmaxv return -1;
34933f62f34aSmaxv
34943f62f34aSmaxv return 0;
34952760ca24Smaxv }
3496