分类: 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 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 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);
//配置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(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。