diff options
author | jkim <jkim@FreeBSD.org> | 2012-04-16 19:31:44 +0000 |
---|---|---|
committer | jkim <jkim@FreeBSD.org> | 2012-04-16 19:31:44 +0000 |
commit | da5eae8899f5e2cb43ecccc320f644abeb47be00 (patch) | |
tree | 054d5675d80c117b6c9b580ee3617e836e7ee926 | |
parent | 1cae003d3852773a1d76e2d5b755178886b68178 (diff) | |
download | FreeBSD-src-da5eae8899f5e2cb43ecccc320f644abeb47be00.zip FreeBSD-src-da5eae8899f5e2cb43ecccc320f644abeb47be00.tar.gz |
- When interrupt is not requested for VM86 call, make a fake exit point and
push the address onto stack as we do for INTn emulation. This avoids stack
underflow when we encounter RETF instruction in VM86 mode. Lack of this
exit point actually caused page fault in VM86 mode with VESA module when we
resume from suspend state[1].
- Remove unnecessary CLI and STI instructions from BIOS interrupt emulation.
INTn and IRET must be able to emulate the flag correctly.
Reported by: gavin [1]
Tested by: gavin (early revision)
MFC after: 3 days
-rw-r--r-- | sys/i386/i386/vm86.c | 23 |
1 files changed, 14 insertions, 9 deletions
diff --git a/sys/i386/i386/vm86.c b/sys/i386/i386/vm86.c index d415a07..62968c5 100644 --- a/sys/i386/i386/vm86.c +++ b/sys/i386/i386/vm86.c @@ -512,22 +512,27 @@ full: void vm86_prepcall(struct vm86frame *vmf) { - uintptr_t addr[] = { 0xA00, 0x1000 }; /* code, stack */ - u_char intcall[] = { - CLI, INTn, 0x00, STI, HLT - }; struct vm86_kernel *vm86; + uint32_t *stack; + uint8_t *code; + code = (void *)0xa00; + stack = (void *)(0x1000 - 2); /* keep aligned */ if ((vmf->vmf_trapno & PAGE_MASK) <= 0xff) { /* interrupt call requested */ - intcall[2] = (u_char)(vmf->vmf_trapno & 0xff); - memcpy((void *)addr[0], (void *)intcall, sizeof(intcall)); - vmf->vmf_ip = addr[0]; + code[0] = INTn; + code[1] = vmf->vmf_trapno & 0xff; + code[2] = HLT; + vmf->vmf_ip = (uintptr_t)code; vmf->vmf_cs = 0; + } else { + code[0] = HLT; + stack--; + stack[0] = MAKE_VEC(0, (uintptr_t)code); } - vmf->vmf_sp = addr[1] - 2; /* keep aligned */ - vmf->kernel_fs = vmf->kernel_es = vmf->kernel_ds = 0; + vmf->vmf_sp = (uintptr_t)stack; vmf->vmf_ss = 0; + vmf->kernel_fs = vmf->kernel_es = vmf->kernel_ds = 0; vmf->vmf_eflags = PSL_VIF | PSL_VM | PSL_USER; vm86 = &PCPU_GET(curpcb)->pcb_ext->ext_vm86; |