summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2008-07-30 11:30:55 +0000
committerkib <kib@FreeBSD.org>2008-07-30 11:30:55 +0000
commit19bf5e280722ebf99ad48917f4b8d0af5dbd14e1 (patch)
tree4dc6b207d6260804b2d05dffc793c7d0907eeccd
parent13b6ce6962eaf8de9b16589dde1fa06b5947d5f8 (diff)
downloadFreeBSD-src-19bf5e280722ebf99ad48917f4b8d0af5dbd14e1.zip
FreeBSD-src-19bf5e280722ebf99ad48917f4b8d0af5dbd14e1.tar.gz
Bring back the save/restore of the %ds, %es, %fs and %gs registers for
the 32bit images on amd64. Change the semantic of the PCB_32BIT pcb flag to request the context switch code to operate on the segment registers. Its previous meaning of saving or restoring the %gs base offset is assigned to the new PCB_GS32BIT flag. FreeBSD 32bit image activator sets the PCB_32BIT flag, while Linux 32bit emulation sets PCB_32BIT | PCB_GS32BIT. Reviewed by: peter MFC after: 2 weeks
-rw-r--r--sys/amd64/amd64/cpu_switch.S47
-rw-r--r--sys/amd64/amd64/genassym.c1
-rw-r--r--sys/amd64/ia32/ia32_signal.c2
-rw-r--r--sys/amd64/include/pcb.h1
-rw-r--r--sys/amd64/linux32/linux32_machdep.c2
5 files changed, 33 insertions, 20 deletions
diff --git a/sys/amd64/amd64/cpu_switch.S b/sys/amd64/amd64/cpu_switch.S
index 8abf262..f34b0cc 100644
--- a/sys/amd64/amd64/cpu_switch.S
+++ b/sys/amd64/amd64/cpu_switch.S
@@ -113,8 +113,8 @@ ENTRY(cpu_switch)
movq PCB_GSBASE(%r8),%r10
testl $PCB_32BIT,PCB_FLAGS(%r8)
- jnz store_gs /* static predict not taken */
-done_store_gs:
+ jnz store_seg
+done_store_seg:
testl $PCB_DBREGS,PCB_FLAGS(%r8)
jnz store_dr /* static predict not taken */
@@ -176,6 +176,10 @@ sw1:
testl $TDP_KTHREAD,TD_PFLAGS(%rsi)
jnz do_kthread
+ testl $PCB_32BIT,PCB_FLAGS(%r8)
+ jnz load_seg
+done_load_seg:
+
cmpq PCB_FSBASE(%r8),%r9
jz 1f
/* Restore userland %fs */
@@ -184,7 +188,6 @@ sw1:
movl PCB_FSBASE+4(%r8),%edx
wrmsr
1:
-
cmpq PCB_GSBASE(%r8),%r10
jz 2f
/* Restore userland %gs */
@@ -193,8 +196,8 @@ sw1:
movl PCB_GSBASE+4(%r8),%edx
wrmsr
2:
-do_tss:
+do_tss:
/* Update the TSS_RSP0 pointer for the next interrupt */
movq PCPU(TSSP), %rax
movq %r8, PCPU(RSP0)
@@ -208,10 +211,6 @@ do_tss:
jnz load_dr /* static predict not taken */
done_load_dr:
- testl $PCB_32BIT,PCB_FLAGS(%r8)
- jnz load_gs /* static predict not taken */
-done_load_gs:
-
/* Restore context. */
movq PCB_R15(%r8),%r15
movq PCB_R14(%r8),%r14
@@ -243,23 +242,35 @@ do_kthread:
movq %r10,PCB_GSBASE(%r8)
jmp do_tss
-store_gs:
+store_seg:
movl %gs,PCB_GS(%r8)
- movq PCB_GS32P(%r8),%rax
+ testl $PCB_GS32BIT,PCB_FLAGS(%r8)
+ jnz 2f
+1: movl %ds,PCB_DS(%r8)
+ movl %es,PCB_ES(%r8)
+ movl %fs,PCB_FS(%r8)
+ jmp done_store_seg
+2: movq PCB_GS32P(%r8),%rax
movq (%rax),%rax
movq %rax,PCB_GS32SD(%r8)
- jmp done_store_gs
+ jmp 1b
-load_gs:
- /* Restore userland %gs while preserving kernel gsbase */
- movq PCB_GS32P(%r8),%rax
- movq PCB_GS32SD(%r8),%rcx
- movq %rcx,(%rax)
- movl $MSR_GSBASE,%ecx
+load_seg:
+ testl $PCB_GS32BIT,PCB_FLAGS(%r8)
+ jnz 2f
+1: movl $MSR_GSBASE,%ecx
rdmsr
movl PCB_GS(%r8),%gs
wrmsr
- jmp done_load_gs
+ movl PCB_DS(%r8),%ds
+ movl PCB_ES(%r8),%es
+ movl PCB_FS(%r8),%fs
+ jmp done_load_seg
+ /* Restore userland %gs while preserving kernel gsbase */
+2: movq PCB_GS32P(%r8),%rax
+ movq PCB_GS32SD(%r8),%rcx
+ movq %rcx,(%rax)
+ jmp 1b
store_dr:
movq %dr7,%rax /* yes, do the save */
diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c
index baa1f15..fec0380 100644
--- a/sys/amd64/amd64/genassym.c
+++ b/sys/amd64/amd64/genassym.c
@@ -140,6 +140,7 @@ ASSYM(PCB_DR6, offsetof(struct pcb, pcb_dr6));
ASSYM(PCB_DR7, offsetof(struct pcb, pcb_dr7));
ASSYM(PCB_DBREGS, PCB_DBREGS);
ASSYM(PCB_32BIT, PCB_32BIT);
+ASSYM(PCB_GS32BIT, PCB_GS32BIT);
ASSYM(PCB_FULLCTX, PCB_FULLCTX);
ASSYM(PCB_FLAGS, offsetof(struct pcb, pcb_flags));
diff --git a/sys/amd64/ia32/ia32_signal.c b/sys/amd64/ia32/ia32_signal.c
index 5849d0d..9e98656 100644
--- a/sys/amd64/ia32/ia32_signal.c
+++ b/sys/amd64/ia32/ia32_signal.c
@@ -741,6 +741,6 @@ ia32_setregs(td, entry, stack, ps_strings)
fpstate_drop(td);
/* Return via doreti so that we can change to a different %cs */
- pcb->pcb_flags |= PCB_FULLCTX;
+ pcb->pcb_flags |= PCB_FULLCTX | PCB_32BIT;
td->td_retval[1] = 0;
}
diff --git a/sys/amd64/include/pcb.h b/sys/amd64/include/pcb.h
index 2a11598..647d5c9 100644
--- a/sys/amd64/include/pcb.h
+++ b/sys/amd64/include/pcb.h
@@ -70,6 +70,7 @@ struct pcb {
struct savefpu pcb_save;
#define PCB_DBREGS 0x02 /* process using debug registers */
#define PCB_FPUINITDONE 0x08 /* fpu state is initialized */
+#define PCB_GS32BIT 0x20 /* linux gs switch */
#define PCB_32BIT 0x40 /* process has 32 bit context (segs etc) */
#define PCB_FULLCTX 0x80 /* full context restore on sysret */
diff --git a/sys/amd64/linux32/linux32_machdep.c b/sys/amd64/linux32/linux32_machdep.c
index 565e6d2..6f1401c 100644
--- a/sys/amd64/linux32/linux32_machdep.c
+++ b/sys/amd64/linux32/linux32_machdep.c
@@ -696,7 +696,7 @@ linux_clone(struct thread *td, struct linux_clone_args *args)
td2->td_pcb->pcb_gs32sd = sd;
td2->td_pcb->pcb_gs32p = &gdt[GUGS32_SEL];
td2->td_pcb->pcb_gs = GSEL(GUGS32_SEL, SEL_UPL);
- td2->td_pcb->pcb_flags |= PCB_32BIT;
+ td2->td_pcb->pcb_flags |= PCB_GS32BIT | PCB_32BIT;
}
}
OpenPOWER on IntegriCloud