微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > linux内核启动流程

linux内核启动流程

时间:11-22 来源:互联网 点击:

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。

[plain]view plaincopyprint?

  1. ENTRY(__trap_init)
  2. stmfdsp!,{r4-r6,lr}
  3. mrsr1,cpsr@codefrom2.0.38
  4. bicr1,r1,#MODE_MASK@clearmodebits/*设置svc模式,disableIRQ,FIQ*/
  5. orrr1,r1,#I_BIT|F_BIT|MODE_SVC@setSVCmode,disableIRQ,FIQ
  6. msrcpsr,r1
  7. adrr1,.LCvectors@setupthevectors
  8. ldmiar1,{r1,r2,r3,r4,r5,r6,ip,lr}
  9. stmiar0,{r1,r2,r3,r4,r5,r6,ip,lr}/*拷贝异常向量*/
  10. addr2,r0,#0x200
  11. adrr0,__stubs_start@copystubsto0x200
  12. adrr1,__stubs_end
  13. 1:ldrr3,[r0],#4
  14. strr3,[r2],#4
  15. cmpr0,r1
  16. blt1b
  17. LOADREGS(fd,sp!,{r4-r6,pc})

__stubs_start到__stubs_end的地址中包含了异常处理的代码,因此拷贝到vectors_base+0x200的位置上。

1.5 init_IRQ()

[cpp]view plaincopyprint?

  1. void__initinit_IRQ(void)
  2. {
  3. externvoidinit_dma(void);
  4. intirq;
  5. for(irq=0;irq
  6. irq_desc[irq].probe_ok=0;
  7. irq_desc[irq].valid=0;
  8. irq_desc[irq].noautoenable=0;
  9. irq_desc[irq].mask_ack=dummy_mask_unmask_irq;
  10. irq_desc[irq].mask=dummy_mask_unmask_irq;
  11. irq_desc[irq].unmask=dummy_mask_unmask_irq;
  12. }
  13. CSR_WRITE(AIC_MDCR,0x7FFFE);/*disableallinterrupts*/
  14. CSR_WRITE(CAHCNF,0x0);/*CloseCache*/
  15. CSR_WRITE(CAHCON,0x87);/*FlushCache*/
  16. while(CSR_READ(CAHCON)!=0);
  17. CSR_WRITE(CAHCNF,0x7);/*OpenCache*/
  18. init_arch_irq();
  19. init_dma();
  20. }

这个函数用来做体系相关的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调用 */

1.

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top