转自:http://blog.csdn.net/qianlong4526888/article/details/27695173
版权声明:本文为博主原创文章,未经博主允许不得转载。
说明:
该流程图按照代码执行时间顺序划分为4部分:
1. Bootloader在图片上半部,最先启动;
2. Kernel在图片下半部,由bootloader引导启动;
3.CPU0执行流程在图片左半部,bootloader代码会进行判断,先行启动CPU0;
4. Secondary CPUs在图片右半部,由CPU唤醒
具体启动流程如下:
1. 在bootloader启动时,会判断执行代码的是否为CPU0,如果不是,则执行wfe等待CPU0发出sev指令唤醒。如果是CPU0,则继续进行初始化工作。
mrs x4,mpidr_el1
tst x4,#15 //testwether the current cpu is CPU0, ie. mpidr_el1=15
b.eq 2f
/*
* Secondary CPUs
*/
1: wfe
ldr x4, mbox
cbz x4, 1b //if x4==0(ie. The value in address of mbox is 0) dead loop,or jump to x4
br x4 // branch to thegiven address
2:…… //UART initialisation (38400 8N1)
以上mbox的地址在Makefile中写定,是0x8000fff8,该地址处初始状态内容为全0。上面代码判断,若mbox地址处内容为0,则死循环;如果不为0则直接跳转到该地址所包含内容处执行。
2. 在dts中,对cpu-release-addr进行赋值,将其地址设为0x8000fff8。即只要往该地址写入相应的值,例如地址A,并且发送sev指令,就能将次级CPU唤醒,并跳转到A地址处执行。
cpu-release-addr = <0x0 0x8000fff8>;
3. 内核中smp_prepare_cpus 函数对0x8000fff8地址处内容进行了赋值,其值为函数secondary_holding_pen 的地址:
release_addr = __va(cpu_release_addr[cpu]);
release_addr[0] = (void*)__pa(secondary_holding_pen);//write function address to mbox
以上代码执行完后发送sev指令,唤醒其他次级CPU执行secondary_holding_pen函数:
/*
* Send an event to wake up the secondaries.
*/
sev();
4. secondary cpu 执行secondary_holding_pen()函数时都会去判断当前CPU的ID,并与secondary_holding_pen_release变量做比对,如果相等,则执行进一步初始化,否则执行WFE等待;
secondary_holding_pen_release变量的修改过程由CPU0调用smp_init()函数进行。该函数首先为相应CPU绑定一个idle线程,然后修改secondary_holding_pen_release的值(其值即CPU0欲唤醒的CPU的ID),最后发送sev指令,唤醒相应CPU执行idle线程。
secondary_holding_pen()函数代码如下:
/*
* This provides a"holding pen" for platforms to hold all secondary
* cores are helduntil we're ready for them to initialise.
*/
ENTRY(secondary_holding_pen)
bl el2_setup // Drop to EL1
mrs x0, mpidr_el1
and x0, x0, #15 // CPU number
adr x1, 1b
ldp x2, x3, [x1]
sub x1, x1, x2
add x3, x3, x1
pen: ldr x4, [x3]
cmp x4,x0
b.eq secondary_startup
wfe
b pen
ENDPROC(secondary_holding_pen)
附录:
内核中启动secondary cpus函数调用过程大致如下:
start_kernel èrest_initèkernel_inièkernel_init_freeable èsmp_init() kernel/smp.c line 649, 由CPU0激活剩余的处理器
cpu_upè_cpu_up()è__cpu_up ()èboot_secondary ()èwrite_pen_release该函数中有一句:secondary_holding_pen_release = val; 然后发送sev指令,激活剩余处理器。