[PATCH] i386: Convert PDA into the percpu section
Currently x86 (similar to x84-64) has a special per-cpu structure called "i386_pda" which can be easily and efficiently referenced via the %fs register. An ELF section is more flexible than a structure, allowing any piece of code to use this area. Indeed, such a section already exists: the per-cpu area. So this patch: (1) Removes the PDA and uses per-cpu variables for each current member. (2) Replaces the __KERNEL_PDA segment with __KERNEL_PERCPU. (3) Creates a per-cpu mirror of __per_cpu_offset called this_cpu_off, which can be used to calculate addresses for this CPU's variables. (4) Simplifies startup, because %fs doesn't need to be loaded with a special segment at early boot; it can be deferred until the first percpu area is allocated (or never for UP). The result is less code and one less x86-specific concept. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com> Signed-off-by: Andi Kleen <ak@suse.de> Cc: Andi Kleen <ak@suse.de>
This commit is contained in:
parent
7a61d35d4b
commit
7c3576d261
@ -15,7 +15,6 @@
|
|||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
#include <asm/thread_info.h>
|
#include <asm/thread_info.h>
|
||||||
#include <asm/elf.h>
|
#include <asm/elf.h>
|
||||||
#include <asm/pda.h>
|
|
||||||
|
|
||||||
#define DEFINE(sym, val) \
|
#define DEFINE(sym, val) \
|
||||||
asm volatile("\n->" #sym " %0 " #val : : "i" (val))
|
asm volatile("\n->" #sym " %0 " #val : : "i" (val))
|
||||||
@ -101,10 +100,6 @@ void foo(void)
|
|||||||
|
|
||||||
OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx);
|
OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx);
|
||||||
|
|
||||||
BLANK();
|
|
||||||
OFFSET(PDA_cpu, i386_pda, cpu_number);
|
|
||||||
OFFSET(PDA_pcurrent, i386_pda, pcurrent);
|
|
||||||
|
|
||||||
#ifdef CONFIG_PARAVIRT
|
#ifdef CONFIG_PARAVIRT
|
||||||
BLANK();
|
BLANK();
|
||||||
OFFSET(PARAVIRT_enabled, paravirt_ops, paravirt_enabled);
|
OFFSET(PARAVIRT_enabled, paravirt_ops, paravirt_enabled);
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
#include <asm/apic.h>
|
#include <asm/apic.h>
|
||||||
#include <mach_apic.h>
|
#include <mach_apic.h>
|
||||||
#endif
|
#endif
|
||||||
#include <asm/pda.h>
|
|
||||||
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
|
||||||
@ -47,13 +46,10 @@ DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = {
|
|||||||
[GDT_ENTRY_APMBIOS_BASE+2] = { 0x0000ffff, 0x00409200 }, /* data */
|
[GDT_ENTRY_APMBIOS_BASE+2] = { 0x0000ffff, 0x00409200 }, /* data */
|
||||||
|
|
||||||
[GDT_ENTRY_ESPFIX_SS] = { 0x00000000, 0x00c09200 },
|
[GDT_ENTRY_ESPFIX_SS] = { 0x00000000, 0x00c09200 },
|
||||||
[GDT_ENTRY_PDA] = { 0x00000000, 0x00c09200 }, /* set in setup_pda */
|
[GDT_ENTRY_PERCPU] = { 0x00000000, 0x00000000 },
|
||||||
} };
|
} };
|
||||||
EXPORT_PER_CPU_SYMBOL_GPL(gdt_page);
|
EXPORT_PER_CPU_SYMBOL_GPL(gdt_page);
|
||||||
|
|
||||||
DEFINE_PER_CPU(struct i386_pda, _cpu_pda);
|
|
||||||
EXPORT_PER_CPU_SYMBOL(_cpu_pda);
|
|
||||||
|
|
||||||
static int cachesize_override __cpuinitdata = -1;
|
static int cachesize_override __cpuinitdata = -1;
|
||||||
static int disable_x86_fxsr __cpuinitdata;
|
static int disable_x86_fxsr __cpuinitdata;
|
||||||
static int disable_x86_serial_nr __cpuinitdata = 1;
|
static int disable_x86_serial_nr __cpuinitdata = 1;
|
||||||
@ -634,21 +630,14 @@ void __init early_cpu_init(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure %gs is initialized properly in idle threads */
|
/* Make sure %fs is initialized properly in idle threads */
|
||||||
struct pt_regs * __devinit idle_regs(struct pt_regs *regs)
|
struct pt_regs * __devinit idle_regs(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
memset(regs, 0, sizeof(struct pt_regs));
|
memset(regs, 0, sizeof(struct pt_regs));
|
||||||
regs->xfs = __KERNEL_PDA;
|
regs->xfs = __KERNEL_PERCPU;
|
||||||
return regs;
|
return regs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initial PDA used by boot CPU */
|
|
||||||
struct i386_pda boot_pda = {
|
|
||||||
._pda = &boot_pda,
|
|
||||||
.cpu_number = 0,
|
|
||||||
.pcurrent = &init_task,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* cpu_init() initializes state that is per-CPU. Some data is already
|
* cpu_init() initializes state that is per-CPU. Some data is already
|
||||||
* initialized (naturally) in the bootstrap process, such as the GDT
|
* initialized (naturally) in the bootstrap process, such as the GDT
|
||||||
|
@ -132,7 +132,7 @@ VM_MASK = 0x00020000
|
|||||||
movl $(__USER_DS), %edx; \
|
movl $(__USER_DS), %edx; \
|
||||||
movl %edx, %ds; \
|
movl %edx, %ds; \
|
||||||
movl %edx, %es; \
|
movl %edx, %es; \
|
||||||
movl $(__KERNEL_PDA), %edx; \
|
movl $(__KERNEL_PERCPU), %edx; \
|
||||||
movl %edx, %fs
|
movl %edx, %fs
|
||||||
|
|
||||||
#define RESTORE_INT_REGS \
|
#define RESTORE_INT_REGS \
|
||||||
@ -556,7 +556,6 @@ END(syscall_badsys)
|
|||||||
|
|
||||||
#define FIXUP_ESPFIX_STACK \
|
#define FIXUP_ESPFIX_STACK \
|
||||||
/* since we are on a wrong stack, we cant make it a C code :( */ \
|
/* since we are on a wrong stack, we cant make it a C code :( */ \
|
||||||
movl %fs:PDA_cpu, %ebx; \
|
|
||||||
PER_CPU(gdt_page, %ebx); \
|
PER_CPU(gdt_page, %ebx); \
|
||||||
GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah); \
|
GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah); \
|
||||||
addl %esp, %eax; \
|
addl %esp, %eax; \
|
||||||
@ -681,7 +680,7 @@ error_code:
|
|||||||
pushl %fs
|
pushl %fs
|
||||||
CFI_ADJUST_CFA_OFFSET 4
|
CFI_ADJUST_CFA_OFFSET 4
|
||||||
/*CFI_REL_OFFSET fs, 0*/
|
/*CFI_REL_OFFSET fs, 0*/
|
||||||
movl $(__KERNEL_PDA), %ecx
|
movl $(__KERNEL_PERCPU), %ecx
|
||||||
movl %ecx, %fs
|
movl %ecx, %fs
|
||||||
UNWIND_ESPFIX_STACK
|
UNWIND_ESPFIX_STACK
|
||||||
popl %ecx
|
popl %ecx
|
||||||
|
@ -317,12 +317,12 @@ is386: movl $2,%ecx # set MP
|
|||||||
movl %eax,%cr0
|
movl %eax,%cr0
|
||||||
|
|
||||||
call check_x87
|
call check_x87
|
||||||
call setup_pda
|
|
||||||
lgdt early_gdt_descr
|
lgdt early_gdt_descr
|
||||||
lidt idt_descr
|
lidt idt_descr
|
||||||
ljmp $(__KERNEL_CS),$1f
|
ljmp $(__KERNEL_CS),$1f
|
||||||
1: movl $(__KERNEL_DS),%eax # reload all the segment registers
|
1: movl $(__KERNEL_DS),%eax # reload all the segment registers
|
||||||
movl %eax,%ss # after changing gdt.
|
movl %eax,%ss # after changing gdt.
|
||||||
|
movl %eax,%fs # gets reset once there's real percpu
|
||||||
|
|
||||||
movl $(__USER_DS),%eax # DS/ES contains default USER segment
|
movl $(__USER_DS),%eax # DS/ES contains default USER segment
|
||||||
movl %eax,%ds
|
movl %eax,%ds
|
||||||
@ -332,16 +332,17 @@ is386: movl $2,%ecx # set MP
|
|||||||
movl %eax,%gs
|
movl %eax,%gs
|
||||||
lldt %ax
|
lldt %ax
|
||||||
|
|
||||||
movl $(__KERNEL_PDA),%eax
|
|
||||||
mov %eax,%fs
|
|
||||||
|
|
||||||
cld # gcc2 wants the direction flag cleared at all times
|
cld # gcc2 wants the direction flag cleared at all times
|
||||||
pushl $0 # fake return address for unwinder
|
pushl $0 # fake return address for unwinder
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
movb ready, %cl
|
movb ready, %cl
|
||||||
movb $1, ready
|
movb $1, ready
|
||||||
cmpb $0,%cl # the first CPU calls start_kernel
|
cmpb $0,%cl # the first CPU calls start_kernel
|
||||||
jne initialize_secondary # all other CPUs call initialize_secondary
|
je 1f
|
||||||
|
movl $(__KERNEL_PERCPU), %eax
|
||||||
|
movl %eax,%fs # set this cpu's percpu
|
||||||
|
jmp initialize_secondary # all other CPUs call initialize_secondary
|
||||||
|
1:
|
||||||
#endif /* CONFIG_SMP */
|
#endif /* CONFIG_SMP */
|
||||||
jmp start_kernel
|
jmp start_kernel
|
||||||
|
|
||||||
@ -364,23 +365,6 @@ check_x87:
|
|||||||
.byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */
|
.byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */
|
||||||
ret
|
ret
|
||||||
|
|
||||||
/*
|
|
||||||
* Point the GDT at this CPU's PDA. On boot this will be
|
|
||||||
* cpu_gdt_table and boot_pda; for secondary CPUs, these will be
|
|
||||||
* that CPU's GDT and PDA.
|
|
||||||
*/
|
|
||||||
ENTRY(setup_pda)
|
|
||||||
/* get the PDA pointer */
|
|
||||||
movl start_pda, %eax
|
|
||||||
|
|
||||||
/* slot the PDA address into the GDT */
|
|
||||||
mov early_gdt_descr+2, %ecx
|
|
||||||
mov %ax, (__KERNEL_PDA+0+2)(%ecx) /* base & 0x0000ffff */
|
|
||||||
shr $16, %eax
|
|
||||||
mov %al, (__KERNEL_PDA+4+0)(%ecx) /* base & 0x00ff0000 */
|
|
||||||
mov %ah, (__KERNEL_PDA+4+3)(%ecx) /* base & 0xff000000 */
|
|
||||||
ret
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* setup_idt
|
* setup_idt
|
||||||
*
|
*
|
||||||
@ -553,9 +537,6 @@ ENTRY(empty_zero_page)
|
|||||||
* This starts the data section.
|
* This starts the data section.
|
||||||
*/
|
*/
|
||||||
.data
|
.data
|
||||||
ENTRY(start_pda)
|
|
||||||
.long boot_pda
|
|
||||||
|
|
||||||
ENTRY(stack_start)
|
ENTRY(stack_start)
|
||||||
.long init_thread_union+THREAD_SIZE
|
.long init_thread_union+THREAD_SIZE
|
||||||
.long __BOOT_DS
|
.long __BOOT_DS
|
||||||
|
@ -28,5 +28,3 @@ EXPORT_SYMBOL(__read_lock_failed);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
EXPORT_SYMBOL(csum_partial);
|
EXPORT_SYMBOL(csum_partial);
|
||||||
|
|
||||||
EXPORT_SYMBOL(_proxy_pda);
|
|
||||||
|
@ -24,6 +24,9 @@
|
|||||||
DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_internodealigned_in_smp;
|
DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_internodealigned_in_smp;
|
||||||
EXPORT_PER_CPU_SYMBOL(irq_stat);
|
EXPORT_PER_CPU_SYMBOL(irq_stat);
|
||||||
|
|
||||||
|
DEFINE_PER_CPU(struct pt_regs *, irq_regs);
|
||||||
|
EXPORT_PER_CPU_SYMBOL(irq_regs);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 'what should we do if we get a hw irq event on an illegal vector'.
|
* 'what should we do if we get a hw irq event on an illegal vector'.
|
||||||
* each architecture has to answer this themselves.
|
* each architecture has to answer this themselves.
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include <linux/random.h>
|
#include <linux/random.h>
|
||||||
#include <linux/personality.h>
|
#include <linux/personality.h>
|
||||||
#include <linux/tick.h>
|
#include <linux/tick.h>
|
||||||
|
#include <linux/percpu.h>
|
||||||
|
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
@ -57,7 +58,6 @@
|
|||||||
|
|
||||||
#include <asm/tlbflush.h>
|
#include <asm/tlbflush.h>
|
||||||
#include <asm/cpu.h>
|
#include <asm/cpu.h>
|
||||||
#include <asm/pda.h>
|
|
||||||
|
|
||||||
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
|
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
|
||||||
|
|
||||||
@ -66,6 +66,12 @@ static int hlt_counter;
|
|||||||
unsigned long boot_option_idle_override = 0;
|
unsigned long boot_option_idle_override = 0;
|
||||||
EXPORT_SYMBOL(boot_option_idle_override);
|
EXPORT_SYMBOL(boot_option_idle_override);
|
||||||
|
|
||||||
|
DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task;
|
||||||
|
EXPORT_PER_CPU_SYMBOL(current_task);
|
||||||
|
|
||||||
|
DEFINE_PER_CPU(int, cpu_number);
|
||||||
|
EXPORT_PER_CPU_SYMBOL(cpu_number);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return saved PC of a blocked thread.
|
* Return saved PC of a blocked thread.
|
||||||
*/
|
*/
|
||||||
@ -342,7 +348,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
|
|||||||
|
|
||||||
regs.xds = __USER_DS;
|
regs.xds = __USER_DS;
|
||||||
regs.xes = __USER_DS;
|
regs.xes = __USER_DS;
|
||||||
regs.xfs = __KERNEL_PDA;
|
regs.xfs = __KERNEL_PERCPU;
|
||||||
regs.orig_eax = -1;
|
regs.orig_eax = -1;
|
||||||
regs.eip = (unsigned long) kernel_thread_helper;
|
regs.eip = (unsigned long) kernel_thread_helper;
|
||||||
regs.xcs = __KERNEL_CS | get_kernel_rpl();
|
regs.xcs = __KERNEL_CS | get_kernel_rpl();
|
||||||
@ -711,7 +717,7 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas
|
|||||||
if (prev->gs | next->gs)
|
if (prev->gs | next->gs)
|
||||||
loadsegment(gs, next->gs);
|
loadsegment(gs, next->gs);
|
||||||
|
|
||||||
write_pda(pcurrent, next_p);
|
x86_write_percpu(current_task, next_p);
|
||||||
|
|
||||||
return prev_p;
|
return prev_p;
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,6 @@
|
|||||||
#include <asm/desc.h>
|
#include <asm/desc.h>
|
||||||
#include <asm/arch_hooks.h>
|
#include <asm/arch_hooks.h>
|
||||||
#include <asm/nmi.h>
|
#include <asm/nmi.h>
|
||||||
#include <asm/pda.h>
|
|
||||||
|
|
||||||
#include <mach_apic.h>
|
#include <mach_apic.h>
|
||||||
#include <mach_wakecpu.h>
|
#include <mach_wakecpu.h>
|
||||||
@ -99,6 +98,9 @@ EXPORT_SYMBOL(x86_cpu_to_apicid);
|
|||||||
|
|
||||||
u8 apicid_2_node[MAX_APICID];
|
u8 apicid_2_node[MAX_APICID];
|
||||||
|
|
||||||
|
DEFINE_PER_CPU(unsigned long, this_cpu_off);
|
||||||
|
EXPORT_PER_CPU_SYMBOL(this_cpu_off);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Trampoline 80x86 program as an array.
|
* Trampoline 80x86 program as an array.
|
||||||
*/
|
*/
|
||||||
@ -456,7 +458,6 @@ extern struct {
|
|||||||
void * esp;
|
void * esp;
|
||||||
unsigned short ss;
|
unsigned short ss;
|
||||||
} stack_start;
|
} stack_start;
|
||||||
extern struct i386_pda *start_pda;
|
|
||||||
|
|
||||||
#ifdef CONFIG_NUMA
|
#ifdef CONFIG_NUMA
|
||||||
|
|
||||||
@ -784,20 +785,17 @@ static inline struct task_struct * alloc_idle_task(int cpu)
|
|||||||
/* Initialize the CPU's GDT. This is either the boot CPU doing itself
|
/* Initialize the CPU's GDT. This is either the boot CPU doing itself
|
||||||
(still using the master per-cpu area), or a CPU doing it for a
|
(still using the master per-cpu area), or a CPU doing it for a
|
||||||
secondary which will soon come up. */
|
secondary which will soon come up. */
|
||||||
static __cpuinit void init_gdt(int cpu, struct task_struct *idle)
|
static __cpuinit void init_gdt(int cpu)
|
||||||
{
|
{
|
||||||
struct desc_struct *gdt = get_cpu_gdt_table(cpu);
|
struct desc_struct *gdt = get_cpu_gdt_table(cpu);
|
||||||
struct i386_pda *pda = &per_cpu(_cpu_pda, cpu);
|
|
||||||
|
|
||||||
pack_descriptor((u32 *)&gdt[GDT_ENTRY_PDA].a,
|
pack_descriptor((u32 *)&gdt[GDT_ENTRY_PERCPU].a,
|
||||||
(u32 *)&gdt[GDT_ENTRY_PDA].b,
|
(u32 *)&gdt[GDT_ENTRY_PERCPU].b,
|
||||||
(unsigned long)pda, sizeof(*pda) - 1,
|
__per_cpu_offset[cpu], 0xFFFFF,
|
||||||
0x80 | DESCTYPE_S | 0x2, 0); /* present read-write data segment */
|
0x80 | DESCTYPE_S | 0x2, 0x8);
|
||||||
|
|
||||||
memset(pda, 0, sizeof(*pda));
|
per_cpu(this_cpu_off, cpu) = __per_cpu_offset[cpu];
|
||||||
pda->_pda = pda;
|
per_cpu(cpu_number, cpu) = cpu;
|
||||||
pda->cpu_number = cpu;
|
|
||||||
pda->pcurrent = idle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Defined in head.S */
|
/* Defined in head.S */
|
||||||
@ -824,9 +822,9 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
|
|||||||
if (IS_ERR(idle))
|
if (IS_ERR(idle))
|
||||||
panic("failed fork for CPU %d", cpu);
|
panic("failed fork for CPU %d", cpu);
|
||||||
|
|
||||||
init_gdt(cpu, idle);
|
init_gdt(cpu);
|
||||||
|
per_cpu(current_task, cpu) = idle;
|
||||||
early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu);
|
early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu);
|
||||||
start_pda = cpu_pda(cpu);
|
|
||||||
|
|
||||||
idle->thread.eip = (unsigned long) start_secondary;
|
idle->thread.eip = (unsigned long) start_secondary;
|
||||||
/* start_eip had better be page-aligned! */
|
/* start_eip had better be page-aligned! */
|
||||||
@ -1188,14 +1186,14 @@ static inline void switch_to_new_gdt(void)
|
|||||||
gdt_descr.address = (long)get_cpu_gdt_table(smp_processor_id());
|
gdt_descr.address = (long)get_cpu_gdt_table(smp_processor_id());
|
||||||
gdt_descr.size = GDT_SIZE - 1;
|
gdt_descr.size = GDT_SIZE - 1;
|
||||||
load_gdt(&gdt_descr);
|
load_gdt(&gdt_descr);
|
||||||
asm volatile ("mov %0, %%fs" : : "r" (__KERNEL_PDA) : "memory");
|
asm("mov %0, %%fs" : : "r" (__KERNEL_PERCPU) : "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
void __init native_smp_prepare_boot_cpu(void)
|
void __init native_smp_prepare_boot_cpu(void)
|
||||||
{
|
{
|
||||||
unsigned int cpu = smp_processor_id();
|
unsigned int cpu = smp_processor_id();
|
||||||
|
|
||||||
init_gdt(cpu, current);
|
init_gdt(cpu);
|
||||||
switch_to_new_gdt();
|
switch_to_new_gdt();
|
||||||
|
|
||||||
cpu_set(cpu, cpu_online_map);
|
cpu_set(cpu, cpu_online_map);
|
||||||
|
@ -504,8 +504,6 @@ static void vmi_pmd_clear(pmd_t *pmd)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
extern void setup_pda(void);
|
|
||||||
|
|
||||||
static void __devinit
|
static void __devinit
|
||||||
vmi_startup_ipi_hook(int phys_apicid, unsigned long start_eip,
|
vmi_startup_ipi_hook(int phys_apicid, unsigned long start_eip,
|
||||||
unsigned long start_esp)
|
unsigned long start_esp)
|
||||||
@ -530,13 +528,11 @@ vmi_startup_ipi_hook(int phys_apicid, unsigned long start_eip,
|
|||||||
|
|
||||||
ap.ds = __USER_DS;
|
ap.ds = __USER_DS;
|
||||||
ap.es = __USER_DS;
|
ap.es = __USER_DS;
|
||||||
ap.fs = __KERNEL_PDA;
|
ap.fs = __KERNEL_PERCPU;
|
||||||
ap.gs = 0;
|
ap.gs = 0;
|
||||||
|
|
||||||
ap.eflags = 0;
|
ap.eflags = 0;
|
||||||
|
|
||||||
setup_pda();
|
|
||||||
|
|
||||||
#ifdef CONFIG_X86_PAE
|
#ifdef CONFIG_X86_PAE
|
||||||
/* efer should match BSP efer. */
|
/* efer should match BSP efer. */
|
||||||
if (cpu_has_nx) {
|
if (cpu_has_nx) {
|
||||||
|
@ -26,7 +26,6 @@ OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
|||||||
OUTPUT_ARCH(i386)
|
OUTPUT_ARCH(i386)
|
||||||
ENTRY(phys_startup_32)
|
ENTRY(phys_startup_32)
|
||||||
jiffies = jiffies_64;
|
jiffies = jiffies_64;
|
||||||
_proxy_pda = 1;
|
|
||||||
|
|
||||||
PHDRS {
|
PHDRS {
|
||||||
text PT_LOAD FLAGS(5); /* R_E */
|
text PT_LOAD FLAGS(5); /* R_E */
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
#ifndef _I386_CURRENT_H
|
#ifndef _I386_CURRENT_H
|
||||||
#define _I386_CURRENT_H
|
#define _I386_CURRENT_H
|
||||||
|
|
||||||
#include <asm/pda.h>
|
|
||||||
#include <linux/compiler.h>
|
#include <linux/compiler.h>
|
||||||
|
#include <asm/percpu.h>
|
||||||
|
|
||||||
struct task_struct;
|
struct task_struct;
|
||||||
|
|
||||||
|
DECLARE_PER_CPU(struct task_struct *, current_task);
|
||||||
static __always_inline struct task_struct *get_current(void)
|
static __always_inline struct task_struct *get_current(void)
|
||||||
{
|
{
|
||||||
return read_pda(pcurrent);
|
return x86_read_percpu(current_task);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define current get_current()
|
#define current get_current()
|
||||||
|
@ -1,25 +1,27 @@
|
|||||||
/*
|
/*
|
||||||
* Per-cpu current frame pointer - the location of the last exception frame on
|
* Per-cpu current frame pointer - the location of the last exception frame on
|
||||||
* the stack, stored in the PDA.
|
* the stack, stored in the per-cpu area.
|
||||||
*
|
*
|
||||||
* Jeremy Fitzhardinge <jeremy@goop.org>
|
* Jeremy Fitzhardinge <jeremy@goop.org>
|
||||||
*/
|
*/
|
||||||
#ifndef _ASM_I386_IRQ_REGS_H
|
#ifndef _ASM_I386_IRQ_REGS_H
|
||||||
#define _ASM_I386_IRQ_REGS_H
|
#define _ASM_I386_IRQ_REGS_H
|
||||||
|
|
||||||
#include <asm/pda.h>
|
#include <asm/percpu.h>
|
||||||
|
|
||||||
|
DECLARE_PER_CPU(struct pt_regs *, irq_regs);
|
||||||
|
|
||||||
static inline struct pt_regs *get_irq_regs(void)
|
static inline struct pt_regs *get_irq_regs(void)
|
||||||
{
|
{
|
||||||
return read_pda(irq_regs);
|
return x86_read_percpu(irq_regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs)
|
static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs)
|
||||||
{
|
{
|
||||||
struct pt_regs *old_regs;
|
struct pt_regs *old_regs;
|
||||||
|
|
||||||
old_regs = read_pda(irq_regs);
|
old_regs = get_irq_regs();
|
||||||
write_pda(irq_regs, new_regs);
|
x86_write_percpu(irq_regs, new_regs);
|
||||||
|
|
||||||
return old_regs;
|
return old_regs;
|
||||||
}
|
}
|
||||||
|
@ -1,99 +0,0 @@
|
|||||||
/*
|
|
||||||
Per-processor Data Areas
|
|
||||||
Jeremy Fitzhardinge <jeremy@goop.org> 2006
|
|
||||||
Based on asm-x86_64/pda.h by Andi Kleen.
|
|
||||||
*/
|
|
||||||
#ifndef _I386_PDA_H
|
|
||||||
#define _I386_PDA_H
|
|
||||||
|
|
||||||
#include <linux/stddef.h>
|
|
||||||
#include <linux/types.h>
|
|
||||||
#include <asm/percpu.h>
|
|
||||||
|
|
||||||
struct i386_pda
|
|
||||||
{
|
|
||||||
struct i386_pda *_pda; /* pointer to self */
|
|
||||||
|
|
||||||
int cpu_number;
|
|
||||||
struct task_struct *pcurrent; /* current process */
|
|
||||||
struct pt_regs *irq_regs;
|
|
||||||
};
|
|
||||||
|
|
||||||
DECLARE_PER_CPU(struct i386_pda, _cpu_pda);
|
|
||||||
#define cpu_pda(i) (&per_cpu(_cpu_pda, (i)))
|
|
||||||
#define pda_offset(field) offsetof(struct i386_pda, field)
|
|
||||||
|
|
||||||
extern void __bad_pda_field(void);
|
|
||||||
|
|
||||||
/* This variable is never instantiated. It is only used as a stand-in
|
|
||||||
for the real per-cpu PDA memory, so that gcc can understand what
|
|
||||||
memory operations the inline asms() below are performing. This
|
|
||||||
eliminates the need to make the asms volatile or have memory
|
|
||||||
clobbers, so gcc can readily analyse them. */
|
|
||||||
extern struct i386_pda _proxy_pda;
|
|
||||||
|
|
||||||
#define pda_to_op(op,field,val) \
|
|
||||||
do { \
|
|
||||||
typedef typeof(_proxy_pda.field) T__; \
|
|
||||||
if (0) { T__ tmp__; tmp__ = (val); } \
|
|
||||||
switch (sizeof(_proxy_pda.field)) { \
|
|
||||||
case 1: \
|
|
||||||
asm(op "b %1,%%fs:%c2" \
|
|
||||||
: "+m" (_proxy_pda.field) \
|
|
||||||
:"ri" ((T__)val), \
|
|
||||||
"i"(pda_offset(field))); \
|
|
||||||
break; \
|
|
||||||
case 2: \
|
|
||||||
asm(op "w %1,%%fs:%c2" \
|
|
||||||
: "+m" (_proxy_pda.field) \
|
|
||||||
:"ri" ((T__)val), \
|
|
||||||
"i"(pda_offset(field))); \
|
|
||||||
break; \
|
|
||||||
case 4: \
|
|
||||||
asm(op "l %1,%%fs:%c2" \
|
|
||||||
: "+m" (_proxy_pda.field) \
|
|
||||||
:"ri" ((T__)val), \
|
|
||||||
"i"(pda_offset(field))); \
|
|
||||||
break; \
|
|
||||||
default: __bad_pda_field(); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define pda_from_op(op,field) \
|
|
||||||
({ \
|
|
||||||
typeof(_proxy_pda.field) ret__; \
|
|
||||||
switch (sizeof(_proxy_pda.field)) { \
|
|
||||||
case 1: \
|
|
||||||
asm(op "b %%fs:%c1,%0" \
|
|
||||||
: "=r" (ret__) \
|
|
||||||
: "i" (pda_offset(field)), \
|
|
||||||
"m" (_proxy_pda.field)); \
|
|
||||||
break; \
|
|
||||||
case 2: \
|
|
||||||
asm(op "w %%fs:%c1,%0" \
|
|
||||||
: "=r" (ret__) \
|
|
||||||
: "i" (pda_offset(field)), \
|
|
||||||
"m" (_proxy_pda.field)); \
|
|
||||||
break; \
|
|
||||||
case 4: \
|
|
||||||
asm(op "l %%fs:%c1,%0" \
|
|
||||||
: "=r" (ret__) \
|
|
||||||
: "i" (pda_offset(field)), \
|
|
||||||
"m" (_proxy_pda.field)); \
|
|
||||||
break; \
|
|
||||||
default: __bad_pda_field(); \
|
|
||||||
} \
|
|
||||||
ret__; })
|
|
||||||
|
|
||||||
/* Return a pointer to a pda field */
|
|
||||||
#define pda_addr(field) \
|
|
||||||
((typeof(_proxy_pda.field) *)((unsigned char *)read_pda(_pda) + \
|
|
||||||
pda_offset(field)))
|
|
||||||
|
|
||||||
#define read_pda(field) pda_from_op("mov",field)
|
|
||||||
#define write_pda(field,val) pda_to_op("mov",field,val)
|
|
||||||
#define add_pda(field,val) pda_to_op("add",field,val)
|
|
||||||
#define sub_pda(field,val) pda_to_op("sub",field,val)
|
|
||||||
#define or_pda(field,val) pda_to_op("or",field,val)
|
|
||||||
|
|
||||||
#endif /* _I386_PDA_H */
|
|
@ -1,9 +1,30 @@
|
|||||||
#ifndef __ARCH_I386_PERCPU__
|
#ifndef __ARCH_I386_PERCPU__
|
||||||
#define __ARCH_I386_PERCPU__
|
#define __ARCH_I386_PERCPU__
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
#ifdef __ASSEMBLY__
|
||||||
#include <asm-generic/percpu.h>
|
|
||||||
#else
|
/*
|
||||||
|
* PER_CPU finds an address of a per-cpu variable.
|
||||||
|
*
|
||||||
|
* Args:
|
||||||
|
* var - variable name
|
||||||
|
* reg - 32bit register
|
||||||
|
*
|
||||||
|
* The resulting address is stored in the "reg" argument.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* PER_CPU(cpu_gdt_descr, %ebx)
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
#define PER_CPU(var, reg) \
|
||||||
|
movl %fs:per_cpu__this_cpu_off, reg; \
|
||||||
|
addl $per_cpu__##var, reg
|
||||||
|
#else /* ! SMP */
|
||||||
|
#define PER_CPU(var, reg) \
|
||||||
|
movl $per_cpu__##var, reg;
|
||||||
|
#endif /* SMP */
|
||||||
|
|
||||||
|
#else /* ...!ASSEMBLY */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PER_CPU finds an address of a per-cpu variable.
|
* PER_CPU finds an address of a per-cpu variable.
|
||||||
@ -18,14 +39,107 @@
|
|||||||
* PER_CPU(cpu_gdt_descr, %ebx)
|
* PER_CPU(cpu_gdt_descr, %ebx)
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
#define PER_CPU(var, cpu) \
|
/* Same as generic implementation except for optimized local access. */
|
||||||
movl __per_cpu_offset(,cpu,4), cpu; \
|
#define __GENERIC_PER_CPU
|
||||||
addl $per_cpu__##var, cpu;
|
|
||||||
#else /* ! SMP */
|
/* This is used for other cpus to find our section. */
|
||||||
#define PER_CPU(var, cpu) \
|
extern unsigned long __per_cpu_offset[];
|
||||||
movl $per_cpu__##var, cpu;
|
|
||||||
|
/* Separate out the type, so (int[3], foo) works. */
|
||||||
|
#define DECLARE_PER_CPU(type, name) extern __typeof__(type) per_cpu__##name
|
||||||
|
#define DEFINE_PER_CPU(type, name) \
|
||||||
|
__attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
|
||||||
|
|
||||||
|
/* We can use this directly for local CPU (faster). */
|
||||||
|
DECLARE_PER_CPU(unsigned long, this_cpu_off);
|
||||||
|
|
||||||
|
/* var is in discarded region: offset to particular copy we want */
|
||||||
|
#define per_cpu(var, cpu) (*({ \
|
||||||
|
extern int simple_indentifier_##var(void); \
|
||||||
|
RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]); }))
|
||||||
|
|
||||||
|
#define __raw_get_cpu_var(var) (*({ \
|
||||||
|
extern int simple_indentifier_##var(void); \
|
||||||
|
RELOC_HIDE(&per_cpu__##var, x86_read_percpu(this_cpu_off)); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
#define __get_cpu_var(var) __raw_get_cpu_var(var)
|
||||||
|
|
||||||
|
/* A macro to avoid #include hell... */
|
||||||
|
#define percpu_modcopy(pcpudst, src, size) \
|
||||||
|
do { \
|
||||||
|
unsigned int __i; \
|
||||||
|
for_each_possible_cpu(__i) \
|
||||||
|
memcpy((pcpudst)+__per_cpu_offset[__i], \
|
||||||
|
(src), (size)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define EXPORT_PER_CPU_SYMBOL(var) EXPORT_SYMBOL(per_cpu__##var)
|
||||||
|
#define EXPORT_PER_CPU_SYMBOL_GPL(var) EXPORT_SYMBOL_GPL(per_cpu__##var)
|
||||||
|
|
||||||
|
/* fs segment starts at (positive) offset == __per_cpu_offset[cpu] */
|
||||||
|
#define __percpu_seg "%%fs:"
|
||||||
|
#else /* !SMP */
|
||||||
|
#include <asm-generic/percpu.h>
|
||||||
|
#define __percpu_seg ""
|
||||||
#endif /* SMP */
|
#endif /* SMP */
|
||||||
|
|
||||||
|
/* For arch-specific code, we can use direct single-insn ops (they
|
||||||
|
* don't give an lvalue though). */
|
||||||
|
extern void __bad_percpu_size(void);
|
||||||
|
|
||||||
|
#define percpu_to_op(op,var,val) \
|
||||||
|
do { \
|
||||||
|
typedef typeof(var) T__; \
|
||||||
|
if (0) { T__ tmp__; tmp__ = (val); } \
|
||||||
|
switch (sizeof(var)) { \
|
||||||
|
case 1: \
|
||||||
|
asm(op "b %1,"__percpu_seg"%0" \
|
||||||
|
: "+m" (var) \
|
||||||
|
:"ri" ((T__)val)); \
|
||||||
|
break; \
|
||||||
|
case 2: \
|
||||||
|
asm(op "w %1,"__percpu_seg"%0" \
|
||||||
|
: "+m" (var) \
|
||||||
|
:"ri" ((T__)val)); \
|
||||||
|
break; \
|
||||||
|
case 4: \
|
||||||
|
asm(op "l %1,"__percpu_seg"%0" \
|
||||||
|
: "+m" (var) \
|
||||||
|
:"ri" ((T__)val)); \
|
||||||
|
break; \
|
||||||
|
default: __bad_percpu_size(); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define percpu_from_op(op,var) \
|
||||||
|
({ \
|
||||||
|
typeof(var) ret__; \
|
||||||
|
switch (sizeof(var)) { \
|
||||||
|
case 1: \
|
||||||
|
asm(op "b "__percpu_seg"%1,%0" \
|
||||||
|
: "=r" (ret__) \
|
||||||
|
: "m" (var)); \
|
||||||
|
break; \
|
||||||
|
case 2: \
|
||||||
|
asm(op "w "__percpu_seg"%1,%0" \
|
||||||
|
: "=r" (ret__) \
|
||||||
|
: "m" (var)); \
|
||||||
|
break; \
|
||||||
|
case 4: \
|
||||||
|
asm(op "l "__percpu_seg"%1,%0" \
|
||||||
|
: "=r" (ret__) \
|
||||||
|
: "m" (var)); \
|
||||||
|
break; \
|
||||||
|
default: __bad_percpu_size(); \
|
||||||
|
} \
|
||||||
|
ret__; })
|
||||||
|
|
||||||
|
#define x86_read_percpu(var) percpu_from_op("mov", per_cpu__##var)
|
||||||
|
#define x86_write_percpu(var,val) percpu_to_op("mov", per_cpu__##var, val)
|
||||||
|
#define x86_add_percpu(var,val) percpu_to_op("add", per_cpu__##var, val)
|
||||||
|
#define x86_sub_percpu(var,val) percpu_to_op("sub", per_cpu__##var, val)
|
||||||
|
#define x86_or_percpu(var,val) percpu_to_op("or", per_cpu__##var, val)
|
||||||
#endif /* !__ASSEMBLY__ */
|
#endif /* !__ASSEMBLY__ */
|
||||||
|
|
||||||
#endif /* __ARCH_I386_PERCPU__ */
|
#endif /* __ARCH_I386_PERCPU__ */
|
||||||
|
@ -377,7 +377,7 @@ struct thread_struct {
|
|||||||
.vm86_info = NULL, \
|
.vm86_info = NULL, \
|
||||||
.sysenter_cs = __KERNEL_CS, \
|
.sysenter_cs = __KERNEL_CS, \
|
||||||
.io_bitmap_ptr = NULL, \
|
.io_bitmap_ptr = NULL, \
|
||||||
.fs = __KERNEL_PDA, \
|
.fs = __KERNEL_PERCPU, \
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
* 25 - APM BIOS support
|
* 25 - APM BIOS support
|
||||||
*
|
*
|
||||||
* 26 - ESPFIX small SS
|
* 26 - ESPFIX small SS
|
||||||
* 27 - PDA [ per-cpu private data area ]
|
* 27 - per-cpu [ offset to per-cpu data area ]
|
||||||
* 28 - unused
|
* 28 - unused
|
||||||
* 29 - unused
|
* 29 - unused
|
||||||
* 30 - unused
|
* 30 - unused
|
||||||
@ -74,8 +74,8 @@
|
|||||||
#define GDT_ENTRY_ESPFIX_SS (GDT_ENTRY_KERNEL_BASE + 14)
|
#define GDT_ENTRY_ESPFIX_SS (GDT_ENTRY_KERNEL_BASE + 14)
|
||||||
#define __ESPFIX_SS (GDT_ENTRY_ESPFIX_SS * 8)
|
#define __ESPFIX_SS (GDT_ENTRY_ESPFIX_SS * 8)
|
||||||
|
|
||||||
#define GDT_ENTRY_PDA (GDT_ENTRY_KERNEL_BASE + 15)
|
#define GDT_ENTRY_PERCPU (GDT_ENTRY_KERNEL_BASE + 15)
|
||||||
#define __KERNEL_PDA (GDT_ENTRY_PDA * 8)
|
#define __KERNEL_PERCPU (GDT_ENTRY_PERCPU * 8)
|
||||||
|
|
||||||
#define GDT_ENTRY_DOUBLEFAULT_TSS 31
|
#define GDT_ENTRY_DOUBLEFAULT_TSS 31
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/threads.h>
|
#include <linux/threads.h>
|
||||||
#include <linux/cpumask.h>
|
#include <linux/cpumask.h>
|
||||||
#include <asm/pda.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_X86_LOCAL_APIC) && !defined(__ASSEMBLY__)
|
#if defined(CONFIG_X86_LOCAL_APIC) && !defined(__ASSEMBLY__)
|
||||||
@ -112,7 +111,8 @@ do { } while (0)
|
|||||||
* from the initial startup. We map APIC_BASE very early in page_setup(),
|
* from the initial startup. We map APIC_BASE very early in page_setup(),
|
||||||
* so this is correct in the x86 case.
|
* so this is correct in the x86 case.
|
||||||
*/
|
*/
|
||||||
#define raw_smp_processor_id() (read_pda(cpu_number))
|
DECLARE_PER_CPU(int, cpu_number);
|
||||||
|
#define raw_smp_processor_id() (x86_read_percpu(cpu_number))
|
||||||
|
|
||||||
extern cpumask_t cpu_callout_map;
|
extern cpumask_t cpu_callout_map;
|
||||||
extern cpumask_t cpu_callin_map;
|
extern cpumask_t cpu_callin_map;
|
||||||
|
Loading…
Reference in New Issue
Block a user