summaryrefslogtreecommitdiffstats
path: root/sys/amd64/vmm
diff options
context:
space:
mode:
authorneel <neel@FreeBSD.org>2014-10-14 21:02:33 +0000
committerneel <neel@FreeBSD.org>2014-10-14 21:02:33 +0000
commit268d74c73af1c767169539f7643faf5c5dab0b7e (patch)
tree4691b3e00cdb6ef3344521872a63d84d2e181c38 /sys/amd64/vmm
parent11a43062e88f70b200a22f55d472124cfee3ee1c (diff)
downloadFreeBSD-src-268d74c73af1c767169539f7643faf5c5dab0b7e.zip
FreeBSD-src-268d74c73af1c767169539f7643faf5c5dab0b7e.tar.gz
Emulate "POP r/m".
This is needed to boot OpenBSD/i386 MP kernel in bhyve. Reported by: grehan MFC after: 1 week
Diffstat (limited to 'sys/amd64/vmm')
-rw-r--r--sys/amd64/vmm/vmm_instruction_emul.c97
1 files changed, 77 insertions, 20 deletions
diff --git a/sys/amd64/vmm/vmm_instruction_emul.c b/sys/amd64/vmm/vmm_instruction_emul.c
index 0d48895..c6ba01e 100644
--- a/sys/amd64/vmm/vmm_instruction_emul.c
+++ b/sys/amd64/vmm/vmm_instruction_emul.c
@@ -69,6 +69,7 @@ enum {
VIE_OP_TYPE_TWO_BYTE,
VIE_OP_TYPE_PUSH,
VIE_OP_TYPE_CMP,
+ VIE_OP_TYPE_POP,
VIE_OP_TYPE_LAST
};
@@ -159,6 +160,11 @@ static const struct vie_op one_byte_opcodes[256] = {
.op_type = VIE_OP_TYPE_OR,
.op_flags = VIE_OP_F_IMM8,
},
+ [0x8F] = {
+ /* XXX Group 1A extended opcode - not just POP */
+ .op_byte = 0x8F,
+ .op_type = VIE_OP_TYPE_POP,
+ },
[0xFF] = {
/* XXX Group 5 extended opcode - not just PUSH */
.op_byte = 0xFF,
@@ -821,7 +827,7 @@ emulate_sub(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
}
static int
-emulate_push(void *vm, int vcpuid, uint64_t mmio_gpa, struct vie *vie,
+emulate_stack_op(void *vm, int vcpuid, uint64_t mmio_gpa, struct vie *vie,
struct vm_guest_paging *paging, mem_region_read_t memread,
mem_region_write_t memwrite, void *arg)
{
@@ -832,18 +838,12 @@ emulate_push(void *vm, int vcpuid, uint64_t mmio_gpa, struct vie *vie,
#endif
struct seg_desc ss_desc;
uint64_t cr0, rflags, rsp, stack_gla, val;
- int error, size, stackaddrsize;
-
- /*
- * Table A-6, "Opcode Extensions", Intel SDM, Vol 2.
- *
- * PUSH is part of the group 5 extended opcodes and is identified
- * by ModRM:reg = b110.
- */
- if ((vie->reg & 7) != 6)
- return (EINVAL);
+ int error, size, stackaddrsize, pushop;
+ val = 0;
size = vie->opsize;
+ pushop = (vie->op.op_type == VIE_OP_TYPE_PUSH) ? 1 : 0;
+
/*
* From "Address-Size Attributes for Stack Accesses", Intel SDL, Vol 1
*/
@@ -882,10 +882,13 @@ emulate_push(void *vm, int vcpuid, uint64_t mmio_gpa, struct vie *vie,
error = vie_read_register(vm, vcpuid, VM_REG_GUEST_RSP, &rsp);
KASSERT(error == 0, ("%s: error %d getting rsp", __func__, error));
+ if (pushop) {
+ rsp -= size;
+ }
- rsp -= size;
if (vie_calculate_gla(paging->cpu_mode, VM_REG_GUEST_SS, &ss_desc,
- rsp, size, stackaddrsize, PROT_WRITE, &stack_gla)) {
+ rsp, size, stackaddrsize, pushop ? PROT_WRITE : PROT_READ,
+ &stack_gla)) {
vm_inject_ss(vm, vcpuid, 0);
return (0);
}
@@ -900,8 +903,8 @@ emulate_push(void *vm, int vcpuid, uint64_t mmio_gpa, struct vie *vie,
return (0);
}
- error = vm_copy_setup(vm, vcpuid, paging, stack_gla, size, PROT_WRITE,
- copyinfo, nitems(copyinfo));
+ error = vm_copy_setup(vm, vcpuid, paging, stack_gla, size,
+ pushop ? PROT_WRITE : PROT_READ, copyinfo, nitems(copyinfo));
if (error == -1) {
/*
* XXX cannot return a negative error value here because it
@@ -914,16 +917,66 @@ emulate_push(void *vm, int vcpuid, uint64_t mmio_gpa, struct vie *vie,
return (0);
}
- error = memread(vm, vcpuid, mmio_gpa, &val, size, arg);
+ if (pushop) {
+ error = memread(vm, vcpuid, mmio_gpa, &val, size, arg);
+ if (error == 0)
+ vm_copyout(vm, vcpuid, &val, copyinfo, size);
+ } else {
+ vm_copyin(vm, vcpuid, copyinfo, &val, size);
+ error = memwrite(vm, vcpuid, mmio_gpa, val, size, arg);
+ rsp += size;
+ }
+#ifdef _KERNEL
+ vm_copy_teardown(vm, vcpuid, copyinfo, nitems(copyinfo));
+#endif
+
if (error == 0) {
- vm_copyout(vm, vcpuid, &val, copyinfo, size);
error = vie_update_register(vm, vcpuid, VM_REG_GUEST_RSP, rsp,
stackaddrsize);
KASSERT(error == 0, ("error %d updating rsp", error));
}
-#ifdef _KERNEL
- vm_copy_teardown(vm, vcpuid, copyinfo, nitems(copyinfo));
-#endif
+ return (error);
+}
+
+static int
+emulate_push(void *vm, int vcpuid, uint64_t mmio_gpa, struct vie *vie,
+ struct vm_guest_paging *paging, mem_region_read_t memread,
+ mem_region_write_t memwrite, void *arg)
+{
+ int error;
+
+ /*
+ * Table A-6, "Opcode Extensions", Intel SDM, Vol 2.
+ *
+ * PUSH is part of the group 5 extended opcodes and is identified
+ * by ModRM:reg = b110.
+ */
+ if ((vie->reg & 7) != 6)
+ return (EINVAL);
+
+ error = emulate_stack_op(vm, vcpuid, mmio_gpa, vie, paging, memread,
+ memwrite, arg);
+ return (error);
+}
+
+static int
+emulate_pop(void *vm, int vcpuid, uint64_t mmio_gpa, struct vie *vie,
+ struct vm_guest_paging *paging, mem_region_read_t memread,
+ mem_region_write_t memwrite, void *arg)
+{
+ int error;
+
+ /*
+ * Table A-6, "Opcode Extensions", Intel SDM, Vol 2.
+ *
+ * POP is part of the group 1A extended opcodes and is identified
+ * by ModRM:reg = b000.
+ */
+ if ((vie->reg & 7) != 0)
+ return (EINVAL);
+
+ error = emulate_stack_op(vm, vcpuid, mmio_gpa, vie, paging, memread,
+ memwrite, arg);
return (error);
}
@@ -938,6 +991,10 @@ vmm_emulate_instruction(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
return (EINVAL);
switch (vie->op.op_type) {
+ case VIE_OP_TYPE_POP:
+ error = emulate_pop(vm, vcpuid, gpa, vie, paging, memread,
+ memwrite, memarg);
+ break;
case VIE_OP_TYPE_PUSH:
error = emulate_push(vm, vcpuid, gpa, vie, paging, memread,
memwrite, memarg);
OpenPOWER on IntegriCloud