Chinaunix首页 | 论坛 | 博客
  • 博客访问: 515335
  • 博文数量: 95
  • 博客积分: 5168
  • 博客等级: 大校
  • 技术积分: 1271
  • 用 户 组: 普通用户
  • 注册时间: 2008-12-28 23:31
文章分类

全部博文(95)

文章存档

2013年(2)

2012年(3)

2011年(1)

2010年(8)

2009年(81)

分类: LINUX

2010-01-08 21:07:14

-------------------------------------------
本文系本站原创,欢迎转载!
转载请注明出处:
http://sjj0412.cublog.cn
-------------------------------------------

asmlinkage void __init start_kernel(void)

{

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

    rest_init();

}

static void noinline __init_refok rest_init(void)

    __releases(kernel_lock)

{

    int pid;

 

    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 the grim

     * reaper of innocent orphaned children.

     *

     * We don't want people to have to make incorrect

     * assumptions about where in the task array this

     * 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      loadercoreb_trampoline_start)拷贝到L1(这个为sdram)

 

    do_pre_smp_initcalls();

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

    smp_init();

//这个会开启coreb

    sched_init_smp();

 

    cpuset_init_smp();

…..........

void __init smp_prepare_cpus(unsigned int max_cpus)

{

    platform_prepare_cpus(max_cpus);

    platform_request_ipi(&ipi_handler);

}

#define COREB_SRAM_BASE  0xff600000

void __init platform_prepare_cpus(unsigned int max_cpus)

{

    int len;

 

    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 void setup_per_cpu_areas(void) { }

static inline void smp_prepare_cpus(unsigned int maxcpus) { }

 

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

/* Called by boot processor to activate the rest. */

static void __init smp_init(void)

{

    unsigned int 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)

{

    int err = 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);

    return err;

}

 

static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)

{

    int ret, nr_calls = 0;

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

    unsigned long 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;

       goto out_notify;

    }

 

    /* Arch-specific enabling code. */

    mutex_lock(&cpu_bitmask_lock);

    ret = __cpu_up(cpu);

    mutex_unlock(&cpu_bitmask_lock);

    if (ret != 0)

       goto out_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);

 

    return ret;

}

 

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

int __cpuinit __cpu_up(unsigned int cpu)

{

    struct task_struct *idle;

    int ret;

 

    idle = fork_idle(cpu);

//为次cpu创建idle进程。

    if (IS_ERR(idle)) {

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

       return PTR_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;

 

    return ret;

}

 

int __cpuinit platform_boot_secondary(unsigned int cpu, struct task_struct *idle)

{

    unsigned long 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);

 

    return cpu_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;

 

    /*Clear Out 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

    CLI R2;

    SSYNC;

#endif

    [p0] = R0;

    SSYNC;

#ifdef ANOMALY_05000125

    STI R2;

#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

    CLI R2;

    SSYNC;

#endif

    [p0] = R0;

    SSYNC;

#ifdef ANOMALY_05000125

    STI R2;

#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;

 

    raise 15;

    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)

{

    unsigned int cpu = smp_processor_id();

    struct mm_struct *mm = &init_mm;

 

    /*

     * We want the D-cache to be enabled early, in case 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);

//配置corebcache为高速缓存。

 

    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(unsigned int cpu)

{

    struct irq_desc *timer_desc;

    unsigned long 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(unsigned int 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

阅读(1550) | 评论(0) | 转发(0) |
0

上一篇:一年了啊

下一篇:好久没写博文了

给主人留下些什么吧!~~