summaryrefslogtreecommitdiffstats
path: root/sys/amd64
diff options
context:
space:
mode:
authorneel <neel@FreeBSD.org>2014-07-24 23:01:53 +0000
committerneel <neel@FreeBSD.org>2014-07-24 23:01:53 +0000
commit563faffd70680046c3f7fa9006056290ed2d712b (patch)
treeaa4138c30e09c29823f382de0479612c95183612 /sys/amd64
parentc6ab5d746c37cac49f50a1579f5d9147ad4c176d (diff)
downloadFreeBSD-src-563faffd70680046c3f7fa9006056290ed2d712b.zip
FreeBSD-src-563faffd70680046c3f7fa9006056290ed2d712b.tar.gz
Fix a couple of issues in the PUSH emulation:
It is not possible to PUSH a 32-bit operand on the stack in 64-bit mode. The default operand size for PUSH is 64-bits and the operand size override prefix changes that to 16-bits. vm_copy_setup() can return '1' if it encounters a fault when walking the guest page tables. This is a guest issue and is now handled properly by resuming the guest to handle the fault.
Diffstat (limited to 'sys/amd64')
-rw-r--r--sys/amd64/vmm/vmm_instruction_emul.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/sys/amd64/vmm/vmm_instruction_emul.c b/sys/amd64/vmm/vmm_instruction_emul.c
index e8a5f7b..b145f69 100644
--- a/sys/amd64/vmm/vmm_instruction_emul.c
+++ b/sys/amd64/vmm/vmm_instruction_emul.c
@@ -726,11 +726,19 @@ emulate_push(void *vm, int vcpuid, uint64_t mmio_gpa, struct vie *vie,
/*
* From "Address-Size Attributes for Stack Accesses", Intel SDL, Vol 1
*/
- if (paging->cpu_mode == CPU_MODE_REAL)
+ if (paging->cpu_mode == CPU_MODE_REAL) {
stackaddrsize = 2;
- else if (paging->cpu_mode == CPU_MODE_64BIT)
+ } else if (paging->cpu_mode == CPU_MODE_64BIT) {
+ /*
+ * "Stack Manipulation Instructions in 64-bit Mode", SDM, Vol 3
+ * - Stack pointer size is always 64-bits.
+ * - PUSH/POP of 32-bit values is not possible in 64-bit mode.
+ * - 16-bit PUSH/POP is supported by using the operand size
+ * override prefix (66H).
+ */
stackaddrsize = 8;
- else {
+ size = vie->opsize_override ? 2 : 8;
+ } else {
/*
* In protected or compability mode the 'B' flag in the
* stack-segment descriptor determines the size of the
@@ -773,8 +781,10 @@ emulate_push(void *vm, int vcpuid, uint64_t mmio_gpa, struct vie *vie,
error = vm_copy_setup(vm, vcpuid, paging, stack_gla, size, PROT_WRITE,
copyinfo, nitems(copyinfo));
- if (error)
- return (error);
+ if (error == -1)
+ return (-1); /* Unrecoverable error */
+ else if (error == 1)
+ return (0); /* Return to guest to handle page fault */
error = memread(vm, vcpuid, mmio_gpa, &val, size, arg);
if (error == 0) {
OpenPOWER on IntegriCloud