aboutsummaryrefslogtreecommitdiff
path: root/sys/amd64
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2014-05-29 16:18:31 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2014-05-29 16:18:31 +0000
commit64e9726555609bf0b30f00255677968a35debb46 (patch)
treec076035f7859446f220b3f15b8db8a0b27400a8e /sys/amd64
parent71e8891a3acf1d465b78a9f250577313a35d8175 (diff)
downloadsrc-64e9726555609bf0b30f00255677968a35debb46.tar.gz
src-64e9726555609bf0b30f00255677968a35debb46.zip
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
Notes
Notes: svn path=/head/; revision=266846
Diffstat (limited to 'sys/amd64')
-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 d4e58b1cecb9..d51078dd1808 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