Skip to content

Commit

Permalink
[PATCH] i386: Convert i386 PDA code to use %fs
Browse files Browse the repository at this point in the history
Convert the PDA code to use %fs rather than %gs as the segment for
per-processor data.  This is because some processors show a small but
measurable performance gain for reloading a NULL segment selector (as %fs
generally is in user-space) versus a non-NULL one (as %gs generally is).

On modern processors the difference is very small, perhaps undetectable.
Some old AMD "K6 3D+" processors are noticably slower when %fs is used
rather than %gs; I have no idea why this might be, but I think they're
sufficiently rare that it doesn't matter much.

This patch also fixes the math emulator, which had not been adjusted to
match the changed struct pt_regs.

[frederik.deweerdt@gmail.com: fixit with gdb]
[mingo@elte.hu: Fix KVM too]

Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
Signed-off-by: Andi Kleen <ak@suse.de>
Cc: Ian Campbell <Ian.Campbell@XenSource.com>
Acked-by: Ingo Molnar <mingo@elte.hu>
Acked-by: Zachary Amsden <zach@vmware.com>
Cc: Eric Dumazet <dada1@cosmosbay.com>
Signed-off-by: Frederik Deweerdt <frederik.deweerdt@gmail.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
  • Loading branch information
Jeremy Fitzhardinge authored and Andi Kleen committed Feb 13, 2007
1 parent 5441392 commit 464d1a7
Show file tree
Hide file tree
Showing 17 changed files with 99 additions and 103 deletions.
2 changes: 1 addition & 1 deletion arch/i386/kernel/asm-offsets.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ void foo(void)
OFFSET(PT_EAX, pt_regs, eax);
OFFSET(PT_DS, pt_regs, xds);
OFFSET(PT_ES, pt_regs, xes);
OFFSET(PT_GS, pt_regs, xgs);
OFFSET(PT_FS, pt_regs, xfs);
OFFSET(PT_ORIG_EAX, pt_regs, orig_eax);
OFFSET(PT_EIP, pt_regs, eip);
OFFSET(PT_CS, pt_regs, xcs);
Expand Down
14 changes: 7 additions & 7 deletions arch/i386/kernel/cpu/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ void __init early_cpu_init(void)
struct pt_regs * __devinit idle_regs(struct pt_regs *regs)
{
memset(regs, 0, sizeof(struct pt_regs));
regs->xgs = __KERNEL_PDA;
regs->xfs = __KERNEL_PDA;
return regs;
}

Expand Down Expand Up @@ -662,12 +662,12 @@ struct i386_pda boot_pda = {
.pcurrent = &init_task,
};

static inline void set_kernel_gs(void)
static inline void set_kernel_fs(void)
{
/* Set %gs for this CPU's PDA. Memory clobber is to create a
/* Set %fs for this CPU's PDA. Memory clobber is to create a
barrier with respect to any PDA operations, so the compiler
doesn't move any before here. */
asm volatile ("mov %0, %%gs" : : "r" (__KERNEL_PDA) : "memory");
asm volatile ("mov %0, %%fs" : : "r" (__KERNEL_PDA) : "memory");
}

/* Initialize the CPU's GDT and PDA. The boot CPU does this for
Expand Down Expand Up @@ -718,7 +718,7 @@ void __cpuinit cpu_set_gdt(int cpu)
the boot CPU, this will transition from the boot gdt+pda to
the real ones). */
load_gdt(cpu_gdt_descr);
set_kernel_gs();
set_kernel_fs();
}

/* Common CPU init for both boot and secondary CPUs */
Expand Down Expand Up @@ -764,8 +764,8 @@ static void __cpuinit _cpu_init(int cpu, struct task_struct *curr)
__set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss);
#endif

/* Clear %fs. */
asm volatile ("mov %0, %%fs" : : "r" (0));
/* Clear %gs. */
asm volatile ("mov %0, %%gs" : : "r" (0));

