summaryrefslogtreecommitdiffstats
path: root/sys/amd64
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>2005-06-30 00:26:54 +0000
committerpeter <peter@FreeBSD.org>2005-06-30 00:26:54 +0000
commit24cb92a9d6ad45321e4076e9abf27de9d94be843 (patch)
treec92b22e99b2fbf61481f551cb5680b0b0c1fc53e /sys/amd64
parent2778435f72bb00f7b707c07e040cc72c341fe5c6 (diff)
downloadFreeBSD-src-24cb92a9d6ad45321e4076e9abf27de9d94be843.zip
FreeBSD-src-24cb92a9d6ad45321e4076e9abf27de9d94be843.tar.gz
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
Diffstat (limited to 'sys/amd64')
-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 bff29b5..564955f 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
OpenPOWER on IntegriCloud