diff options
author | Dan McDonald <danmcd@mnx.io> | 2022-11-06 23:04:04 -0500 |
---|---|---|
committer | Dan McDonald <danmcd@mnx.io> | 2022-11-06 23:04:04 -0500 |
commit | d6e6c033222e8067ec1dfeb10a4ee03139b6168c (patch) | |
tree | 404802c4b32f00af2021b6dcdcfc6c3c501b9826 /usr/src/uts/intel/io | |
parent | 33edda4c44df77895e91c50a9a02028873cd0ee6 (diff) | |
parent | 1fde93bfc5537d4261d6ef3ac9db44a76d697e75 (diff) | |
download | illumos-joyent-d6e6c033222e8067ec1dfeb10a4ee03139b6168c.tar.gz |
[illumos-gate merge]
commit 1fde93bfc5537d4261d6ef3ac9db44a76d697e75
14489 bhyve should emulate imul
commit 77ef2e2dc992015d6c68f5923c0216f6d000fc96
15120 dtest missing dependency on CPU counters
commit 5fcf5f8704b3d1b7e6175f9cb17fea58f5e56cdb
15119 truss could support IP, IPv6 sockopts
15115 IP_DONTFRAG could use docs
commit 0accf5554adfa8ff02c02d58042253bfa597bfa2
15114 IP_DONTFRAG more like IP please frag
commit b18d44ce328fbdf8d8c82ef1763d30b8a46edfde
14535 cfgadm_usb(8) should provide iSerialNumber in -v output
commit 4f3f3e9a1dee62c031fa67cfe64e11d6dd3fab1b
14763 bhyve upstream sync 2022 August
commit cfed4d7055842c539437036c634e7fe84d10977d
15085 mech_krb5: memory leaked during context establishment
commit 549ab26f262a63e8892b99d530a98fea6423ad63
15084 SMBD leaks memory during startup/refresh
commit 56a2adb63cd7b5ba73bb3f0fb3930b2d2730513e
15082 SMB Clients see but can't access restricted named streams
commit 66a9cc68640459b14e330f94bcab980ef58fd66d
14957 pcieadm overloads header1.iobasehi
Diffstat (limited to 'usr/src/uts/intel/io')
-rw-r--r-- | usr/src/uts/intel/io/vmm/amd/amdvi_hw.c | 7 | ||||
-rw-r--r-- | usr/src/uts/intel/io/vmm/amd/svm.c | 10 | ||||
-rw-r--r-- | usr/src/uts/intel/io/vmm/amd/vmcb.h | 1 | ||||
-rw-r--r-- | usr/src/uts/intel/io/vmm/intel/vmx.c | 20 | ||||
-rw-r--r-- | usr/src/uts/intel/io/vmm/sys/vmm_kernel.h | 1 | ||||
-rw-r--r-- | usr/src/uts/intel/io/vmm/vmm.c | 14 | ||||
-rw-r--r-- | usr/src/uts/intel/io/vmm/vmm_instruction_emul.c | 139 |
7 files changed, 184 insertions, 8 deletions
diff --git a/usr/src/uts/intel/io/vmm/amd/amdvi_hw.c b/usr/src/uts/intel/io/vmm/amd/amdvi_hw.c index 33a2557492..c217b19112 100644 --- a/usr/src/uts/intel/io/vmm/amd/amdvi_hw.c +++ b/usr/src/uts/intel/io/vmm/amd/amdvi_hw.c @@ -418,7 +418,7 @@ amdvi_cmd_inv_intr_map(struct amdvi_softc *softc, static void amdvi_inv_domain(struct amdvi_softc *softc, uint16_t domain_id) { - struct amdvi_cmd *cmd; + struct amdvi_cmd *cmd __diagused; cmd = amdvi_get_cmd_tail(softc); KASSERT(cmd != NULL, ("Cmd is NULL")); @@ -439,13 +439,14 @@ amdvi_inv_domain(struct amdvi_softc *softc, uint16_t domain_id) static bool amdvi_cmp_wait(struct amdvi_softc *softc) { - struct amdvi_ctrl *ctrl; +#ifdef AMDVI_DEBUG_CMD + struct amdvi_ctrl *ctrl = softc->ctrl; +#endif const uint64_t VERIFY = 0xA5A5; volatile uint64_t *read; int i; bool status; - ctrl = softc->ctrl; read = &softc->cmp_data; *read = 0; amdvi_cmd_cmp(softc, VERIFY); diff --git a/usr/src/uts/intel/io/vmm/amd/svm.c b/usr/src/uts/intel/io/vmm/amd/svm.c index f4f01ea4b6..a20a844030 100644 --- a/usr/src/uts/intel/io/vmm/amd/svm.c +++ b/usr/src/uts/intel/io/vmm/amd/svm.c @@ -378,6 +378,10 @@ vmcb_init(struct svm_softc *sc, int vcpu, uint64_t iopm_base_pa, svm_enable_intercept(sc, vcpu, VMCB_CTRL2_INTCPT, VMCB_INTCPT_STGI); svm_enable_intercept(sc, vcpu, VMCB_CTRL2_INTCPT, VMCB_INTCPT_CLGI); svm_enable_intercept(sc, vcpu, VMCB_CTRL2_INTCPT, VMCB_INTCPT_SKINIT); + if (vcpu_trap_wbinvd(sc->vm, vcpu) != 0) { + svm_enable_intercept(sc, vcpu, VMCB_CTRL2_INTCPT, + VMCB_INTCPT_WBINVD); + } /* * The ASID will be set to a non-zero value just before VMRUN. @@ -1448,7 +1452,6 @@ svm_vmexit(struct svm_softc *svm_sc, int vcpu, struct vm_exit *vmexit) (void) vm_suspend(svm_sc->vm, VM_SUSPEND_TRIPLEFAULT); handled = 1; break; - case VMCB_EXIT_INVD: case VMCB_EXIT_INVLPGA: /* privileged invalidation instructions */ vm_inject_ud(svm_sc->vm, vcpu); @@ -1464,6 +1467,11 @@ svm_vmexit(struct svm_softc *svm_sc, int vcpu, struct vm_exit *vmexit) vm_inject_ud(svm_sc->vm, vcpu); handled = 1; break; + case VMCB_EXIT_INVD: + case VMCB_EXIT_WBINVD: + /* ignore exit */ + handled = 1; + break; case VMCB_EXIT_VMMCALL: /* No handlers make use of VMMCALL for now */ vm_inject_ud(svm_sc->vm, vcpu); diff --git a/usr/src/uts/intel/io/vmm/amd/vmcb.h b/usr/src/uts/intel/io/vmm/amd/vmcb.h index 7a57979d56..91e00193bf 100644 --- a/usr/src/uts/intel/io/vmm/amd/vmcb.h +++ b/usr/src/uts/intel/io/vmm/amd/vmcb.h @@ -172,6 +172,7 @@ struct svm_softc; #define VMCB_EXIT_STGI 0x84 #define VMCB_EXIT_CLGI 0x85 #define VMCB_EXIT_SKINIT 0x86 +#define VMCB_EXIT_WBINVD 0x89 #define VMCB_EXIT_MONITOR 0x8A #define VMCB_EXIT_MWAIT 0x8B #define VMCB_EXIT_NPF 0x400 diff --git a/usr/src/uts/intel/io/vmm/intel/vmx.c b/usr/src/uts/intel/io/vmm/intel/vmx.c index c16fe1f1d4..e42455a0f3 100644 --- a/usr/src/uts/intel/io/vmm/intel/vmx.c +++ b/usr/src/uts/intel/io/vmm/intel/vmx.c @@ -188,6 +188,9 @@ static int vmx_initialized; /* PAUSE triggers a VM-exit */ static int cap_pause_exit; +/* WBINVD triggers a VM-exit */ +static int cap_wbinvd_exit; + /* Monitor trap flag */ static int cap_monitor_trap; @@ -548,6 +551,11 @@ vmx_init(void) PROCBASED_PAUSE_EXITING, 0, &tmp) == 0); + cap_wbinvd_exit = (vmx_set_ctlreg(MSR_VMX_PROCBASED_CTLS2, + MSR_VMX_PROCBASED_CTLS2, + PROCBASED2_WBINVD_EXITING, 0, + &tmp) == 0); + cap_invpcid = (vmx_set_ctlreg(MSR_VMX_PROCBASED_CTLS2, MSR_VMX_PROCBASED_CTLS2, PROCBASED2_ENABLE_INVPCID, 0, &tmp) == 0); @@ -819,7 +827,12 @@ vmx_vminit(struct vm *vm) vmcs_write(VMCS_EPTP, vmx->eptp); vmcs_write(VMCS_PIN_BASED_CTLS, pin_ctls); vmcs_write(VMCS_PRI_PROC_BASED_CTLS, proc_ctls); - vmcs_write(VMCS_SEC_PROC_BASED_CTLS, proc2_ctls); + + uint32_t use_proc2_ctls = proc2_ctls; + if (cap_wbinvd_exit && vcpu_trap_wbinvd(vm, i) != 0) + use_proc2_ctls |= PROCBASED2_WBINVD_EXITING; + vmcs_write(VMCS_SEC_PROC_BASED_CTLS, use_proc2_ctls); + vmcs_write(VMCS_EXIT_CTLS, exit_ctls); vmcs_write(VMCS_ENTRY_CTLS, entry_ctls); vmcs_write(VMCS_MSR_BITMAP, msr_bitmap_pa); @@ -2530,6 +2543,11 @@ vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit) SDT_PROBE3(vmm, vmx, exit, vminsn, vmx, vcpu, vmexit); vmexit->exitcode = VM_EXITCODE_VMINSN; break; + case EXIT_REASON_INVD: + case EXIT_REASON_WBINVD: + /* ignore exit */ + handled = HANDLED; + break; default: SDT_PROBE4(vmm, vmx, exit, unknown, vmx, vcpu, vmexit, reason); diff --git a/usr/src/uts/intel/io/vmm/sys/vmm_kernel.h b/usr/src/uts/intel/io/vmm/sys/vmm_kernel.h index c5c7d7889e..1ef2d48adf 100644 --- a/usr/src/uts/intel/io/vmm/sys/vmm_kernel.h +++ b/usr/src/uts/intel/io/vmm/sys/vmm_kernel.h @@ -358,6 +358,7 @@ void vm_copyout(struct vm *vm, int vcpuid, const void *kaddr, struct vm_copyinfo *copyinfo, size_t len); int vcpu_trace_exceptions(struct vm *vm, int vcpuid); +int vcpu_trap_wbinvd(struct vm *vm, int vcpuid); void vm_inject_ud(struct vm *vm, int vcpuid); void vm_inject_gp(struct vm *vm, int vcpuid); diff --git a/usr/src/uts/intel/io/vmm/vmm.c b/usr/src/uts/intel/io/vmm/vmm.c index 44f1ee5ca2..136c38c5ab 100644 --- a/usr/src/uts/intel/io/vmm/vmm.c +++ b/usr/src/uts/intel/io/vmm/vmm.c @@ -286,10 +286,13 @@ SYSCTL_NODE(_hw, OID_AUTO, vmm, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, * Halt the guest if all vcpus are executing a HLT instruction with * interrupts disabled. */ -static int halt_detection_enabled = 1; +int halt_detection_enabled = 1; /* Trap into hypervisor on all guest exceptions and reflect them back */ -static int trace_guest_exceptions; +int trace_guest_exceptions; + +/* Trap WBINVD and ignore it */ +int trap_wbinvd = 1; static void vm_free_memmap(struct vm *vm, int ident); static bool sysmem_mapping(struct vm *vm, struct mem_map *mm); @@ -403,10 +406,15 @@ vcpu_init(struct vm *vm, int vcpu_id, bool create) int vcpu_trace_exceptions(struct vm *vm, int vcpuid) { - return (trace_guest_exceptions); } +int +vcpu_trap_wbinvd(struct vm *vm, int vcpuid) +{ + return (trap_wbinvd); +} + struct vm_exit * vm_exitinfo(struct vm *vm, int cpuid) { diff --git a/usr/src/uts/intel/io/vmm/vmm_instruction_emul.c b/usr/src/uts/intel/io/vmm/vmm_instruction_emul.c index 14c78f411d..9fbb923cd9 100644 --- a/usr/src/uts/intel/io/vmm/vmm_instruction_emul.c +++ b/usr/src/uts/intel/io/vmm/vmm_instruction_emul.c @@ -182,6 +182,7 @@ enum { VIE_OP_TYPE_TEST, VIE_OP_TYPE_BEXTR, VIE_OP_TYPE_CLTS, + VIE_OP_TYPE_MUL, VIE_OP_TYPE_LAST }; @@ -220,6 +221,10 @@ static const struct vie_op two_byte_opcodes[256] = { .op_byte = 0xAE, .op_type = VIE_OP_TYPE_TWOB_GRP15, }, + [0xAF] = { + .op_byte = 0xAF, + .op_type = VIE_OP_TYPE_MUL, + }, [0xB6] = { .op_byte = 0xB6, .op_type = VIE_OP_TYPE_MOVZX, @@ -419,6 +424,25 @@ static enum vm_reg_name gpr_map[16] = { VM_REG_GUEST_R15 }; +static const char *gpr_name_map[][16] = { + [1] = { + "a[hl]", "c[hl]", "d[hl]", "b[hl]", "spl", "bpl", "sil", "dil", + "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b", + }, + [2] = { + "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", + "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w", + }, + [4] = { + "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", + "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d", + }, + [8] = { + "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + }, +}; + static enum vm_reg_name cr_map[16] = { VM_REG_GUEST_CR0, VM_REG_LAST, @@ -477,6 +501,14 @@ vie_regnum_map(uint8_t regnum) return (gpr_map[regnum]); } +const char * +vie_regnum_name(uint8_t regnum, uint8_t size) +{ + VERIFY3U(regnum, <, 16); + VERIFY(size == 1 || size == 2 || size == 4 || size == 8); + return (gpr_name_map[size][regnum]); +} + static void vie_calc_bytereg(struct vie *vie, enum vm_reg_name *reg, int *lhbr) { @@ -679,6 +711,40 @@ getaddflags(int opsize, uint64_t x, uint64_t y) } /* + * Macro creation of functions getimulflags{16,32,64} + */ +/* BEGIN CSTYLED */ +#define GETIMULFLAGS(sz) \ +static ulong_t \ +getimulflags##sz(uint##sz##_t x, uint##sz##_t y) \ +{ \ + ulong_t rflags; \ + \ + __asm __volatile("imul %2,%1; pushfq; popq %0" : \ + "=r" (rflags), "+r" (x) : "m" (y)); \ + return (rflags); \ +} struct __hack +/* END CSTYLED */ + +GETIMULFLAGS(16); +GETIMULFLAGS(32); +GETIMULFLAGS(64); + +static ulong_t +getimulflags(int opsize, uint64_t x, uint64_t y) +{ + KASSERT(opsize == 2 || opsize == 4 || opsize == 8, + ("getimulflags: invalid operand size %d", opsize)); + + if (opsize == 2) + return (getimulflags16(x, y)); + else if (opsize == 4) + return (getimulflags32(x, y)); + else + return (getimulflags64(x, y)); +} + +/* * Return the status flags that would result from doing (x & y). */ /* BEGIN CSTYLED */ @@ -1843,6 +1909,76 @@ vie_emulate_sub(struct vie *vie, struct vm *vm, int vcpuid, uint64_t gpa) } static int +vie_emulate_mul(struct vie *vie, struct vm *vm, int vcpuid, uint64_t gpa) +{ + int error, size; + uint64_t rflags, rflags2, val1, val2; + __int128_t nval; + enum vm_reg_name reg; + ulong_t (*getflags)(int, uint64_t, uint64_t) = NULL; + + size = vie->opsize; + error = EINVAL; + + switch (vie->op.op_byte) { + case 0xAF: + /* + * Multiply the contents of a destination register by + * the contents of a register or memory operand and + * put the signed result in the destination register. + * + * AF/r IMUL r16, r/m16 + * AF/r IMUL r32, r/m32 + * REX.W + AF/r IMUL r64, r/m64 + */ + + getflags = getimulflags; + + /* get the first operand */ + reg = gpr_map[vie->reg]; + error = vm_get_register(vm, vcpuid, reg, &val1); + if (error != 0) + break; + + /* get the second operand */ + error = vie_mmio_read(vie, vm, vcpuid, gpa, &val2, size); + if (error != 0) + break; + + /* perform the operation and write the result */ + nval = (int64_t)val1 * (int64_t)val2; + + error = vie_update_register(vm, vcpuid, reg, nval, size); + + DTRACE_PROBE4(vie__imul, + const char *, vie_regnum_name(vie->reg, size), + uint64_t, val1, uint64_t, val2, __uint128_t, nval); + + break; + default: + break; + } + + if (error == 0) { + rflags2 = getflags(size, val1, val2); + error = vm_get_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, + &rflags); + if (error) + return (error); + + rflags &= ~RFLAGS_STATUS_BITS; + rflags |= rflags2 & RFLAGS_STATUS_BITS; + error = vie_update_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, + rflags, 8); + + DTRACE_PROBE2(vie__imul__rflags, + uint64_t, rflags, uint64_t, rflags2); + } + + return (error); +} + +static int vie_emulate_stack_op(struct vie *vie, struct vm *vm, int vcpuid, uint64_t gpa) { struct vm_copyinfo copyinfo[2]; @@ -2244,6 +2380,9 @@ vie_emulate_mmio(struct vie *vie, struct vm *vm, int vcpuid) case VIE_OP_TYPE_BEXTR: error = vie_emulate_bextr(vie, vm, vcpuid, gpa); break; + case VIE_OP_TYPE_MUL: + error = vie_emulate_mul(vie, vm, vcpuid, gpa); + break; default: error = EINVAL; break; |