smp启动分析

asmlinkage void __init start_kernel(void)

{

    …................

    rest_init();

}

static void noinline __init_refokrest_init(void)

    __releases(kernel_lock)

{

    intpid;

 

    kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);

    numa_default_policy();

    pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);

    kthreadd_task= find_task_by_pid(pid);

    unlock_kernel();

 

    /*

     * The boot idle thread must execute schedule()

     * at least one to get things moving:

     */

    preempt_enable_no_resched();

    schedule();

    preempt_disable();

 

    /*Call into cpu_idle with preempt disabled */

    cpu_idle();

}

 

static int __init kernel_init(void *unused)

{

    lock_kernel();

    /*

     * init can run on any cpu.

     */

    set_cpus_allowed(current,CPU_MASK_ALL);

    /*

     * Tell the world that we're going to be thegrim

     * reaper of innocent orphaned children.

     *

     * We don't want people to have to makeincorrect

     * assumptions about where in the task arraythis

     * can be found.

     */

    init_pid_ns.child_reaper= current;

 

    __set_special_pids(1,1);

    cad_pid= task_pid(current);

 

    smp_prepare_cpus(max_cpus);

//这个做准备,比如在bf561里,是map设置为0,1,同时把coreb      loader(coreb_trampoline_start)拷贝到L1(这个为sdram)

 

    do_pre_smp_initcalls();

//这个没有多大用,在bf中

    smp_init();

//这个会开启coreb

    sched_init_smp();

 

    cpuset_init_smp();

…..........

void __init smp_prepare_cpus(unsigned intmax_cpus)

{

    platform_prepare_cpus(max_cpus);

    platform_request_ipi(&ipi_handler);

}

#defineCOREB_SRAM_BASE  0xff600000

void __init platform_prepare_cpus(unsignedint max_cpus)

{

    intlen;

 

    len = &coreb_trampoline_end - &coreb_trampoline_start+ 1;

 

    if(len > COREB_SRAM_SIZE) {

       /*Paranoid. */

       printk(KERN_ERR"Bootstrap code size (%d) > CoreB SRAM (%d).\n",

              len, COREB_SRAM_SIZE);

       return;

    }

 

    dma_memcpy((void *)COREB_SRAM_BASE,&coreb_trampoline_start, len);

     //COREB_SRAM_BASE就是coreb 高速L1的地址。

    /*Both cores ought to be present on a bf561! */

    cpu_set(0, cpu_present_map); /* CoreA */

    cpu_set(1, cpu_present_map); /* CoreB */

 

    printk(KERN_INFO"CoreB bootstrap code to SRAM %p via DMA.\n", (void*)COREB_SRAM_BASE);

}

 

#ifndef CONFIG_SMP

 

#ifdef CONFIG_X86_LOCAL_APIC

static void __init smp_init(void)

{

    APIC_init_uniprocessor();

}

#else

#define smp_init()   do { } while (0)

#endif

 

static inline voidsetup_per_cpu_areas(void) { }

static inline voidsmp_prepare_cpus(unsigned int maxcpus) { }

 

#else //由于定义了smp,所以是这个

/* Called by boot processor to activate therest. */

static void __init smp_init(void)

{

    unsignedint cpu;

 

    /*FIXME: This should be done in userspace --RR */

    for_each_present_cpu(cpu) {

       if(num_online_cpus() >= max_cpus)

           break;

       if(!cpu_online(cpu))

           cpu_up(cpu);

//这个会cpu_up(1),因为0 cpu已经启动了阿。

    }

 

    /*Any cleanup work */

    printk(KERN_INFO"Brought up %ld CPUs\n", (long)num_online_cpus());

    smp_cpus_done(max_cpus);

}

 

#endif

 

上面应该会执行cpu_up(0),cpu_up(1);

int __cpuinit cpu_up(unsigned int cpu)

{

    interr = 0;

 

    mutex_lock(&cpu_add_remove_lock);

    if(cpu_hotplug_disabled)

       err= -EBUSY;

    else

       err = _cpu_up(cpu, 0);

 

    mutex_unlock(&cpu_add_remove_lock);

    returnerr;

}

 

static int __cpuinit _cpu_up(unsigned intcpu, int tasks_frozen)

{

    intret, nr_calls = 0;

    void*hcpu = (void *)(long)cpu;

    unsignedlong mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;

 

    if(cpu_online(cpu) || !cpu_present(cpu))

       return-EINVAL;

 

    raw_notifier_call_chain(&cpu_chain,CPU_LOCK_ACQUIRE, hcpu);

    ret= __raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE | mod, hcpu,

                         -1,&nr_calls);

    if(ret == NOTIFY_BAD) {

       printk("%s:attempt to bring up CPU %u failed\n",

              __FUNCTION__,cpu);

       ret= -EINVAL;

       gotoout_notify;

    }

 

    /*Arch-specific enabling code. */

    mutex_lock(&cpu_bitmask_lock);

    ret = __cpu_up(cpu);

    mutex_unlock(&cpu_bitmask_lock);

    if(ret != 0)

       gotoout_notify;

    BUG_ON(!cpu_online(cpu));

 

    /*Now call notifier in preparation. */

    raw_notifier_call_chain(&cpu_chain,CPU_ONLINE | mod, hcpu);

 

out_notify:

    if(ret != 0)

       __raw_notifier_call_chain(&cpu_chain,

              CPU_UP_CANCELED| mod, hcpu, nr_calls, NULL);

    raw_notifier_call_chain(&cpu_chain,CPU_LOCK_RELEASE, hcpu);

 

    returnret;

}

 

