diff --git a/sys/amd64/amd64/cpu_switch.S b/sys/amd64/amd64/cpu_switch.S index f34b0cc..a0b11f8 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 06c0803..f3c41f7 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 9e98656..162dcf9 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; }