summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjkim <jkim@FreeBSD.org>2012-04-16 19:31:44 +0000
committerjkim <jkim@FreeBSD.org>2012-04-16 19:31:44 +0000
commitda5eae8899f5e2cb43ecccc320f644abeb47be00 (patch)
tree054d5675d80c117b6c9b580ee3617e836e7ee926
parent1cae003d3852773a1d76e2d5b755178886b68178 (diff)
downloadFreeBSD-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.c23
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;
OpenPOWER on IntegriCloud