//下面这个函数是跟arch有关的,对于blackfin是:

int __cpuinit __cpu_up(unsigned int cpu)

{

    structtask_struct *idle;

    intret;

 

    idle = fork_idle(cpu);

//为次cpu创建idle进程。

    if(IS_ERR(idle)) {

       printk(KERN_ERR"CPU%u: fork() failed\n", cpu);

       returnPTR_ERR(idle);

    }

 

    secondary_stack= task_stack_page(idle) + THREAD_SIZE;

    smp_wmb();

 

    ret = platform_boot_secondary(cpu, idle);

 

    if(ret) {

       cpu_clear(cpu,cpu_present_map);

       printk(KERN_CRIT"CPU%u: processor failed to boot (%d)\n", cpu, ret);

       free_task(idle);

    }else

       cpu_set(cpu,cpu_online_map);

 

    secondary_stack= NULL;

 

    returnret;

}

 

int __cpuinitplatform_boot_secondary(unsigned int cpu, struct task_struct *idle)

{

    unsignedlong timeout;

 

    if ((bfin_read_SICA_SYSCR() & COREB_SRAM_INIT) == 0)

       return -EBUSY;    /*CoreB already running?! */

 

    printk(KERN_INFO"Booting Core B.\n");

 

    spin_lock(&boot_lock);

 

    /*Kick CoreB, which should start execution from CORE_SRAM_BASE. */

    SSYNC();

    bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() &~COREB_SRAM_INIT);

    //开启coreb

    SSYNC();

 

    timeout= jiffies + 1 * HZ;

    while(time_before(jiffies, timeout)) {

       if(cpu_isset(cpu, cpu_callin_map))

           break;

       udelay(100);

       barrier();

       if(jiffies > (timeout+500))  {

           printk(KERN_INFO".");

           timeout= jiffies;

       }

    }

 

    spin_unlock(&boot_lock);

 

    returncpu_isset(cpu, cpu_callin_map) ? 0 : -ENOSYS;

}

 

对于B核:

当coreB启动时就会执行:_coreb_trampoline_start(这个开始在片外ram,被corea复制了一份到coreb L1)

