diff options
author | kib <kib@FreeBSD.org> | 2008-07-30 11:30:55 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2008-07-30 11:30:55 +0000 |
commit | 19bf5e280722ebf99ad48917f4b8d0af5dbd14e1 (patch) | |
tree | 4dc6b207d6260804b2d05dffc793c7d0907eeccd /sys/amd64 | |
parent | 13b6ce6962eaf8de9b16589dde1fa06b5947d5f8 (diff) | |
download | FreeBSD-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
Diffstat (limited to 'sys/amd64')
-rw-r--r-- | sys/amd64/amd64/cpu_switch.S | 47 | ||||
-rw-r--r-- | sys/amd64/amd64/genassym.c | 1 | ||||
-rw-r--r-- | sys/amd64/ia32/ia32_signal.c | 2 | ||||
-rw-r--r-- | sys/amd64/include/pcb.h | 1 | ||||
-rw-r--r-- | sys/amd64/linux32/linux32_machdep.c | 2 |
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; } } |