1.3 parse_options()
分析由内核引导程序发送给内核的启动选项,在初始化过程中按照某些选项运行,并将剩余部分传送给init进程。
这些选项可能已经存储在配置文件中,也可能是由用户在系统启动时敲入的。但内核并不关心这些,这些细节都是内核引导程序关注的内容,嵌入式系统更是如此。
1.4 trap_init() (/kernel/traps.c do_trap)
这个函数用来做体系相关的中断处理的初始化,在该函数中调用__trap_init((void *)vectors_base())
函数将exception vector设置到vectors_base开始的地址上。 __trap_init函数位于entry-armv.S文件中,对于ARM处理器,共有复位、未定义指令、SWI、预取终止、数据终止、IRQ和FIQ 几种方式。
SWI主要用来实现系统调用,而产生了IRQ之后,通过exception vector进入中断处理过程,执行do_IRQ函数。
armnommu的trap_init()函数在arch/armnommu/kernel/traps.c文件中。
vectors_base是写中断向量的开始地址,在include/asm-armnommu/proc-armv/system.h文件中设置,地址为0或0XFFFF0000。
ENTRY(__trap_init)
stmfd sp!, {r4 -r6, lr}
mrs r1, cpsr @ codefrom 2.0.38bic r1, r1, #MODE_MASK @ clear mode bits/*设置svc模式,disable IRQ,FIQ*/orr r1, r1, #I_BIT|F_BIT|MODE_SVC @ setSVC mode, disable IRQ,FIQ
msr cpsr, r1
adr r1, .LCvectors @setup the vectors
ldmia r1, {r1, r2, r3, r4, r5, r6, ip, lr}
stmia r0, {r1, r2, r3, r4, r5, r6, ip, lr}/*拷贝异常向量*/add r2, r0, #0x200adr r0, __stubs_start @ copy stubs to0x200adr r1, __stubs_end1: ldr r3, [r0], #4str r3, [r2], #4cmp r0, r1
blt 1b
LOADREGS(fd, sp!, {r4 - r6, pc})
View Code
__stubs_start到__stubs_end的地址中包含了异常处理的代码,因此拷贝到vectors_base+0x200的位置上。
1.5 init_IRQ()
1 void __init init_IRQ(void)2 {3 extern void init_dma(void);4 intirq;5
6 for (irq = 0; irq < NR_IRQS; irq++) {7 irq_desc[irq].probe_ok = 0;8 irq_desc[irq].valid = 0;9 irq_desc[irq].noautoenable = 0;10 irq_desc[irq].mask_ack =dummy_mask_unmask_irq;11 irq_desc[irq].mask =dummy_mask_unmask_irq;12 irq_desc[irq].unmask =dummy_mask_unmask_irq;13 }14 CSR_WRITE(AIC_MDCR, 0x7FFFE); /*disable all interrupts*/
15 CSR_WRITE(CAHCNF,0x0);/*Close Cache*/
16 CSR_WRITE(CAHCON,0x87);/*Flush Cache*/
17 while(CSR_READ(CAHCON)!=0);18 CSR_WRITE(CAHCNF,0x7);/*Open Cache*/
19
20 init_arch_irq();21 init_dma();22 }
这个函数用来做体系相关的irq处理的初始化.
irq_desc数组是用来描述IRQ的请求队列,每一个中断号分配一个irq_desc结构,组成了一个数组。
NR_IRQS代表中断数目,这里只是对中断结构irq_desc进行了初始化。
在默认的初始化完成后调用初始化函数init_arch_irq,先执行arch/armnommu/kernel/irq-arch.c文件中的函数genarch_init_irq(),然后就执行 include/asm-armnommu/arch-xxxx/irq.h中的inline函数irq_init_irq,在这里对irq_desc进行了实质的初始化。
其中mask用阻塞中断;unmask用来取消阻塞;mask_ack的作用是阻塞中断,同时还回应ack给硬件表示这个中断已经被处理了,否则硬件将再次发生同一个中断。这里,不是所有硬件需要这个ack回应,所以很多时候mask_ack与mask用的是同一个函数。
接下来执行init_dma()函数,如果不支持DMA,可以设置include/asm-armnommu/arch-xxxx/dma.h中的 MAX_DMA_CHANNELS为0,这样在arch/armnommu/kernel/dma.c文件中会根据这个定义使用不同的函数。
1.6 sched_init()
初始化系统调度进程,主要对定时器机制和时钟中断的Bottom Half的初始化函数进行设置。
与时间相关的初始化过程主要有两步:
(1)调用 init_timervecs()函数初始化内核定时器机制;
(2)调用init_bh()函数将BH向量TIMER_BH、TQUEUE_BH和 IMMEDIATE_BH所对应的BH函数分别设置成timer_bh()、tqueue_bh()和immediate_bh()函数
1.7 softirq_init()
内核的软中断机制初始化函数。
调用tasklet_init初始化tasklet_struct结构,软中断的个数为32个。用于bh的 tasklet_struct结构调用tasklet_init()以后,它们的函数指针func全都指向bh_action()。
bh_action就是tasklet实现bh机制的代码,但此时具体的bh函数还没有指定。
HI_SOFTIRQ用于实现bottom half,TASKLET_SOFTIRQ用于公共的tasklet。
open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL); /*初始化公共的tasklet_struct要用到的软中断*/open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL);/*初始化tasklet_struct实现的bottom half调用*/