ENTRY(_coreb_trampoline_start)

    /*Set the SYSCFG register */

    R0= 0x36;

    SYSCFG= R0; /*Enable Cycle Counter and Nesting Of Interrupts(3rd Bit)*/

    R0= 0;

 

    /*ClearOut All the data and pointer  Registers*/

    R1= R0;

    R2= R0;

    R3= R0;

    R4= R0;

    R5= R0;

    R6= R0;

    R7= R0;

 

    P0= R0;

    P1= R0;

    P2= R0;

    P3= R0;

    P4= R0;

    P5= R0;

 

    LC0= r0;

    LC1= r0;

    L0= r0;

    L1= r0;

    L2= r0;

    L3= r0;

 

    /*Clear Out All the DAG Registers*/

    B0= r0;

    B1= r0;

    B2= r0;

    B3= r0;

 

    I0= r0;

    I1= r0;

    I2= r0;

    I3= r0;

 

    M0= r0;

    M1= r0;

    M2= r0;

    M3= r0;

 

    /*Turn off the icache */

    p0.l= (IMEM_CONTROL & 0xFFFF);

    p0.h= (IMEM_CONTROL >> 16);

    R1= [p0];

    R0= ~ENICPLB;

    R0= R0 & R1;

 

    /*Anomaly 05000125 */

#ifdef ANOMALY_05000125

    CLIR2;

    SSYNC;

#endif

    [p0]= R0;

    SSYNC;

#ifdef ANOMALY_05000125

    STIR2;

#endif

 

    /*Turn off the dcache */

    p0.l= (DMEM_CONTROL & 0xFFFF);

    p0.h= (DMEM_CONTROL >> 16);

    R1= [p0];

    R0= ~ENDCPLB;

    R0= R0 & R1;

 

    /*Anomaly 05000125 */

#ifdef ANOMALY_05000125

    CLIR2;

    SSYNC;

#endif

    [p0]= R0;

    SSYNC;

#ifdef ANOMALY_05000125

    STIR2;

#endif

 

    /*Initialize stack pointer */

    sp.l= lo(INITIAL_STACK);

    sp.h= hi(INITIAL_STACK);

    fp= sp;

    usp= sp;

 

    /*This section keeps the processor in supervisor mode

     * during core B startup.  Branches to the idle task.

     */

 

    /*EVT15 = _real_start */

 

    p0.l= lo(EVT15);

    p0.h= hi(EVT15);

    p1.l = _coreb_start;

    p1.h = _coreb_start;

//这个使得coreb回跳到:coreb_start(在片外ram)

    [p0]= p1;

    csync;

 

    p0.l= lo(IMASK);

    p0.h= hi(IMASK);

    p1.l= IMASK_IVG15;

    p1.h= 0x0;

    [p0]= p1;

    csync;

 

    raise15;

    p0.l= .LWAIT_HERE;

    p0.h= .LWAIT_HERE;

    reti= p0;

#if defined(ANOMALY_05000281)

    nop;nop; nop;

#endif

    rti;//模拟一个调用返回,然后就跳到_coreb_start,因为_coreb_start的值是链接的时候决定的,肯定是0x20000000以下地址,这个是片外SDRAM的地址,就相当于跳到corea的指令空间了,也就共享代码了,这就达到了smp效果了。

 

.LWAIT_HERE:

    jump.LWAIT_HERE;

 

.align 4

ENTRY(_coreb_trampoline_end)

 

这个在片外ram

ENTRY(_coreb_start)

    [--sp]= reti;

 

    p0.l= lo(WDOGB_CTL);

    p0.h= hi(WDOGB_CTL);

    r0= 0xAD6(z);

    w[p0]= r0;   /* Clear the watchdog. */

    ssync;

 

    /*

     * switch to IDLE stack.

     */

    p0.l= _secondary_stack;

    p0.h= _secondary_stack;

    sp= [p0];

    usp= sp;

    fp= sp;

    sp+= -12;

    call_init_pda

    sp+= 12;

    call _secondary_start_kernel;

.L_exit:

    jump.s .L_exit;

 

 

void __cpuinit secondary_start_kernel(void)