/* Clear all 6 debug registers: */
set_debugreg(0, 0);
Expand Down
32 changes: 16 additions & 16 deletions arch/i386/kernel/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
* 18(%esp) - %eax
* 1C(%esp) - %ds
* 20(%esp) - %es
* 24(%esp) - %gs
* 24(%esp) - %fs
* 28(%esp) - orig_eax
* 2C(%esp) - %eip
* 30(%esp) - %cs
Expand Down Expand Up @@ -99,9 +99,9 @@ VM_MASK = 0x00020000

#define SAVE_ALL \
cld; \
pushl %gs; \
pushl %fs; \
CFI_ADJUST_CFA_OFFSET 4;\
/*CFI_REL_OFFSET gs, 0;*/\
/*CFI_REL_OFFSET fs, 0;*/\
pushl %es; \
CFI_ADJUST_CFA_OFFSET 4;\
/*CFI_REL_OFFSET es, 0;*/\
Expand Down Expand Up @@ -133,7 +133,7 @@ VM_MASK = 0x00020000
movl %edx, %ds; \
movl %edx, %es; \
movl $(__KERNEL_PDA), %edx; \
movl %edx, %gs
movl %edx, %fs

#define RESTORE_INT_REGS \
popl %ebx; \
Expand Down Expand Up @@ -166,9 +166,9 @@ VM_MASK = 0x00020000
2: popl %es; \
CFI_ADJUST_CFA_OFFSET -4;\
/*CFI_RESTORE es;*/\
3: popl %gs; \
3: popl %fs; \
CFI_ADJUST_CFA_OFFSET -4;\
/*CFI_RESTORE gs;*/\
/*CFI_RESTORE fs;*/\
.pushsection .fixup,"ax"; \
4: movl $0,(%esp); \
jmp 1b; \
Expand Down Expand Up @@ -349,11 +349,11 @@ sysenter_past_esp:
movl PT_OLDESP(%esp), %ecx
xorl %ebp,%ebp
TRACE_IRQS_ON
1: mov PT_GS(%esp), %gs
1: mov PT_FS(%esp), %fs
ENABLE_INTERRUPTS_SYSEXIT
CFI_ENDPROC
.pushsection .fixup,"ax"
2: movl $0,PT_GS(%esp)
2: movl $0,PT_FS(%esp)
jmp 1b
.section __ex_table,"a"
.align 4
Expand Down Expand Up @@ -550,7 +550,7 @@ syscall_badsys:

#define FIXUP_ESPFIX_STACK \
/* since we are on a wrong stack, we cant make it a C code :( */ \
movl %gs:PDA_cpu, %ebx; \
movl %fs:PDA_cpu, %ebx; \
PER_CPU(cpu_gdt_descr, %ebx); \
movl GDS_address(%ebx), %ebx; \
GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah); \
Expand Down Expand Up @@ -632,7 +632,7 @@ KPROBE_ENTRY(page_fault)
CFI_ADJUST_CFA_OFFSET 4
ALIGN
error_code:
/* the function address is in %gs's slot on the stack */
/* the function address is in %fs's slot on the stack */
pushl %es
CFI_ADJUST_CFA_OFFSET 4
/*CFI_REL_OFFSET es, 0*/
Expand Down Expand Up @@ -661,20 +661,20 @@ error_code:
CFI_ADJUST_CFA_OFFSET 4
CFI_REL_OFFSET ebx, 0
cld
pushl %gs
pushl %fs
CFI_ADJUST_CFA_OFFSET 4
/*CFI_REL_OFFSET gs, 0*/
/*CFI_REL_OFFSET fs, 0*/
movl $(__KERNEL_PDA), %ecx
movl %ecx, %gs
movl %ecx, %fs
UNWIND_ESPFIX_STACK
popl %ecx
CFI_ADJUST_CFA_OFFSET -4
/*CFI_REGISTER es, ecx*/
movl PT_GS(%esp), %edi # get the function address
movl PT_FS(%esp), %edi # get the function address
movl PT_ORIG_EAX(%esp), %edx # get the error code
movl $-1, PT_ORIG_EAX(%esp) # no syscall to restart
mov %ecx, PT_GS(%esp)
/*CFI_REL_OFFSET gs, ES*/
mov %ecx, PT_FS(%esp)
/*CFI_REL_OFFSET fs, ES*/
movl $(__USER_DS), %ecx
movl %ecx, %ds
movl %ecx, %es
Expand Down
6 changes: 3 additions & 3 deletions arch/i386/kernel/head.S
Original file line number Diff line number Diff line change
Expand Up @@ -319,12 +319,12 @@ is386: movl $2,%ecx # set MP
movl %eax,%ds
movl %eax,%es

