Linux_arm_启动_c语言部分详解,[原创]Linux arm 启动 c语言部分详解第四讲

Linux arm启动c语言部分详解第四讲(from setup_per_cpu_areas();)

Written by leeming

上面的setup_arch花了我们大量的篇幅,现在我们要继续往前推进了。

注:黑色为主线,蓝色为函数的一级展开,红色是注意重要的地方。

//因为我们没有定义CONFIG_SMP,所以这两个函数都为空

setup_per_cpu_areas();

smp_prepare_boot_cpu();

/*

* Set up the scheduler prior starting any interrupts (such as the

* timer interrupt). Full topology setup happens at smp_init()

* time - but meanwhile we still have a functioning scheduler.

*/

//和进程初始化有关的函数,进程是任何操作系统的一个大点,因此这部分内容还是很多的,我这次主要是讲解c语言的启动,所以这部分暂时会比较浅的涉及,以后有机会也详细谈到

sched_init();

{

runqueue_t *rq;

int i, j, k;

for_each_cpu(i) {

prio_array_t *array;

//获取每个cpu的运行队列结构体runqurere_t

rq = cpu_rq(i);

spin_lock_init(&rq->lock);

rq->nr_running = 0;//该队列中可运行的进程数

//prio_array_t *active, *expired, arrays[2];

rq->active = rq->arrays;

rq->expired = rq->arrays + 1;

rq->best_expired_prio = MAX_PRIO;

/*此处删除了smp的内容*/

atomic_set(&rq->nr_iowait, 0);

//初始化active和expired队列位图,将优先队列中的0-(MAX_PRIO-1)清0

//将MAX_PRIO对应的置1

for (j = 0; j < 2; j++) {

array = rq->arrays + j;

for (k = 0; k < MAX_PRIO; k++) {

INIT_LIST_HEAD(array->queue + k);

__clear_bit(k, array->bitmap);

}

// delimiter for bitsearch

__set_bit(MAX_PRIO, array->bitmap);

}

}

/*

* The boot idle thread does lazy MMU switching as well:

*/

atomic_inc(&init_mm.mm_count);

//啥都没做

enter_lazy_tlb(&init_mm, current);

/*

* Make us the idle thread. Technically, schedule() should not be

* called from this thread, however somewhere below it might be,

* but because we are the idle thread, we just pick up running again

* when this runqueue becomes "idle".

*/

//初始化当前进程,也就是idle进程

init_idle(current, smp_processor_id());

}

/*

* Disable preemption - early bootup scheduling is extremely

* fragile until we cpu_idle() for the first time.

*/

//禁止抢占,原因如上

preempt_disable();

build_all_zonelists();

//处理器热插拔时的失控函数,类似变频时相应的驱动模块做出的反应,显然嵌入式中不可能用到

page_alloc_init();

//打印启动参数,也就是我们再setup_arch中获得的参数,这里只是打印,对参数的分析就在printk下面

printk(KERN_NOTICE "Kernel command line: %s\n", saved_command_line);

//再次分析参数,之前在setup_arch里面也做了一次,但那次只是得到我们的内存信息

parse_early_param();

parse_args("Booting kernel", command_line, __start___param,

__stop___param - __start___param,

&unknown_bootoption);

sort_main_extable();

//将中断向量表所在的区域(链接的时候的位置不可能是0xffff0000)的内容搬运至0xffff0000;将中断处理部分的代码搬运至0xffff0200处。

trap_init();

rcu_init();

init_IRQ();

{

struct irqdesc *desc;

int irq;

#ifdef CONFIG_SMP

bad_irq_desc.affinity = CPU_MASK_ALL;

bad_irq_desc.cpu = smp_processor_id();

#endif

//NR_IRQS在我们的4020中定义为32个中断,arm本身最多支持128个

for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) {

//将这些中断初始化为bad_irq_desc

*desc = bad_irq_desc;

INIT_LIST_HEAD(&desc->pend);

}

//init_arch_irq是一个全局的函数指针,它初始化的时候是一个空函数

//但是在setup_arch中把它指向了我们4020的函数,init_arch_irq = mdesc->init_irq;

//也就是在arch/arm/mach-sep4020/irq.c中的sep4020_init_irq,这里重新对我们所有的中断进行初始化

init_arch_irq();

}

pidhash_init();

init_timers();

{

//这个函数就是timers_nb这个结构体的call函数

timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE,

(void *)(long)smp_processor_id());

//这个是用的机制和cpufreq的机制是一样的,通过notifier_chain_register(&cpu_chain, nb)注册的;

//只不过这里的链是cpu_chain,而cpufreq是其他的链

register_cpu_notifier(&timers_nb);

//设置软中断行动函数描述结构变量softirq_vec[=1](系统定时器)的设置

//也就是设置timer定时器到期之后的处理函数

open_softirq(TIMER_SOFTIRQ, run_timer_softirq, NULL);

}

//其中函数hrtimers_init()和高精度时钟相关

hrtimers_init();

//和init_timers最后部分是softirq类似,只不过在那里是初始化=1的时候;

//在softirq_init中是初始化=6, =0的情况,对于整个软中断来说有以下几种情况

/*enum

{

HI_SOFTIRQ=0,

TIMER_SOFTIRQ,

NET_TX_SOFTIRQ,

NET_RX_SOFTIRQ,

BLOCK_SOFTIRQ,

TASKLET_SOFTIRQ

};*/

softirq_init();

//调用arch/arm/kernel/time.c中的time_init;它首先会检查system_timer这个全局结构体的偏移是否为空

//system_timer和我们之前在init_IRQ中提到的init_arch_irq类似,也是在setup_arch中赋值的

//system_timer = mdesc->timer;所以之前一直强调setup_arch是一个非常重要的函数,和我们处理器的移植紧密相关的

time_init();

至此,虽然start_kernel的函数只分析了一小部分,但是和平台和处理器相关的部分已经基本完毕,相信看完了这几讲,你会清楚的知道对于arch/arm/mach-sep4020中的那些文件为什么要那么写,是不是可以优化(肯定可以),知其然,知其所以然。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值