{

    unsignedint cpu = smp_processor_id();

    structmm_struct *mm = &init_mm;

 

    /*

     * We want the D-cache to be enabled early, incase the atomic

     * support code emulates cache coherence (see

     * __ARCH_SYNC_CORE_DCACHE).

     */

    init_exception_vectors();

//设置向量空间,肯定是片外ram的地址范围的,且和corea的应该相同,因为corea也是调用这个函数设置向量空间的,corea是在setup_arch中调用的。

    bfin_setup_caches(cpu);

//配置coreb的cache为高速缓存。

 

    local_irq_disable();

 

    /*Attach the new idle task to the global mm. */

    atomic_inc(&mm->mm_users);

    atomic_inc(&mm->mm_count);

    current->active_mm= mm;

    BUG_ON(current->mm); /* Can't be, but better be safe than sorry. */

 

    preempt_disable();

 

    setup_secondary(cpu);

//主要是中断设置相关的东西,比如tick中断

    local_irq_enable();

 

    platform_secondary_init(cpu);

 

    cpu_idle();//进入idle进程

}

 

static void __init setup_secondary(unsignedint cpu)

{

    structirq_desc *timer_desc;

    unsignedlong ilat;

 

    bfin_write_IMASK(0);

    CSYNC();

    ilat= bfin_read_ILAT();

    CSYNC();

    bfin_write_ILAT(ilat);

    CSYNC();

 

    /*Reserve the PDA space for the secondary CPU. */

    reserve_pda();

 

    /*Enable interrupt levels IVG7-15. IARs have been already

     * programmed by the boot CPU.  */

    irq_flags = irq_flags | IMASK_IVG15 |

        IMASK_IVG14 |IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |

        IMASK_IVG10 |IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;

 

#ifdef CONFIG_TICK_SOURCE_SYSTMR0

    /*Power down the core timer, just to play safe. */

    bfin_write_TCNTL(0);

 

    /*system timer0 has been setup by CoreA. */

#else

    timer_desc= irq_desc + IRQ_CORETMR;

    setup_core_timer();

    timer_desc->chip->enable(IRQ_CORETMR);

//开启时钟中断了,就可以调度了阿

#endif

}

 

void __init platform_secondary_init(unsignedint cpu)

{

    local_irq_disable();

 

    /*Clone setup for peripheral interrupt sources from CoreA. */

    bfin_write_SICB_IMASK0(bfin_read_SICA_IMASK0());

    bfin_write_SICB_IMASK1(bfin_read_SICA_IMASK1());

    SSYNC();

 

    /*Clone setup for IARs from CoreA. */

    bfin_write_SICB_IAR0(bfin_read_SICA_IAR0());

    bfin_write_SICB_IAR1(bfin_read_SICA_IAR1());

    bfin_write_SICB_IAR2(bfin_read_SICA_IAR2());

    bfin_write_SICB_IAR3(bfin_read_SICA_IAR3());

    bfin_write_SICB_IAR4(bfin_read_SICA_IAR4());

    bfin_write_SICB_IAR5(bfin_read_SICA_IAR5());

    bfin_write_SICB_IAR6(bfin_read_SICA_IAR6());

    bfin_write_SICB_IAR7(bfin_read_SICA_IAR7());

    SSYNC();

 

    local_irq_enable();

 

    /*Calibrate loops per jiffy value. */

    calibrate_delay();

 

    /*Store CPU-private information to the cpu_data array. */

    bfin_setup_cpudata(cpu);

 

    /*We are done with local CPU inits, unblock the boot CPU. */

//叫醒corea,这时开始两个核都开始工作了。

    cpu_set(cpu, cpu_callin_map);

    spin_lock(&boot_lock);

    spin_unlock(&boot_lock);

}

 

 

为啥需要拷贝过程,即corea将_coreb_trampoline_start拷贝到coreb呢?是因为coreb启动时有一个固定的pc值(bf561中是L1 Icache的地址),所以必须将coreb开始要执行的代码放到这个地址,然后为了达到smp的效果,必须返回去,这个就是coreb_start函数->secondary_start_kernel->idle。



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值