type
status
date
slug
summary
tags
category
icon
password
URL
在 bootloader 将控制权交给 linux kernel 前,需要完成下面几个动作
- 初始化系统中 ram,并将 ram 信息告知 kernel
- 准备好 device tree blob, 并将首地址写到 x0 寄存器
- 解压内核 (option)
- MMU=off, D-cache=off
一、介绍几个关于内核位置的宏,在启动过程中,经常会用到
#define __PHYS_OFFSET (KERNEL_START - TEXT_OFFSET)
: kernel space 首地址
KERNEL_START: _text=PAGE_OFFSET + TEXT_OFFSET
: kernel 开始运行的虚拟地址 (内核正文段开始的虚拟地址)
TEXT_OFFSET
: 内核正文地址距离 kernel space 首地址的偏移量- 对于 arm32,该空间一般为 32kb(0x8000),用于保存内核页表 (process id = 0 的 pgd), 以及 bootloader 和 kernel 间参数传递
- 对于 arm64, 该空间一般为 512kb(0x80000)
PAGE_OFFSET
: 目前看和__PHYS_OFFSET
一样,均表示 kernel space 首地址
二、启动代码分析
2.1 常见 arm 指令
ldr
:ldr r0, [r1]
r0=* r1; 将 r1 指向的内容存入 r0ldr r0 0x12345678
: 把 0x12345678 这个地址中的值存放到 r0 中, r0=*(0x12345678)ldr r0, =0x12345678
: 此时 ldr 是个伪指令,功能类似 mov,r0=0x12345678
str
:str r0 [r1, #4]
* (r1+4) = r0; 将 r0 中内容存入 r1+4 中的地址- .macro str_l, src, sym, tmp
- adrp
- str , [, :lo12:]
str
:str r0 [r1] , #4
*r1=r0; r1=r1+4; 将 r0 中内容存入 r1 中的地址, 并将新地址 r1+8 存入 r1
adr
: 小范围地址读取指令,将基于 pc 相对偏移的地址值读取到寄存器中 (距离 pc 1m 以内)- 原理:将符号的 21 位偏移,加上 pc,结果写入到寄存器中
adr_l
: 将符号地址转变为运行时地址 (通过 pc relative offset 形式)- .macro ldr_l, dst, sym
- adrp ,
- ldr , [, :lo12:]
adrp
: 以页为单位的大范围地址读取指令, 通过该指令可以获得符号的物理地址,当然是 page 对齐的
mrs
: 处理器模式切换指令,从指定寄存器读取到临时寄存器
msr
: 写模式到指定寄存器
bic
:bic x0, x0, #0xF000 0000 0000 0000
: 位清除,将 x0 的高 4 位清除
rsb
:rsb x0, x0, #123
: x0=1280-x0
ldp,stp
: load/store pair;ldp x8, x2, [x0, #0x10]
: x0 += 0x10, x8 = (x0), x2 = (x0 + 0x8);stp x9, x8, [x4]
: (x4) = x9, (x4 + 8) = x9;
b,bl,blx,bx
: 分别为跳转指令, 带返回值的跳转指令, 带返回和状态切换的跳转指令, 带状态切换的跳转指令
2.2 head.s 中入口函数 stext
2.3 preserve_boot_args
2.4 el2_setup
2.5 set_cpu_boot_mode_flag
__vet_fdt ———
参考文档:
- Documentation/arm64/booting.txt
- http://www.wowotech.net/armv8a_arch/arm64_initialize_1.html
- https://www.jianshu.com/p/4b68f45065c6