summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>2003-05-15 00:23:40 +0000
committerpeter <peter@FreeBSD.org>2003-05-15 00:23:40 +0000
commit12d7e4bee670b00c658676727ee630be6fbb7af1 (patch)
tree1cae0c59e2d1157890a9bc0eb09af3e021373ef6 /sys
parent7208ad8cbbe97024b739c1267077266cf9792ad3 (diff)
downloadFreeBSD-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.S13
-rw-r--r--sys/amd64/amd64/genassym.c1
-rw-r--r--sys/amd64/amd64/machdep.c9
-rw-r--r--sys/amd64/ia32/ia32_sysvec.c9
-rw-r--r--sys/amd64/include/cpufunc.h36
-rw-r--r--sys/amd64/include/pcb.h1
-rw-r--r--sys/compat/ia32/ia32_sysvec.c9
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;
OpenPOWER on IntegriCloud