1.Fix smp race between kernel vm86 BIOS calling and userland vm86 mode code,
remove global variable in_vm86call, set vm86 calling flag in PCB flags. 2.Fix vm86 BIOS calling preempted problem by changing vm86_lock mutex type from MTX_DEF to MTX_SPIN. vm86pcb is not remembered in thread struct, when the thread calling vm86 BIOS is preempted by interrupt thread, and later switching back to the thread would cause incorrect context be loaded into CPU registers, this leads to kernel crash.
This commit is contained in:
parent
ad9fbf676c
commit
b2a02ec1dc
@ -281,8 +281,9 @@ doreti_next:
|
||||
*/
|
||||
testl $PSL_VM,TF_EFLAGS(%esp) /* are we in vm86 mode? */
|
||||
jz doreti_notvm86
|
||||
cmpl $1,in_vm86call /* are we in a vm86 call? XXXSMP */
|
||||
jne doreti_ast /* can handle ASTs now if not */
|
||||
movl PCPU(CURPCB),%ecx
|
||||
testl $PCB_VM86CALL,PCB_FLAGS(%ecx) /* are we in a vm86 call? */
|
||||
jz doreti_ast /* can handle ASTS now if not */
|
||||
jmp doreti_exit
|
||||
|
||||
doreti_notvm86:
|
||||
|
@ -281,8 +281,9 @@ doreti_next:
|
||||
*/
|
||||
testl $PSL_VM,TF_EFLAGS(%esp) /* are we in vm86 mode? */
|
||||
jz doreti_notvm86
|
||||
cmpl $1,in_vm86call /* are we in a vm86 call? XXXSMP */
|
||||
jne doreti_ast /* can handle ASTs now if not */
|
||||
movl PCPU(CURPCB),%ecx
|
||||
testl $PCB_VM86CALL,PCB_FLAGS(%ecx) /* are we in a vm86 call? */
|
||||
jz doreti_ast /* can handle ASTS now if not */
|
||||
jmp doreti_exit
|
||||
|
||||
doreti_notvm86:
|
||||
|
@ -146,6 +146,7 @@ ASSYM(PCB_SAVEFPU_SIZE, sizeof(union savefpu));
|
||||
ASSYM(PCB_ONFAULT, offsetof(struct pcb, pcb_onfault));
|
||||
|
||||
ASSYM(PCB_SIZE, sizeof(struct pcb));
|
||||
ASSYM(PCB_VM86CALL, PCB_VM86CALL);
|
||||
|
||||
ASSYM(TF_TRAPNO, offsetof(struct trapframe, tf_trapno));
|
||||
ASSYM(TF_ERR, offsetof(struct trapframe, tf_err));
|
||||
|
@ -260,7 +260,8 @@ trap(frame)
|
||||
#endif /* DEVICE_POLLING */
|
||||
|
||||
if ((ISPL(frame.tf_cs) == SEL_UPL) ||
|
||||
((frame.tf_eflags & PSL_VM) && !in_vm86call)) {
|
||||
((frame.tf_eflags & PSL_VM) &&
|
||||
!(PCPU_GET(curpcb)->pcb_flags & PCB_VM86CALL))) {
|
||||
/* user trap */
|
||||
|
||||
sticks = td->td_kse->ke_sticks;
|
||||
@ -311,9 +312,7 @@ trap(frame)
|
||||
case T_PROTFLT: /* general protection fault */
|
||||
case T_STKFLT: /* stack fault */
|
||||
if (frame.tf_eflags & PSL_VM) {
|
||||
mtx_lock(&Giant);
|
||||
i = vm86_emulate((struct vm86frame *)&frame);
|
||||
mtx_unlock(&Giant);
|
||||
if (i == 0)
|
||||
goto user;
|
||||
break;
|
||||
@ -466,9 +465,7 @@ trap(frame)
|
||||
case T_PROTFLT: /* general protection fault */
|
||||
case T_STKFLT: /* stack fault */
|
||||
if (frame.tf_eflags & PSL_VM) {
|
||||
mtx_lock(&Giant);
|
||||
i = vm86_emulate((struct vm86frame *)&frame);
|
||||
mtx_unlock(&Giant);
|
||||
if (i != 0)
|
||||
/*
|
||||
* returns to original process
|
||||
@ -482,7 +479,7 @@ trap(frame)
|
||||
/* FALL THROUGH */
|
||||
|
||||
case T_SEGNPFLT: /* segment not present fault */
|
||||
if (in_vm86call)
|
||||
if (PCPU_GET(curpcb)->pcb_flags & PCB_VM86CALL)
|
||||
break;
|
||||
|
||||
if (td->td_intr_nesting_level != 0)
|
||||
@ -584,7 +581,8 @@ trap(frame)
|
||||
* debugging the kernel.
|
||||
*/
|
||||
/* XXX Giant */
|
||||
if (user_dbreg_trap() && !in_vm86call) {
|
||||
if (user_dbreg_trap() &&
|
||||
!(PCPU_GET(curpcb)->pcb_flags & PCB_VM86CALL)) {
|
||||
/*
|
||||
* Reset breakpoint bits because the
|
||||
* processor doesn't
|
||||
|
@ -67,6 +67,8 @@ struct pcb {
|
||||
#define PCB_DBREGS 0x02 /* process using debug registers */
|
||||
#define PCB_NPXTRAP 0x04 /* npx trap pending */
|
||||
#define PCB_NPXINITDONE 0x08 /* fpu state is initialized */
|
||||
#define PCB_VM86CALL 0x10 /* in vm86 call */
|
||||
|
||||
caddr_t pcb_onfault; /* copyin/out fault recovery */
|
||||
int pcb_gs;
|
||||
struct pcb_ext *pcb_ext; /* optional pcb extension */
|
||||
|
@ -281,8 +281,9 @@ doreti_next:
|
||||
*/
|
||||
testl $PSL_VM,TF_EFLAGS(%esp) /* are we in vm86 mode? */
|
||||
jz doreti_notvm86
|
||||
cmpl $1,in_vm86call /* are we in a vm86 call? XXXSMP */
|
||||
jne doreti_ast /* can handle ASTs now if not */
|
||||
movl PCPU(CURPCB),%ecx
|
||||
testl $PCB_VM86CALL,PCB_FLAGS(%ecx) /* are we in a vm86 call? */
|
||||
jz doreti_ast /* can handle ASTS now if not */
|
||||
jmp doreti_exit
|
||||
|
||||
doreti_notvm86:
|
||||
|
@ -146,6 +146,7 @@ ASSYM(PCB_SAVEFPU_SIZE, sizeof(union savefpu));
|
||||
ASSYM(PCB_ONFAULT, offsetof(struct pcb, pcb_onfault));
|
||||
|
||||
ASSYM(PCB_SIZE, sizeof(struct pcb));
|
||||
ASSYM(PCB_VM86CALL, PCB_VM86CALL);
|
||||
|
||||
ASSYM(TF_TRAPNO, offsetof(struct trapframe, tf_trapno));
|
||||
ASSYM(TF_ERR, offsetof(struct trapframe, tf_err));
|
||||
|
@ -260,7 +260,8 @@ trap(frame)
|
||||
#endif /* DEVICE_POLLING */
|
||||
|
||||
if ((ISPL(frame.tf_cs) == SEL_UPL) ||
|
||||
((frame.tf_eflags & PSL_VM) && !in_vm86call)) {
|
||||
((frame.tf_eflags & PSL_VM) &&
|
||||
!(PCPU_GET(curpcb)->pcb_flags & PCB_VM86CALL))) {
|
||||
/* user trap */
|
||||
|
||||
sticks = td->td_kse->ke_sticks;
|
||||
@ -311,9 +312,7 @@ trap(frame)
|
||||
case T_PROTFLT: /* general protection fault */
|
||||
case T_STKFLT: /* stack fault */
|
||||
if (frame.tf_eflags & PSL_VM) {
|
||||
mtx_lock(&Giant);
|
||||
i = vm86_emulate((struct vm86frame *)&frame);
|
||||
mtx_unlock(&Giant);
|
||||
if (i == 0)
|
||||
goto user;
|
||||
break;
|
||||
@ -466,9 +465,7 @@ trap(frame)
|
||||
case T_PROTFLT: /* general protection fault */
|
||||
case T_STKFLT: /* stack fault */
|
||||
if (frame.tf_eflags & PSL_VM) {
|
||||
mtx_lock(&Giant);
|
||||
i = vm86_emulate((struct vm86frame *)&frame);
|
||||
mtx_unlock(&Giant);
|
||||
if (i != 0)
|
||||
/*
|
||||
* returns to original process
|
||||
@ -482,7 +479,7 @@ trap(frame)
|
||||
/* FALL THROUGH */
|
||||
|
||||
case T_SEGNPFLT: /* segment not present fault */
|
||||
if (in_vm86call)
|
||||
if (PCPU_GET(curpcb)->pcb_flags & PCB_VM86CALL)
|
||||
break;
|
||||
|
||||
if (td->td_intr_nesting_level != 0)
|
||||
@ -584,7 +581,8 @@ trap(frame)
|
||||
* debugging the kernel.
|
||||
*/
|
||||
/* XXX Giant */
|
||||
if (user_dbreg_trap() && !in_vm86call) {
|
||||
if (user_dbreg_trap() &&
|
||||
!(PCPU_GET(curpcb)->pcb_flags & PCB_VM86CALL)) {
|
||||
/*
|
||||
* Reset breakpoint bits because the
|
||||
* processor doesn't
|
||||
|
@ -425,12 +425,13 @@ vm86_initialize(void)
|
||||
pcb = &vml->vml_pcb;
|
||||
ext = &vml->vml_ext;
|
||||
|
||||
mtx_init(&vm86_lock, "vm86 lock", NULL, MTX_DEF);
|
||||
mtx_init(&vm86_lock, "vm86 lock", NULL, MTX_SPIN);
|
||||
|
||||
bzero(pcb, sizeof(struct pcb));
|
||||
pcb->new_ptd = vm86pa | PG_V | PG_RW | PG_U;
|
||||
pcb->vm86_frame = vm86paddr - sizeof(struct vm86frame);
|
||||
pcb->pgtable_va = vm86paddr;
|
||||
pcb->pcb_flags = PCB_VM86CALL;
|
||||
pcb->pcb_ext = ext;
|
||||
|
||||
bzero(ext, sizeof(struct pcb_ext));
|
||||
@ -577,9 +578,9 @@ vm86_intcall(int intnum, struct vm86frame *vmf)
|
||||
return (EINVAL);
|
||||
|
||||
vmf->vmf_trapno = intnum;
|
||||
mtx_lock(&vm86_lock);
|
||||
mtx_lock_spin(&vm86_lock);
|
||||
retval = vm86_bioscall(vmf);
|
||||
mtx_unlock(&vm86_lock);
|
||||
mtx_unlock_spin(&vm86_lock);
|
||||
return (retval);
|
||||
}
|
||||
|
||||
@ -599,7 +600,7 @@ vm86_datacall(intnum, vmf, vmc)
|
||||
u_int page;
|
||||
int i, entry, retval;
|
||||
|
||||
mtx_lock(&vm86_lock);
|
||||
mtx_lock_spin(&vm86_lock);
|
||||
for (i = 0; i < vmc->npages; i++) {
|
||||
page = vtophys(vmc->pmap[i].kva & PG_FRAME);
|
||||
entry = vmc->pmap[i].pte_num;
|
||||
@ -616,7 +617,7 @@ vm86_datacall(intnum, vmf, vmc)
|
||||
pte[entry] = vmc->pmap[i].old_pte;
|
||||
pmap_invalidate_page(kernel_pmap, vmc->pmap[i].kva);
|
||||
}
|
||||
mtx_unlock(&vm86_lock);
|
||||
mtx_unlock_spin(&vm86_lock);
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
@ -44,9 +44,8 @@
|
||||
.data
|
||||
ALIGN_DATA
|
||||
|
||||
.globl in_vm86call, vm86pcb
|
||||
.globl vm86pcb
|
||||
|
||||
in_vm86call: .long 0
|
||||
vm86pcb: .long 0
|
||||
|
||||
.text
|
||||
@ -129,8 +128,6 @@ ENTRY(vm86_bioscall)
|
||||
|
||||
call vm86_prepcall /* finish setup */
|
||||
|
||||
movl $1,in_vm86call /* set flag for trap() */
|
||||
|
||||
/*
|
||||
* Return via doreti
|
||||
*/
|
||||
@ -158,8 +155,6 @@ ENTRY(vm86_biosret)
|
||||
popl %eax
|
||||
movl %eax,%cr3 /* install old page table */
|
||||
|
||||
movl $0,in_vm86call /* reset trapflag */
|
||||
|
||||
movl PCPU(TSS_GDT),%ebx /* entry in GDT */
|
||||
movl SCR_TSS0(%edx),%eax
|
||||
movl %eax,0(%ebx) /* restore first word */
|
||||
|
@ -67,6 +67,8 @@ struct pcb {
|
||||
#define PCB_DBREGS 0x02 /* process using debug registers */
|
||||
#define PCB_NPXTRAP 0x04 /* npx trap pending */
|
||||
#define PCB_NPXINITDONE 0x08 /* fpu state is initialized */
|
||||
#define PCB_VM86CALL 0x10 /* in vm86 call */
|
||||
|
||||
caddr_t pcb_onfault; /* copyin/out fault recovery */
|
||||
int pcb_gs;
|
||||
struct pcb_ext *pcb_ext; /* optional pcb extension */
|
||||
|
@ -145,7 +145,6 @@ struct vm86_intcall_args {
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
extern int in_vm86call;
|
||||
extern int vm86paddr;
|
||||
|
||||
struct thread;
|
||||
|
Loading…
Reference in New Issue
Block a user