aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorPeter Wemm <peter@FreeBSD.org>2005-06-30 00:26:54 +0000
committerPeter Wemm <peter@FreeBSD.org>2005-06-30 00:26:54 +0000
commit2bdfd0d8144acf29c7e9a510998bfad22702aa76 (patch)
treec92b22e99b2fbf61481f551cb5680b0b0c1fc53e /sys
parent2de92a386e6c6607bc212cdd576e03675d79000d (diff)
downloadsrc-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')
-rw-r--r--sys/amd64/amd64/exception.S29
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