从linux内核启动说起(三)

1、            内核启动过程分析(以ARM为例)

(1)arch/arm/kernel/head.S

①       确定内核是否支持该架构和单板。

②       连接内核时使用的虚拟地址,所以要设置页表,使能MMU。

③       调用C函数start_kernel之前的常规工作,包括复制数据段,清除BSS段,设置栈指针,保存CPU ID到processor_id变量,保存机器码ID,调用start_kernel。

④       理解代码:

/*

 * Kernel startup entry point.

 * ---------------------------

 *

 * This is normally called from thedecompressor code.  The requirements

 * are: MMU = off, D-cache = off, I-cache =dont care, r0 = 0,

 * r1 = machine nr, r2 = atags pointer.

 *

 * This code is mostly position independent, soif you link the kernel at

 * 0xc0008000, you call this at__pa(0xc0008000).

 *

 * See linux/arch/arm/tools/mach-types for thecomplete list of machine

 * numbers for r1.

 *

 * We're trying to keep crap to a minimum; DONOT add any machine specific

 * crap here - that's what the boot loader (orin extreme, well justified

 * circumstances, zImage) is for.

 */

       __HEAD

ENTRY(stext)

       setmode   PSR_F_BIT| PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode

                                                     @and irqs disabled

       mrc  p15,0, r9, c0, c0                 @ getprocessor id

       bl      __lookup_processor_type                  @ r5=procinfo r9=cpuid

       movs         r10,r5                                   @invalid processor (r5=0)?

 THUMB( it     eq)            @ force fixup-able longbranch encoding

       beq  __error_p                   @yes, error 'p'

       bl      __lookup_machine_type           @ r5=machinfo

       movs         r8,r5                                     @invalid machine (r5=0)?

 THUMB( it     eq)            @ force fixup-able longbranch encoding

     beq  __error_a                   @ yes, error 'a'

………………………………………………………………

l  bl __lookup_processor_type  

调用__lookup_processor_type子程序。

在内核映像中定义了若干proc_info_list结构,表示支持的cpu。如果定义了CONFIG_CPU_ARM920t则编译proc-arm920.S的文件生成对应的proc_info_list结构。

__lookup_processor_type的作用就是从实际硬件获得cpu Id 号和内核中proc_info_list是否有相对应的cpu类型,如果没有返回0.

l  bl __lookup_machine_type

调用__lookup_machine_type子程序。

和匹配CPUID的过程相似,在匹配机器类型过程中,没一个开发板都对应与一个machine_desc结构体,它定义了开发板相对应的属性和函数,比如机器的Id,IO起始物理地址,Bootloader传入的参数地址,中断初始化函数,Io映射函数等。每一个machine_desc结构体是由一个BSP文件内的MACHINE_START和MACHINE_END定义。Uboot在调用内核时,r1存储的是机器ID。匹配不成功则返回0,匹配成功则返回machine_desc结构体地址,在start_kernel()中被多次使用。

如果上述匹配CPUID和MACHINEID都成功则继续执行。

l  下面是对SMDK2440的BSP文件的machine_desc结构分析

MACHINE_START(S3C2440,"SMDK2440")

       /* Maintainer: Ben Dooks<ben-linux@fluff.org> */

       .boot_params   = S3C2410_SDRAM_PA + 0x100,

 

       .init_irq     =s3c24xx_init_irq,

       .map_io             =smdk2440_map_io,

       .init_machine   = smdk2440_machine_init,

       .timer                  =&s3c24xx_timer,

MACHINE_END

…………………………………………………………

#define MACHINE_START(_type,_name)                         \

staticconst struct machine_desc __mach_desc_##_type       \

 __used                                                                  \

 __attribute__((__section__(".arch.info.init")))= {   \

       .nr              =MACH_TYPE_##_type,          \

       .name                =_name,

 

#defineMACHINE_END                                     \

};

在arch/arm/tools/mach-types.h中定义了机器类型。

machine_is_xxx        CONFIG_xxxx            MACH_TYPE_xxx              number

s3c2440                      ARCH_S3C2440                S3C2440                    362

(2)init/main.cstart_kernel()函数。

①       调用setup_arch()函数设置与体系结构相关的环境。

setup_arch()函数内容如下:

setup_processor();//处理器设置

mdesc =setup_machine(machine_arch_type);//获取单板的machine_desc结构体。

parse_tags(tags);//解析machine_desc中初始化的boot参数

paging_init(mdesc);//重新初始化页表

paging_init(mdesc);分析:我们知道默认外设I/O资源是不在Linux内核空间中的(如sram或硬件接口寄存器等),若需要访问该外设I/O资源,必须先将其地址映射到内核空间中来,然后才能在内核空间中访问它。这里的map_io成员即内核提供给用户的创建外设I/O资源到内核虚拟地址静态映射表的接口函数。Map_io成员函数会在系统初始化过程中被调用,流程如下:
Start_kernel -> setup_arch() -->paging_init() --> devicemaps_init()—>Map_io中被调用。

②       初始化控制台。

console_init();调用s3c24xx_serial_console初始化。

③       Reset_init启动init进程。

Reset_initàkernel_thread创建一个线程àinit_post()àrun_init_process();如果命令行定义了“init=xxx”则调用xxx作为第一个进程否则默认调用根文件系统的/sbin/init程序。至此内核启动了第一个进程并根据init进程的配置文件/etc/inittab执行进程。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值