diff options
author | peter <peter@FreeBSD.org> | 2003-05-15 00:23:40 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 2003-05-15 00:23:40 +0000 |
commit | 12d7e4bee670b00c658676727ee630be6fbb7af1 (patch) | |
tree | 1cae0c59e2d1157890a9bc0eb09af3e021373ef6 /sys | |
parent | 7208ad8cbbe97024b739c1267077266cf9792ad3 (diff) | |
download | FreeBSD-src-12d7e4bee670b00c658676727ee630be6fbb7af1.zip FreeBSD-src-12d7e4bee670b00c658676727ee630be6fbb7af1.tar.gz |
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)
Diffstat (limited to 'sys')
-rw-r--r-- | sys/amd64/amd64/cpu_switch.S | 13 | ||||
-rw-r--r-- | sys/amd64/amd64/genassym.c | 1 | ||||
-rw-r--r-- | sys/amd64/amd64/machdep.c | 9 | ||||
-rw-r--r-- | sys/amd64/ia32/ia32_sysvec.c | 9 | ||||
-rw-r--r-- | sys/amd64/include/cpufunc.h | 36 | ||||
-rw-r--r-- | sys/amd64/include/pcb.h | 1 | ||||
-rw-r--r-- | sys/compat/ia32/ia32_sysvec.c | 9 |
7 files changed, 42 insertions, 36 deletions
diff --git a/sys/amd64/amd64/cpu_switch.S b/sys/amd64/amd64/cpu_switch.S index 3ca4ecd..9465396 100644 --- a/sys/amd64/amd64/cpu_switch.S +++ b/sys/amd64/amd64/cpu_switch.S @@ -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 */ diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c index b55ef08..3ccad23 100644 --- a/sys/amd64/amd64/genassym.c +++ b/sys/amd64/amd64/genassym.c @@ -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)); diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index b0b6ce2..a5d85f1 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -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; } diff --git a/sys/amd64/ia32/ia32_sysvec.c b/sys/amd64/ia32/ia32_sysvec.c index 684677a..5ced18c 100644 --- a/sys/amd64/ia32/ia32_sysvec.c +++ b/sys/amd64/ia32/ia32_sysvec.c @@ -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; diff --git a/sys/amd64/include/cpufunc.h b/sys/amd64/include/cpufunc.h index 21257dd..5d4c0dc 100644 --- a/sys/amd64/include/cpufunc.h +++ b/sys/amd64/include/cpufunc.h @@ -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 diff --git a/sys/amd64/include/pcb.h b/sys/amd64/include/pcb.h index 5bfb41f..83d308f 100644 --- a/sys/amd64/include/pcb.h +++ b/sys/amd64/include/pcb.h @@ -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; diff --git a/sys/compat/ia32/ia32_sysvec.c b/sys/compat/ia32/ia32_sysvec.c index 684677a..5ced18c 100644 --- a/sys/compat/ia32/ia32_sysvec.c +++ b/sys/compat/ia32/ia32_sysvec.c @@ -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; |