summaryrefslogtreecommitdiff
path: root/usr/src/uts/intel/io
diff options
context:
space:
mode:
authorDan McDonald <danmcd@mnx.io>2022-11-06 23:04:04 -0500
committerDan McDonald <danmcd@mnx.io>2022-11-06 23:04:04 -0500
commitd6e6c033222e8067ec1dfeb10a4ee03139b6168c (patch)
tree404802c4b32f00af2021b6dcdcfc6c3c501b9826 /usr/src/uts/intel/io
parent33edda4c44df77895e91c50a9a02028873cd0ee6 (diff)
parent1fde93bfc5537d4261d6ef3ac9db44a76d697e75 (diff)
downloadillumos-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.c7
-rw-r--r--usr/src/uts/intel/io/vmm/amd/svm.c10
-rw-r--r--usr/src/uts/intel/io/vmm/amd/vmcb.h1
-rw-r--r--usr/src/uts/intel/io/vmm/intel/vmx.c20
-rw-r--r--usr/src/uts/intel/io/vmm/sys/vmm_kernel.h1
-rw-r--r--usr/src/uts/intel/io/vmm/vmm.c14
-rw-r--r--usr/src/uts/intel/io/vmm/vmm_instruction_emul.c139
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;