diff options
author | Peter Wemm <peter@FreeBSD.org> | 2005-06-30 00:26:54 +0000 |
---|---|---|
committer | Peter Wemm <peter@FreeBSD.org> | 2005-06-30 00:26:54 +0000 |
commit | 2bdfd0d8144acf29c7e9a510998bfad22702aa76 (patch) | |
tree | c92b22e99b2fbf61481f551cb5680b0b0c1fc53e /sys/amd64 | |
parent | 2de92a386e6c6607bc212cdd576e03675d79000d (diff) | |
download | src-2bdfd0d8144acf29c7e9a510998bfad22702aa76.tar.gz src-2bdfd0d8144acf29c7e9a510998bfad22702aa76.zip |
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
Notes
Notes:
svn path=/head/; revision=147677
Diffstat (limited to 'sys/amd64')
-rw-r--r-- | sys/amd64/amd64/exception.S | 29 |
1 files changed, 26 insertions, 3 deletions
diff --git a/sys/amd64/amd64/exception.S b/sys/amd64/amd64/exception.S index bff29b5fd2d9..564955f588bc 100644 --- a/sys/amd64/amd64/exception.S +++ b/sys/amd64/amd64/exception.S @@ -126,8 +126,6 @@ IDTVEC(missing) TRAP_ERR(T_SEGNPFLT) IDTVEC(stk) TRAP_ERR(T_STKFLT) -IDTVEC(prot) - TRAP_ERR(T_PROTFLT) IDTVEC(align) TRAP_ERR(T_ALIGNFLT) @@ -203,7 +201,8 @@ IDTVEC(page) testb $SEL_RPL_MASK,TF_CS(%rsp) /* Did we come from kernel? */ jz 1f /* already running with kernel GS.base */ 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 %rdi,TF_ADDR(%rsp) /* enabling interrupts. */ testl $PSL_I,TF_RFLAGS(%rsp) @@ -211,6 +210,30 @@ IDTVEC(page) sti 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, * and the new privilige level. We are still running on the old user stack |