lkml.org 
[lkml]   [2006]   [Sep]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH] i386-pda: Initialize the PDA early, before any C code runs.
    Initialize the PDA early, before any C code runs.

    This patch makes sure the PDA is usable in head.S, before any C code
    is run.

    On the boot CPU, this is done by using a temporary boot_pda which is
    initialized appropriately. It is replaced with a proper PDA when the
    proper GDT is installed.

    For secondary CPUs, the GDT and PDA are pre-allocated and initialized.
    head.S just needs to set %gs and load the GDT.

    In the process, this removes the need for early_smp_processor_id() and
    early_current().

    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: Andi Kleen <ak@suse.de>

    ---
    arch/i386/kernel/cpu/common.c | 123 ++++++++++++++++----------------
    arch/i386/kernel/head.S | 33 +++++++-
    arch/i386/kernel/smpboot.c | 41 +++++-----
    include/asm-i386/current.h | 7 -
    include/asm-i386/pda.h | 2
    include/asm-i386/processor.h | 4 -
    include/asm-i386/smp.h | 4 -

    ===================================================================
    --- a/arch/i386/kernel/cpu/common.c
    +++ b/arch/i386/kernel/cpu/common.c
    @@ -13,7 +13,6 @@
    #include <asm/mmu_context.h>
    #include <asm/mtrr.h>
    #include <asm/mce.h>
    -#include <asm/smp.h>
    #ifdef CONFIG_X86_LOCAL_APIC
    #include <asm/mpspec.h>
    #include <asm/apic.h>
    @@ -596,7 +595,7 @@ struct pt_regs * __devinit idle_regs(str
    return regs;
    }

    -__cpuinit int alloc_gdt(int cpu)
    +static __cpuinit int alloc_gdt(int cpu)
    {
    struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
    struct desc_struct *gdt;
    @@ -642,19 +641,12 @@ __cpuinit int alloc_gdt(int cpu)
    return 1;
    }

    -static __cpuinit void pda_init(int cpu, struct task_struct *curr)
    -{
    - struct i386_pda *pda = cpu_pda(cpu);
    -
    - memset(pda, 0, sizeof(*pda));
    -
    - pda->_pda = pda;
    -
    - pda->cpu_number = cpu;
    - pda->pcurrent = curr;
    -
    - printk("cpu %d current %p\n", cpu, curr);
    -}
    +/* Initial PDA used by boot CPU */
    +struct i386_pda boot_pda = {
    + ._pda = &boot_pda,
    + .cpu_number = 0,
    + .pcurrent = &init_task,
    +};

    static inline void set_kernel_gs(void)
    {
    @@ -664,11 +656,10 @@ static inline void set_kernel_gs(void)
    asm volatile ("mov %0, %%gs" : : "r" (__KERNEL_PDA) : "memory");
    }

    -/* Initialize the CPU's GDT and PDA */
    -static __cpuinit void init_gdt(void)
    -{
    - int cpu = early_smp_processor_id();
    - struct task_struct *curr = early_current();
    +/* Initialize the CPU's GDT and PDA. The boot CPU does this for
    + itself, but secondaries find this done for them. */
    +__cpuinit int init_gdt(int cpu, struct task_struct *idle)
    +{
    struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
    __u32 stk16_off = (__u32)&per_cpu(cpu_16bit_stack, cpu);
    struct desc_struct *gdt;
    @@ -678,8 +669,7 @@ static __cpuinit void init_gdt(void)
    allocated. */
    if (!alloc_gdt(cpu)) {
    printk(KERN_CRIT "CPU%d failed to allocate GDT or PDA\n", cpu);
    - for (;;)
    - local_irq_enable();
    + return 0;
    }

    gdt = (struct desc_struct *)cpu_gdt_descr->address;
    @@ -705,52 +695,32 @@ static __cpuinit void init_gdt(void)
    (unsigned long)pda, sizeof(*pda) - 1,
    0x80 | DESCTYPE_S | 0x2, 0); /* present read-write data segment */

    +
    + memset(pda, 0, sizeof(*pda));
    + pda->_pda = pda;
    + pda->cpu_number = cpu;
    + pda->pcurrent = idle;
    +
    + return 1;
    +}
    +
    +/* Common CPU init for both boot and secondary CPUs */
    +static void __cpuinit _cpu_init(int cpu, struct task_struct *curr)
    +{
    + struct tss_struct * t = &per_cpu(init_tss, cpu);
    + struct thread_struct *thread = &curr->thread;
    + struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
    +
    + /* Reinit these anyway, even if they've already been done (on
    + the boot CPU, this will transition from the boot gdt+pda to
    + the real ones). */
    load_gdt(cpu_gdt_descr);
    set_kernel_gs();
    -
    - /* Do this once everything GDT-related has been set up. */
    - pda_init(cpu, curr);
    -}
    -
    -/* Set up a very early PDA for the boot CPU so that smp_processor_id()
    - and current will work. */
    -void __init smp_setup_processor_id(void)
    -{
    - static __initdata struct i386_pda boot_pda;
    -
    - pack_descriptor((u32 *)&cpu_gdt_table[GDT_ENTRY_PDA].a,
    - (u32 *)&cpu_gdt_table[GDT_ENTRY_PDA].b,
    - (unsigned long)&boot_pda, sizeof(struct i386_pda) - 1,
    - 0x80 | DESCTYPE_S | 0x2, 0); /* present read-write data segment */
    -
    - boot_pda.pcurrent = early_current();
    -
    - /* Set %gs for this CPU's PDA */
    - set_kernel_gs();
    -}
    -
    -/*
    - * cpu_init() initializes state that is per-CPU. Some data is already
    - * initialized (naturally) in the bootstrap process, such as the GDT
    - * and IDT. We reload them nevertheless, this function acts as a
    - * 'CPU state barrier', nothing should get across.
    - */
    -void __cpuinit cpu_init(void)
    -{
    - int cpu = early_smp_processor_id();
    - struct task_struct *curr = early_current();
    -
    - struct tss_struct * t = &per_cpu(init_tss, cpu);
    - struct thread_struct *thread = &curr->thread;

    if (cpu_test_and_set(cpu, cpu_initialized)) {
    printk(KERN_WARNING "CPU#%d already initialized!\n", cpu);
    for (;;) local_irq_enable();
    }
    -
    - /* Init the GDT and PDA early, before calling printk(),
    - since it may end up using the PDA indirectly. */
    - init_gdt();

    printk(KERN_INFO "Initializing CPU#%d\n", cpu);

    @@ -803,6 +773,37 @@ void __cpuinit cpu_init(void)
    mxcsr_feature_mask_init();
    }

    +/* Entrypoint to initialize secondary CPU */
    +void __cpuinit secondary_cpu_init(void)
    +{
    + int cpu = smp_processor_id();
    + struct task_struct *curr = current;
    +
    + _cpu_init(cpu, curr);
    +}
    +
    +/*
    + * cpu_init() initializes state that is per-CPU. Some data is already
    + * initialized (naturally) in the bootstrap process, such as the GDT
    + * and IDT. We reload them nevertheless, this function acts as a
    + * 'CPU state barrier', nothing should get across.
    + */
    +void __cpuinit cpu_init(void)
    +{
    + int cpu = smp_processor_id();
    + struct task_struct *curr = current;
    +
    + /* Set up the real GDT and PDA, so we can transition from the
    + boot versions. */
    + if (!init_gdt(cpu, curr)) {
    + /* failed to allocate something; not much we can do... */
    + for (;;)
    + local_irq_enable();
    + }
    +
    + _cpu_init(cpu, curr);
    +}
    +
    #ifdef CONFIG_HOTPLUG_CPU
    void __cpuinit cpu_uninit(void)
    {
    ===================================================================
    --- a/arch/i386/kernel/head.S
    +++ b/arch/i386/kernel/head.S
    @@ -302,6 +302,7 @@ 2: movl %cr0,%eax
    movl %eax,%cr0

    call check_x87
    + call setup_pda
    lgdt cpu_gdt_descr
    lidt idt_descr
    ljmp $(__KERNEL_CS),$1f
    @@ -312,10 +313,13 @@ 1: movl $(__KERNEL_DS),%eax # reload all
    movl %eax,%ds
    movl %eax,%es

    - xorl %eax,%eax # Clear FS/GS and LDT
    + xorl %eax,%eax # Clear FS and LDT
    movl %eax,%fs
    - movl %eax,%gs
    lldt %ax
    +
    + movl $(__KERNEL_PDA),%eax
    + mov %eax,%gs
    +
    cld # gcc2 wants the direction flag cleared at all times
    pushl %eax # fake return address
    #ifdef CONFIG_SMP
    @@ -345,6 +349,23 @@ 1: movb $1,X86_HARD_MATH
    .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */
    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.
    + */
    +setup_pda:
    + /* get the PDA pointer */
    + movl start_pda, %eax
    +
    + /* slot the PDA address into the GDT */
    + mov cpu_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
    *
    @@ -484,7 +505,9 @@ ENTRY(empty_zero_page)
    * This starts the data section.
    */
    .data
    -
    +ENTRY(start_pda)
    + .long boot_pda
    +
    ENTRY(stack_start)
    .long init_thread_union+THREAD_SIZE
    .long __BOOT_DS
    @@ -525,7 +548,7 @@ idt_descr:

    # boot GDT descriptor (later on used by CPU#0):
    .word 0 # 32 bit align gdt_desc.address
    -cpu_gdt_descr:
    +ENTRY(cpu_gdt_descr)
    .word GDT_ENTRIES*8-1
    .long cpu_gdt_table

    @@ -585,7 +608,7 @@ ENTRY(cpu_gdt_table)
    .quad 0x004092000000ffff /* 0xc8 APM DS data */

    .quad 0x0000920000000000 /* 0xd0 - ESPFIX 16-bit SS */
    - .quad 0x0000000000000000 /* 0xd8 - PDA */
    + .quad 0x00cf92000000ffff /* 0xd8 - PDA */
    .quad 0x0000000000000000 /* 0xe0 - unused */
    .quad 0x0000000000000000 /* 0xe8 - unused */
    .quad 0x0000000000000000 /* 0xf0 - unused */
    ===================================================================
    --- a/arch/i386/kernel/smpboot.c
    +++ b/arch/i386/kernel/smpboot.c
    @@ -536,11 +536,11 @@ static void __devinit start_secondary(vo
    static void __devinit start_secondary(void *unused)
    {
    /*
    - * Don't put *anything* before cpu_init(), SMP
    + * Don't put *anything* before secondary_cpu_init(), SMP
    * booting is too fragile that we want to limit the
    * things done here to the most necessary things.
    */
    - cpu_init();
    + secondary_cpu_init();
    preempt_disable();
    smp_callin();
    while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
    @@ -590,8 +590,6 @@ static void __devinit start_secondary(vo
    */
    void __devinit initialize_secondary(void)
    {
    - struct task_struct *curr = early_current();
    -
    /*
    * We don't actually need to load the full TSS,
    * basically just the stack pointer and the eip.
    @@ -601,13 +599,16 @@ void __devinit initialize_secondary(void
    "movl %0,%%esp\n\t"
    "jmp *%1"
    :
    - :"r" (curr->thread.esp),"r" (curr->thread.eip));
    -}
    -
    + :"m" (current->thread.esp),"m" (current->thread.eip));
    +}
    +
    +/* Static state in head.S used to set up a CPU */
    extern struct {
    void * esp;
    unsigned short ss;
    } stack_start;
    +extern struct i386_pda *start_pda;
    +extern struct Xgt_desc_struct cpu_gdt_descr;

    #ifdef CONFIG_NUMA

    @@ -934,17 +935,6 @@ static int __devinit do_boot_cpu(int api
    unsigned long start_eip;
    unsigned short nmi_high = 0, nmi_low = 0;

    - /* Pre-allocate the CPU's GDT and PDA so it doesn't have to do
    - any memory allocation during the delicate CPU-bringup
    - phase. */
    - if (!alloc_gdt(cpu)) {
    - printk(KERN_INFO "Couldn't allocate GDT/PDA for CPU %d\n", cpu);
    - return -1; /* ? */
    - }
    -
    - ++cpucount;
    - alternatives_smp_switch(1);
    -
    /*
    * We can't use kernel_thread since we must avoid to
    * reschedule the child.
    @@ -952,14 +942,29 @@ static int __devinit do_boot_cpu(int api
    idle = alloc_idle_task(cpu);
    if (IS_ERR(idle))
    panic("failed fork for CPU %d", cpu);
    +
    + /* Pre-allocate and initialize the CPU's GDT and PDA so it
    + doesn't have to do any memory allocation during the
    + delicate CPU-bringup phase. */
    + if (!init_gdt(cpu, idle)) {
    + printk(KERN_INFO "Couldn't allocate GDT/PDA for CPU %d\n", cpu);
    + return -1; /* ? */
    + }
    +
    idle->thread.eip = (unsigned long) start_secondary;
    /* start_eip had better be page-aligned! */
    start_eip = setup_trampoline();
    +
    + ++cpucount;
    + alternatives_smp_switch(1);

    /* So we see what's up */
    printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip);
    /* Stack for startup_32 can be just as for start_secondary onwards */
    stack_start.esp = (void *) idle->thread.esp;
    +
    + start_pda = cpu_pda(cpu);
    + cpu_gdt_descr = per_cpu(cpu_gdt_descr, cpu);

    irq_ctx_init(cpu);

    ===================================================================
    --- a/include/asm-i386/current.h
    +++ b/include/asm-i386/current.h
    @@ -1,15 +1,10 @@
    #ifndef _I386_CURRENT_H
    #define _I386_CURRENT_H

    -#include <linux/thread_info.h>
    #include <asm/pda.h>
    +#include <linux/compiler.h>

    struct task_struct;
    -
    -static __always_inline struct task_struct *early_current(void)
    -{
    - return current_thread_info()->task;
    -}

    static __always_inline struct task_struct *get_current(void)
    {
    ===================================================================
    --- a/include/asm-i386/pda.h
    +++ b/include/asm-i386/pda.h
    @@ -1,5 +1,7 @@
    #ifndef _I386_PDA_H
    #define _I386_PDA_H
    +
    +#include <linux/stddef.h>

    struct i386_pda
    {
    ===================================================================
    --- a/include/asm-i386/processor.h
    +++ b/include/asm-i386/processor.h
    @@ -728,6 +728,8 @@ extern unsigned long boot_option_idle_ov
    extern unsigned long boot_option_idle_override;
    extern void enable_sep_cpu(void);
    extern int sysenter_setup(void);
    -extern int alloc_gdt(int cpu);
    +
    +extern int init_gdt(int cpu, struct task_struct *idle);
    +extern void secondary_cpu_init(void);

    #endif /* __ASM_I386_PROCESSOR_H */
    ===================================================================
    --- a/include/asm-i386/smp.h
    +++ b/include/asm-i386/smp.h
    @@ -60,9 +60,6 @@ extern void cpu_uninit(void);
    * so this is correct in the x86 case.
    */
    #define raw_smp_processor_id() (read_pda(cpu_number))
    -/* This is valid from the very earliest point in boot that we care
    - about. */
    -#define early_smp_processor_id() (current_thread_info()->cpu)

    extern cpumask_t cpu_callout_map;
    extern cpumask_t cpu_callin_map;
    @@ -99,7 +96,6 @@ extern unsigned int num_processors;

    #define safe_smp_processor_id() 0
    #define cpu_physical_id(cpu) boot_cpu_physical_apicid
    -#define early_smp_processor_id() 0

    #define NO_PROC_ID 0xFF /* No processor magic marker */


    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2006-09-12 00:55    [W:0.042 / U:120.140 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site