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。