xorl %eax,%eax # Clear FS and LDT
movl %eax,%fs
xorl %eax,%eax # Clear GS and LDT
movl %eax,%gs
lldt %ax

movl $(__KERNEL_PDA),%eax
mov %eax,%gs
mov %eax,%fs

cld # gcc2 wants the direction flag cleared at all times
pushl $0 # fake return address for unwinder
Expand Down
4 changes: 2 additions & 2 deletions arch/i386/kernel/kprobes.c
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
" pushf\n"
/* skip cs, eip, orig_eax */
" subl $12, %esp\n"
" pushl %gs\n"
" pushl %fs\n"
" pushl %ds\n"
" pushl %es\n"
" pushl %eax\n"
Expand All @@ -387,7 +387,7 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
" popl %edi\n"
" popl %ebp\n"
" popl %eax\n"
/* skip eip, orig_eax, es, ds, gs */
/* skip eip, orig_eax, es, ds, fs */
" addl $20, %esp\n"
" popf\n"
" ret\n");
Expand Down
24 changes: 11 additions & 13 deletions arch/i386/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,8 +308,8 @@ void show_regs(struct pt_regs * regs)
regs->eax,regs->ebx,regs->ecx,regs->edx);
printk("ESI: %08lx EDI: %08lx EBP: %08lx",
regs->esi, regs->edi, regs->ebp);
printk(" DS: %04x ES: %04x GS: %04x\n",
0xffff & regs->xds,0xffff & regs->xes, 0xffff & regs->xgs);
printk(" DS: %04x ES: %04x FS: %04x\n",
0xffff & regs->xds,0xffff & regs->xes, 0xffff & regs->xfs);

cr0 = read_cr0();
cr2 = read_cr2();
Expand Down Expand Up @@ -340,7 +340,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)

regs.xds = __USER_DS;
regs.xes = __USER_DS;
regs.xgs = __KERNEL_PDA;
regs.xfs = __KERNEL_PDA;
regs.orig_eax = -1;
regs.eip = (unsigned long) kernel_thread_helper;
regs.xcs = __KERNEL_CS | get_kernel_rpl();
Expand Down Expand Up @@ -425,7 +425,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,

p->thread.eip = (unsigned long) ret_from_fork;

savesegment(fs,p->thread.fs);
savesegment(gs,p->thread.gs);

