summaryrefslogtreecommitdiffstats
path: root/sys/amd64/amd64/exception.S
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2014-05-29 16:18:31 +0000
committerkib <kib@FreeBSD.org>2014-05-29 16:18:31 +0000
commit7c98ae33769f0413abfb4dbb09d1b281f0b98b8f (patch)
treec076035f7859446f220b3f15b8db8a0b27400a8e /sys/amd64/amd64/exception.S
parent2bf4c9cd3e8c4b12dd4d3bd4e0927cf8351326f2 (diff)
downloadFreeBSD-src-7c98ae33769f0413abfb4dbb09d1b281f0b98b8f.zip
FreeBSD-src-7c98ae33769f0413abfb4dbb09d1b281f0b98b8f.tar.gz
When usermode loaded non-default segment selector into the %gs,
correctly prepare KGSBASE msr to restore the user descriptor base on the last swapgs during return to usermode. Reported and tested by: peterj Sponsored by: The FreeBSD Foundation MFC after: 1 week
Diffstat (limited to 'sys/amd64/amd64/exception.S')
-rw-r--r--sys/amd64/amd64/exception.S23
1 files changed, 20 insertions, 3 deletions
diff --git a/sys/amd64/amd64/exception.S b/sys/amd64/amd64/exception.S
index d4e58b1..d51078d 100644
--- a/sys/amd64/amd64/exception.S
+++ b/sys/amd64/amd64/exception.S
@@ -721,21 +721,38 @@ ld_fsbase:
pushfq
cli
movl $MSR_GSBASE,%ecx
+ /* Save current kernel %gs base into %r12d:%r13d */
rdmsr
+ movl %eax,%r12d
+ movl %edx,%r13d
.globl ld_gs
ld_gs:
movw %si,%gs
+ /* Save user %gs base into %r14d:%r15d */
+ rdmsr
+ movl %eax,%r14d
+ movl %edx,%r15d
+ /* Restore kernel %gs base */
+ movl %r12d,%eax
+ movl %r13d,%edx
wrmsr
popfq
+ /*
+ * Restore user %gs base, either from PCB if used for TLS, or
+ * from the previously saved msr read.
+ */
+ movl $MSR_KGSBASE,%ecx
cmpw $KUG32SEL,%si
jne 1f
- movl $MSR_KGSBASE,%ecx
movl PCB_GSBASE(%r8),%eax
movl PCB_GSBASE+4(%r8),%edx
+ jmp ld_gsbase
+1:
+ movl %r14d,%eax
+ movl %r15d,%edx
.globl ld_gsbase
ld_gsbase:
- wrmsr
-1:
+ wrmsr /* May trap if non-canonical, but only for TLS. */
.globl ld_es
ld_es:
movw TF_ES(%rsp),%es
OpenPOWER on IntegriCloud