内核启动汇编阶段分析

原文地址:https://blog.csdn.net/qq_28992301/article/details/52082892


内核启动汇编阶段分析

  汇编阶段的主线代码主要分布在head.S中

1.设置虚拟地址和物理地址(约29行)

#define KERNEL_RAM_VADDR    (PAGE_OFFSET + TEXT_OFFSET)
#define KERNEL_RAM_PADDR    (PHYS_OFFSET + TEXT_OFFSET)
  • Linux是一定开mmu的,故必须同时设置虚拟地址和物理地址
  • 首先来看虚拟地址,其值为(PAGE_OFFSET + TEXT_OFFSET),首先追踪PAGE_OFFSET 这个宏,发现有挺多个文件定义的,看了一遍发现应该是arch/arm/include/asm/memory.h中,但是memory.h中也有两处定义,一处在约27行,一处在115行
    在这里插入图片描述
    可知,如果定义了 CONFIG_MMU则此处的PAGE_OFFSET将会被定义
    在这里插入图片描述
    如果前面27行的PAGE_OFFSET未被定义,则此处的PAGE_OFFSET将会被定义
    分析可知, Linux是一定开mmu的,CONFIG_MMU应该会被定义,arch/arm/configs/xxx_defconfig配置文件中,发现里面果然定义了CONFIG_MMU,再搜索CONFIG_PAGE_OFFSET,发现它的值为0xC0000000;
    接着来搜TEXT_OFFSET,它位于arch/arm/Makefile中,其值为$(textofs-y),再搜索textofs-y,发现它的值为 0x00008000。这样我们最终可以确定,kernel的虚拟地址为0xc0008000
  • 再来看物理地址,发现也有TEXT_OFFSET,故值也为0x00008000;PHYS_OFFSET的值为0x30000000。这样我们最终可以确定,kernel的物理地址为0x30008000

2.检验各种参数,并建立页表(约77行)

    __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      @ get processor id
    bl  __lookup_processor_type     @ r5=procinfo r9=cpuid
    movs    r10, r5             @ invalid processor (r5=0)?
    beq __error_p           @ yes, error 'p'
    bl  __lookup_machine_type       @ r5=machinfo
    movs    r8, r5              @ invalid machine (r5=0)?
    beq __error_a           @ yes, error 'a'
    bl  __vet_atags
    bl  __create_page_tables
    ldr r13, __switch_data      @ address to jump to after
                        @ mmu has been enabled
    adr lr, BSYM(__enable_mmu)      @ return (PIC) address
 ARM(   add pc, r10, #PROCINFO_INITFUNC )
 THUMB( add r12, r10, #PROCINFO_INITFUNC    )
 THUMB( mov pc, r12             )
 ENDPROC(stext)
  • 这里是kernel的正式入口,开始执行第一句代码

  • 首先上来从协处理器的寄存器那读取cpu的ID号,然后放到r9中,再调用__lookup_processor_type这个函数来检验这个cpu是否合法,此函数的具体实现是遍历一个数组,看看数组里面有没有这个ID;如果不合法就调用__error_p函数(其实进入了一个死循环)表示kernel启动失败….

  • 然后是检验机器码,调用了__lookup_machine_type函数,该函数的定义:
    在这里插入图片描述
    其原理是:kernel在编译的时候把数个机器码作为一个自定义段,链接到了特定的地址,具体地址在上图中的标号4处。现在,__lookup_machine_type函数将机器码从自定义段内读到r3中,然后和r1进行比较,而U-boot引导kernel时传递的机器码就是放在r1中的,于是乎__lookup_machine_type函数就不停的循环判断,相当于遍历了一般自定义段,如果没有符合的就调用就把0赋给r5,最后再返回,stext会根据r5的值来判断是否调用__error_a函数,它表示kernel启动失败….那么还有一个问题,所有的机器码保存在源码的什么地方呢?当我们编译后会生成一个include/generated/mach-types.h里面包含了所有的机器码:
    在这里插入图片描述
    我们可以通过查询这个文件来获知我们cpu对应的机器码,机器码很重要,kernel初始化的时候会根据机器码动态配置自己,所以一旦U-boot传过来的机器码不匹配,启动就会失败

  • 然后是检验U-boot传过来的参数(即tag),调用了__vet_atags函数

  • 然后第一次建立页表,调用了__vet_atags函数,此处建立的页表是1mb单位的段式粗页表,这里先救救急,等到后面第二次正式建立页表的时候就会把这次建的废掉…….

  • 最后把标号__switch_data赋给r13,等待后面跳转到__switch_data函数处执行,这个函数最后会跳转到kernel的c语言初始化处

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值