tsk = current;
if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) {
Expand Down Expand Up @@ -501,8 +501,8 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
dump->regs.eax = regs->eax;
dump->regs.ds = regs->xds;
dump->regs.es = regs->xes;
savesegment(fs,dump->regs.fs);
dump->regs.gs = regs->xgs;
dump->regs.fs = regs->xfs;
savesegment(gs,dump->regs.gs);
dump->regs.orig_eax = regs->orig_eax;
dump->regs.eip = regs->eip;
dump->regs.cs = regs->xcs;
Expand Down Expand Up @@ -653,7 +653,7 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas
load_esp0(tss, next);

/*
* Save away %fs. No need to save %gs, as it was saved on the
* Save away %gs. No need to save %fs, as it was saved on the
* stack on entry. No need to save %es and %ds, as those are
* always kernel segments while inside the kernel. Doing this
* before setting the new TLS descriptors avoids the situation
Expand All @@ -662,20 +662,18 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas
* used %fs or %gs (it does not today), or if the kernel is
* running inside of a hypervisor layer.
*/
savesegment(fs, prev->fs);
savesegment(gs, prev->gs);

/*
* Load the per-thread Thread-Local Storage descriptor.
*/
load_TLS(next, cpu);

/*
* Restore %fs if needed.
*
* Glibc normally makes %fs be zero.
* Restore %gs if needed (which is common)
*/
if (unlikely(prev->fs | next->fs))
loadsegment(fs, next->fs);
if (prev->gs | next->gs)
loadsegment(gs, next->gs);

write_pda(pcurrent, next_p);

Expand Down
16 changes: 8 additions & 8 deletions arch/i386/kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,14 @@ static int putreg(struct task_struct *child,
unsigned long regno, unsigned long value)
{
switch (regno >> 2) {
case FS:
case GS:
if (value && (value & 3) != 3)
return -EIO;
child->thread.fs = value;
child->thread.gs = value;
return 0;
case DS:
case ES:
case GS:
case FS:
if (value && (value & 3) != 3)
return -EIO;
value &= 0xffff;
Expand All @@ -112,7 +112,7 @@ static int putreg(struct task_struct *child,
value |= get_stack_long(child, EFL_OFFSET) & ~FLAG_MASK;
break;
}
if (regno > ES*4)
if (regno > FS*4)
regno -= 1*4;
put_stack_long(child, regno, value);
return 0;
Expand All @@ -124,18 +124,18 @@ static unsigned long getreg(struct task_struct *child,
unsigned long retval = ~0UL;

switch (regno >> 2) {
case FS:
retval = child->thread.fs;
case GS:
retval = child->thread.gs;
break;
case DS:
case ES:
case GS:
case FS:
case SS:
case CS:
retval = 0xffff;
/* fall through */
default:
if (regno > ES*4)
if (regno > FS*4)
regno -= 1*4;
retval &= get_stack_long(child, regno);
}
Expand Down
10 changes: 5 additions & 5 deletions arch/i386/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *peax
X86_EFLAGS_TF | X86_EFLAGS_SF | X86_EFLAGS_ZF | \
X86_EFLAGS_AF | X86_EFLAGS_PF | X86_EFLAGS_CF)

COPY_SEG(gs);
GET_SEG(fs);
GET_SEG(gs);
COPY_SEG(fs);
COPY_SEG(es);
COPY_SEG(ds);
COPY(edi);
Expand Down Expand Up @@ -244,9 +244,9 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
{
int tmp, err = 0;

err |= __put_user(regs->xgs, (unsigned int __user *)&sc->gs);
savesegment(fs, tmp);
err |= __put_user(tmp, (unsigned int __user *)&sc->fs);
err |= __put_user(regs->xfs, (unsigned int __user *)&sc->fs);
savesegment(gs, tmp);
err |= __put_user(tmp, (unsigned int __user *)&sc->gs);

err |= __put_user(regs->xes, (unsigned int __user *)&sc->es);
err |= __put_user(regs->xds, (unsigned int __user *)&sc->ds);
Expand Down
7 changes: 4 additions & 3 deletions arch/i386/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -291,10 +291,11 @@ void show_registers(struct pt_regs *regs)
int i;
int in_kernel = 1;
unsigned long esp;
unsigned short ss;
unsigned short ss, gs;

esp = (unsigned long) (&regs->esp);
savesegment(ss, ss);
savesegment(gs, gs);
if (user_mode_vm(regs)) {
in_kernel = 0;
esp = regs->esp;
Expand All @@ -313,8 +314,8 @@ void show_registers(struct pt_regs *regs)
regs->eax, regs->ebx, regs->ecx, regs->edx);
printk(KERN_EMERG "esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n",
regs->esi, regs->edi, regs->ebp, esp);
printk(KERN_EMERG "ds: %04x es: %04x ss: %04x\n",
regs->xds & 0xffff, regs->xes & 0xffff, ss);
printk(KERN_EMERG "ds: %04x es: %04x fs: %04x gs: %04x ss: %04x\n",
regs->xds & 0xffff, regs->xes & 0xffff, regs->xfs & 0xffff, gs, ss);
printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)",
TASK_COMM_LEN, current->comm, current->pid,
current_thread_info(), current, current->thread_info);
Expand Down
Loading

0 comments on commit 464d1a7

Please sign in to comment.