1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-16 10:20:30 +00:00

Collect the nastiness for preserving the kernel MSR_GSBASE around the

load_gs() calls into a single place that is less likely to go wrong.

Eliminate the per-process context switching of MSR_GSBASE, because it
should be constant for a single cpu.  Instead, save/restore it during
the loading of the new %gs selector for the new process.

Approved by:	re (amd64/* blanket)
This commit is contained in:
Peter Wemm 2003-05-15 00:23:40 +00:00
parent be52ef1399
commit c0a54ff621
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=115006
7 changed files with 42 additions and 36 deletions

View File

@ -106,12 +106,6 @@ ENTRY(cpu_switch)
pushfq /* PSL */
popq PCB_RFLAGS(%r8)
/* Save kernel %gs.base */
movl $MSR_GSBASE,%ecx
rdmsr
movl %eax,PCB_KGSBASE(%r8)
movl %edx,PCB_KGSBASE+4(%r8)
/* Save userland %fs */
movl $MSR_FSBASE,%ecx
rdmsr
@ -176,12 +170,11 @@ sw1:
movl PCB_DS(%r8),%ds
movl PCB_ES(%r8),%es
movl PCB_FS(%r8),%fs
movl PCB_GS(%r8),%gs
/* Restore kernel %gs.base */
/* Restore userland %gs while preserving kernel gsbase */
movl $MSR_GSBASE,%ecx
movl PCB_KGSBASE(%r8),%eax
movl PCB_KGSBASE+4(%r8),%edx
rdmsr
movl PCB_GS(%r8),%gs
wrmsr
/* Restore userland %fs */

View File

@ -125,7 +125,6 @@ ASSYM(PCB_RIP, offsetof(struct pcb, pcb_rip));
ASSYM(PCB_RFLAGS, offsetof(struct pcb, pcb_rflags));
ASSYM(PCB_FSBASE, offsetof(struct pcb, pcb_fsbase));
ASSYM(PCB_GSBASE, offsetof(struct pcb, pcb_gsbase));
ASSYM(PCB_KGSBASE, offsetof(struct pcb, pcb_kgsbase));
ASSYM(PCB_DS, offsetof(struct pcb, pcb_ds));
ASSYM(PCB_ES, offsetof(struct pcb, pcb_es));
ASSYM(PCB_FS, offsetof(struct pcb, pcb_fs));

View File

@ -476,21 +476,15 @@ exec_setregs(td, entry, stack, ps_strings)
{
struct trapframe *regs = td->td_frame;
struct pcb *pcb = td->td_pcb;
u_int64_t pc;
wrmsr(MSR_FSBASE, 0);
wrmsr(MSR_KGSBASE, 0); /* User value while we're in the kernel */
pcb->pcb_fsbase = 0;
pcb->pcb_gsbase = 0;
pcb->pcb_kgsbase = rdmsr(MSR_GSBASE);
load_ds(_udatasel);
load_es(_udatasel);
load_fs(_udatasel);
critical_enter();
pc = rdmsr(MSR_GSBASE);
load_gs(_udatasel); /* Clobbers kernel %GS.base */
wrmsr(MSR_GSBASE, pc);
critical_exit();
load_gs(_udatasel);
pcb->pcb_ds = _udatasel;
pcb->pcb_es = _udatasel;
pcb->pcb_fs = _udatasel;
@ -1317,7 +1311,6 @@ hammer_time(void)
/* setup proc 0's pcb */
thread0.td_pcb->pcb_flags = 0; /* XXXKSE */
thread0.td_pcb->pcb_cr3 = IdlePML4;
thread0.td_pcb->pcb_kgsbase = (u_int64_t)pc;
thread0.td_frame = &proc0_tf;
}

View File

@ -241,22 +241,15 @@ ia32_setregs(td, entry, stack, ps_strings)
{
struct trapframe *regs = td->td_frame;
struct pcb *pcb = td->td_pcb;
u_int64_t pc;
register_t s;
wrmsr(MSR_FSBASE, 0);
wrmsr(MSR_KGSBASE, 0); /* User value while we're in the kernel */
pcb->pcb_fsbase = 0;
pcb->pcb_gsbase = 0;
pcb->pcb_kgsbase = rdmsr(MSR_GSBASE);
load_ds(_udatasel);
load_es(_udatasel);
load_fs(_udatasel);
s = intr_disable();
pc = rdmsr(MSR_GSBASE);
load_gs(_udatasel); /* Clobbers kernel %GS.base */
wrmsr(MSR_GSBASE, pc);
intr_restore(s);
load_gs(_udatasel);
pcb->pcb_ds = _udatasel;
pcb->pcb_es = _udatasel;
pcb->pcb_fs = _udatasel;

View File

@ -475,6 +475,41 @@ load_es(u_int sel)
__asm __volatile("movl %0,%%es" : : "rm" (sel));
}
#ifdef _KERNEL
/* This is defined in <machine/specialreg.h> but is too painful to get to */
#ifndef MSR_FSBASE
#define MSR_FSBASE 0xc0000100
#endif
static __inline void
load_fs(u_int sel)
{
register u_int32_t fsbase __asm("ecx");
/* Preserve the fsbase value across the selector load */
fsbase = MSR_FSBASE;
__asm __volatile("rdmsr; movl %0,%%fs; wrmsr"
: : "rm" (sel), "c" (fsbase) : "eax", "edx");
}
#ifndef MSR_GSBASE
#define MSR_GSBASE 0xc0000101
#endif
static __inline void
load_gs(u_int sel)
{
register u_int32_t gsbase __asm("ecx");
/*
* Preserve the gsbase value across the selector load.
* Note that we have to disable interrupts because the gsbase
* being trashed happens to be the kernel gsbase at the time.
*/
gsbase = MSR_GSBASE;
__asm __volatile("pushfq; cli; rdmsr; movl %0,%%gs; wrmsr; popfq"
: : "rm" (sel), "c" (gsbase) : "eax", "edx");
}
#else
/* Usable by userland */
static __inline void
load_fs(u_int sel)
{
@ -486,6 +521,7 @@ load_gs(u_int sel)
{
__asm __volatile("movl %0,%%gs" : : "rm" (sel));
}
#endif
/* void lidt(struct region_descriptor *addr); */
static __inline void

View File

@ -59,7 +59,6 @@ struct pcb {
register_t pcb_rflags;
register_t pcb_fsbase;
register_t pcb_gsbase;
register_t pcb_kgsbase;
u_int32_t pcb_ds;
u_int32_t pcb_es;
u_int32_t pcb_fs;

View File

@ -241,22 +241,15 @@ ia32_setregs(td, entry, stack, ps_strings)
{
struct trapframe *regs = td->td_frame;
struct pcb *pcb = td->td_pcb;
u_int64_t pc;
register_t s;
wrmsr(MSR_FSBASE, 0);
wrmsr(MSR_KGSBASE, 0); /* User value while we're in the kernel */
pcb->pcb_fsbase = 0;
pcb->pcb_gsbase = 0;
pcb->pcb_kgsbase = rdmsr(MSR_GSBASE);
load_ds(_udatasel);
load_es(_udatasel);
load_fs(_udatasel);
s = intr_disable();
pc = rdmsr(MSR_GSBASE);
load_gs(_udatasel); /* Clobbers kernel %GS.base */
wrmsr(MSR_GSBASE, pc);
intr_restore(s);
load_gs(_udatasel);
pcb->pcb_ds = _udatasel;
pcb->pcb_es = _udatasel;
pcb->pcb_fs = _udatasel;