Add a special-case handler for general protection faults. It appears to

be possible to get the swapgs state reversed if doreti traps during
the iretq.  Attempt to handle this.  load_gs() might need special
handling too.  Running the kernel with the user's TLS and the
kernel's PCPU space interchanged would be bad(TM).

Discovered as a result of a conversation with:  bde
Approved by:  re
This commit is contained in:
Peter Wemm 2005-06-30 00:26:54 +00:00
parent 2de92a386e
commit 2bdfd0d814

View File

@ -126,8 +126,6 @@ IDTVEC(missing)
TRAP_ERR(T_SEGNPFLT) TRAP_ERR(T_SEGNPFLT)
IDTVEC(stk) IDTVEC(stk)
TRAP_ERR(T_STKFLT) TRAP_ERR(T_STKFLT)
IDTVEC(prot)
TRAP_ERR(T_PROTFLT)
IDTVEC(align) IDTVEC(align)
TRAP_ERR(T_ALIGNFLT) TRAP_ERR(T_ALIGNFLT)
@ -203,7 +201,8 @@ IDTVEC(page)
testb $SEL_RPL_MASK,TF_CS(%rsp) /* Did we come from kernel? */ testb $SEL_RPL_MASK,TF_CS(%rsp) /* Did we come from kernel? */
jz 1f /* already running with kernel GS.base */ jz 1f /* already running with kernel GS.base */
swapgs swapgs
1: movq %rdi,TF_RDI(%rsp) /* free up a GP register */ 1:
movq %rdi,TF_RDI(%rsp) /* free up a GP register */
movq %cr2,%rdi /* preserve %cr2 before .. */ movq %cr2,%rdi /* preserve %cr2 before .. */
movq %rdi,TF_ADDR(%rsp) /* enabling interrupts. */ movq %rdi,TF_ADDR(%rsp) /* enabling interrupts. */
testl $PSL_I,TF_RFLAGS(%rsp) testl $PSL_I,TF_RFLAGS(%rsp)
@ -211,6 +210,30 @@ IDTVEC(page)
sti sti
jmp alltraps_pushregs_no_rdi jmp alltraps_pushregs_no_rdi
/*
* We have to special-case this one. If we get a trap in doreti() at
* the iretq stage, we'll reenter with the wrong gs state. We'll have
* to do a special the swapgs in this case even coming from the kernel.
* XXX linux has a trap handler for their equivalent of load_gs().
*/
IDTVEC(prot)
subq $TF_ERR,%rsp
movq $T_PROTFLT,TF_TRAPNO(%rsp)
movq $0,TF_ADDR(%rsp)
movq %rdi,TF_RDI(%rsp) /* free up a GP register */
leaq doreti_iret(%rip),%rdi
cmpq %rdi,TF_RIP(%rsp)
je 2f /* kernel but with user gsbase!! */
testb $SEL_RPL_MASK,TF_CS(%rsp) /* Did we come from kernel? */
jz 1f /* already running with kernel GS.base */
2:
swapgs
1:
testl $PSL_I,TF_RFLAGS(%rsp)
jz alltraps_pushregs_no_rdi
sti
jmp alltraps_pushregs_no_rdi
/* /*
* Fast syscall entry point. We enter here with just our new %cs/%ss set, * Fast syscall entry point. We enter here with just our new %cs/%ss set,
* and the new privilige level. We are still running on the old user stack * and the new privilige level. We are still running on the old user stack