指定init启动Linux内核,Linux内核启动流程详细分析

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。

23ec08da3fc5a0a1f4a20a7799c16311.gif

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调用*/0b1331709591d260c1c78e86d0c51c18.png

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值