aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/amd64/amd64/cpu_switch.S20
-rw-r--r--sys/amd64/amd64/machdep.c1
-rw-r--r--sys/amd64/ia32/ia32_signal.c1
3 files changed, 20 insertions, 2 deletions
diff --git a/sys/amd64/amd64/cpu_switch.S b/sys/amd64/amd64/cpu_switch.S
index f34b0cccee31..a0b11f82500f 100644
--- a/sys/amd64/amd64/cpu_switch.S
+++ b/sys/amd64/amd64/cpu_switch.S
@@ -109,8 +109,24 @@ ENTRY(cpu_switch)
movq %rsp,PCB_RSP(%r8)
movq %rbx,PCB_RBX(%r8)
movq %rax,PCB_RIP(%r8)
- movq PCB_FSBASE(%r8),%r9
- movq PCB_GSBASE(%r8),%r10
+
+ /*
+ * Reread fs and gs bases. Explicit fs segment register load
+ * by the usermode code may change actual fs base without
+ * updating pcb_{fs,gs}base.
+ *
+ * %rdx still contains the mtx, save %rdx around rdmsr.
+ */
+ movq %rdx,%r11
+ movl $MSR_FSBASE,%ecx
+ rdmsr
+ shlq $32,%rdx
+ leaq (%rax,%rdx),%r9
+ movl $MSR_KGSBASE,%ecx
+ rdmsr
+ shlq $32,%rdx
+ leaq (%rax,%rdx),%r10
+ movq %r11,%rdx
testl $PCB_32BIT,PCB_FLAGS(%r8)
jnz store_seg
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index 06c0803b959e..f3c41f7b7d7d 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -734,6 +734,7 @@ exec_setregs(td, entry, stack, ps_strings)
pcb->pcb_fsbase = 0;
pcb->pcb_gsbase = 0;
critical_exit();
+ pcb->pcb_flags &= ~(PCB_32BIT | PCB_GS32BIT);
load_ds(_udatasel);
load_es(_udatasel);
load_fs(_udatasel);
diff --git a/sys/amd64/ia32/ia32_signal.c b/sys/amd64/ia32/ia32_signal.c
index 9e98656e18f5..162dcf99831b 100644
--- a/sys/amd64/ia32/ia32_signal.c
+++ b/sys/amd64/ia32/ia32_signal.c
@@ -742,5 +742,6 @@ ia32_setregs(td, entry, stack, ps_strings)
/* Return via doreti so that we can change to a different %cs */
pcb->pcb_flags |= PCB_FULLCTX | PCB_32BIT;
+ pcb->pcb_flags &= ~PCB_GS32BIT;
td->td_retval[1] = 0;
}