linux启动流程之汇编阶段(二)

详细分析内核汇编段代码

linux启动流程之汇编阶段(二)_第1张图片

内核启动入口点,这通常是从解压代码中调用的。要求是:MMU关闭,D-cache关闭,I-cache无关,r0为0,r1机器编号,r2atagsdtb指针,这段代码大部分是位置无关的,所以如果你链接内核在0xc0008000__pa(0xc0008000)转换为物理地址调用它。参见linux/arch/arm/tools/mach-types获得r1机器枚举的完整列表。我们尽量把垃圾降到最低;

不要在这里添加任何特定于机器的垃圾——这就是引导加载程序(或者在极端、合理的情况下,zImage)的用途。

 

这里提到了机器码在linux/arch/arm/tools/mach-types我们简单看一下:

linux启动流程之汇编阶段(二)_第2张图片

可以看出每个cpu有对应的编号,具体如何修改参考文件头部说明

 

linux启动流程之汇编阶段(二)_第3张图片

__HEAD

#define __HEAD           .section   ".head.text","ax"

定义内存段到名称为.head.text的地方

"ax"表示该节区可分配并且可执行

 

ENTRY(stext) 用于指定汇编程序的入口点

linux启动流程之汇编阶段(二)_第4张图片

在反汇编中可以得到印证

 

THUMB(  adr  r9, BSYM(1f)   )      @ Kernel is always entered in ARM.

THUMB(  bx    r9           )      @ If this is a Thumb-2 kernel,

THUMB(  .thumb                 )      @ switch to Thumb now.

THUMB(1:                    )

通过宏CONFIG_THUMB2_KERNEL选择是否开启这段Thumb指令

 adr r9 BSYM(1f)   把THUMB(1:)处的地址加载到r9 如果开启Thumb指令的话地址+1下面跳转的时候开启Thumb指令集

 bx  r9 若目标地址的bit[0]0把目标地址的代码解释为ARM代码,若目标地址的bit[0]1,即把目标地址的代码解释为Thumb代码。

 .thumb开启thumb指令

 

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

                                          @ and irqs disabled

0x00000040| 0x00000080| 0x00000013  bit6bit7bit0bit1bit41D3

上面的翻译成汇编即为msr CPSR_c, #211

cpsr_c代表的是cpsr寄存器的低8位,也就是控制位

linux启动流程之汇编阶段(二)_第5张图片

进入管理模式,禁止中断

 

mrc p15, 0, r9, c0, c0         @ get processor id

MRC指令将协处理器的寄存器中数值传送到ARM处理器的寄存器中。

请求协处理器P15执行操作0,操作数为c0c0,结果放在r9中,这里r9中存放的是cpuid,后面有机会咱会详细介绍arm的结构和汇编指令

 

跳转到__lookup_processor_type:

linux启动流程之汇编阶段(二)_第6张图片

#define __CPUINIT        .section       ".cpuinit.text", "ax"  这段代码存放在.cpuinit.text

 

adr  r3, __lookup_processor_type_data __lookup_processor_type_data的地址加载到r3

linux启动流程之汇编阶段(二)_第7张图片

linux启动流程之汇编阶段(二)_第8张图片

ldmia      r3, {r4 - r6}  r3为基地址的数据依次放入r4r6,相当于把一个地址的数据连续的拿到寄存器R4=标号3处的虚拟地址,r5=__arch_info_beginr6=__arch_info_end

sub r3, r3, r4               @ 物理地址-虚拟地址  r3是一个地址 r3这个地址内的第一个数据是r4内存的数据,r4内存的数据是一个链接地址,由于没有开启mmu还所以r3是个物理地址(已知链接地址和物理地址去找链接地址的实际物理地址)

add r5, r5, r3               @ convert virt addresses to 实际的开始地址

add r6, r6, r3               @ physical address space  实际的结束地址

1:    ldmia      r5, {r3, r4}                   @ value, mask

       and r4, r4, r9               @ mask wanted bits

       teq  r3, r4

       beq 2f

       add r5, r5, #PROC_INFO_SZ          @ sizeof(proc_info_list)

       cmp r5, r6

       blo  1b

       mov r5, #0                          @ unknown processor

2:    mov pc, lr

ENDPROC(__lookup_processor_type)

循环匹配cpuid和掩码,匹配后就会返回,不行的话R50后面会进入__error_p

 

 R3存储后方2标号地址

ldmia      r3, {r4, r8}  r4=2标号的链接地址 r8PAGE_OFFSET0x00000000

sub r4, r3, r4               @ (物理地址链接地址)

add r8, r8, r4               @ 偏移地址

 

到目前为止

r1 =机器号,r2 = atagsdtb

r8 = 偏移地址 r9 = cpuid, r10 = procinfo

 

 

 

你可能感兴趣的:(linux驱动开发)