没有合适的资源?快使用搜索试试~ 我知道了~
linux内核启动流程解析
4星 · 超过85%的资源 需积分: 10 12 下载量 53 浏览量
2011-05-11
09:04:22
上传
评论
收藏 77KB DOC 举报
温馨提示
试读
13页
国嵌嵌入式培训,难得的嵌入式学习资料。适合培训和自学。linux内核启动流程解析。
资源推荐
资源详情
资源评论
Linux 内核构成
(国嵌 2440 培训)
1 arch/arm/boot/compressed/Makefile arch/arm/boot/compressed/vmlinux.lds
2. arch/arm/kernel/vmlinux.lds
Linux 内核启动流程
(国嵌 2440 培训)
arch/arm/boot/compressed/start.S
Start:
.type start,#function
.rept 8
mov r0, r0
.endr
b 1f
.word 0x016f2818 @ Magic numbers to help the loader
.word start @ absolute load/run zImage address
.word _edata @ zImage end address
1: mov r7, r1 @ save architecture ID
mov r8, r2 @ save atags pointer
这也标志着 u-boot 将系统完全的交给了 OS,bootloader 生命终止。之后代码在 133 行会读
取 cpsr 并判断是否处理器处于 supervisor 模式——从 u-boot 进入 kernel,系统已经处于
SVC32 模式;而利用 angel 进入则处于 user 模式,还需要额外两条指令。之后是再次确认中
断关闭,并完成 cpsr 写入
mrs r2, cpsr @ get current mode
tst r2, #3 @ not user?
bne not_angel
mov r0, #0x17 @ angel_SWIreason_EnterSVC
swi 0x123456 @ angel_SWI_ARM
not_angel:
mrs r2, cpsr @ turn off interrupts to
orr r2, r2, #0xc0 @ prevent angel from running
msr cpsr_c, r2
然后在 LC0 地址处将分段信息导入 r0-r6、ip、sp 等寄存器,并检查代码是否运行在与链接时
相同的目标地址,以决定是否进行处理。由于现在很少有人不使用 loader 和 tags,将 zImage
烧写到 rom 直接从 0x0 位置执行,所以这个处理是必须的(但是 zImage 的头现在也保留了不
用 loader 也可 启 动的 能力) 。 arm 架构 下 自解 压头一 般是链 接在 0x0 地址 而 被加 载到
0x30008000 运行,所以要修正这个变化。涉及到
r5 寄存器存放的 zImage 基地址
r6 和 r12(即 ip 寄存器)存放的 got(global offset table)
r2 和 r3 存放的 bss 段起止地址
sp 栈指针地址
很简单,这些寄存器统统被加上一个你也能猜到的偏移地址 0x30008000。该地址是 s3c2410
相关的,其他的 ARM 处理器可以参考下表
PXA2xx 是 0xa0008000
IXP2x00 和 IXP4xx 是 0x00008000
Freescale i.MX31/37 是 0x80008000
TI davinci DM64xx 是 0x80008000
TI omap 系列是 0x80008000
AT91RM/SAM92xx 系列是 0x20008000
Cirrus EP93xx 是 0x00008000
这些操作发生在代码 172 行开始的地方,下面只粘贴一部分
add r5, r5, r0
add r6, r6, r0
add ip, ip, r0
后面在 211 行进行 bss 段的清零工作
not_relocated: mov r0, #0
1: str r0, [r2], #4 @ clear bss
str r0, [r2], #4
str r0, [r2], #4
str r0, [r2], #4
cmp r2, r3
blo 1b
然后 224 行,打开 cache,并为后面解压缩设置 64KB 的临时 malloc 空间
bl cache_on
mov r1, sp @ malloc space above stack
add r2, sp, #0x10000 @ 64k max 接下来 238 行进行检查,确定内核解压缩
后的 Image 目标地址是否会覆盖到 zImage 头,如果是则准备将 zImage 头转移到解压出来的
内核后面
cmp r4, r2
bhs wont_overwrite
sub r3, sp, r5 @ > compressed kernel size
add r0, r4, r3, lsl #2 @ allow for 4x expansion
cmp r0, r5
bls wont_overwrite
mov r5, r2 @ decompress after malloc space
mov r0, r5
mov r3, r7
bl decompress_kernel
真实情况——在大多数的应用中,内核编译都会把压缩的 zImage 和非压缩的 Image 链接到同
样的地址,s3c2410 平台下即是 0x30008000。这样做的好处是,人们不用关心内核是 Image
还是 zImage,放到这个位置执行就 OK,所以在解压缩后 zImage 头必须为真正的内核让路。
在 250 行解压完毕,内核长度返回值存放在 r0 寄存器里。在内核末尾空出 128 字节的栈空间用,
并且使其长度 128 字节对齐。
add r0, r0, #127 + 128 @ alignment + stack
bic r0, r0, #127 @ align the kernel length
算出搬移代码的参数:计算内核末尾地址并存放于 r1 寄存器,需要搬移代码原来地址放在 r2,
需要搬移的长度放在 r3。然后执行搬移,并设置好 sp 指针指向新的栈(原来的栈也会被内核
覆盖掉)
add r1, r5, r0 @ end of decompressed kernel
adr r2, reloc_start
ldr r3, LC1
add r3, r2, r3
1: ldmia r2!, {r9 - r14} @ copy relocation code
stmia r1!, {r9 - r14}
ldmia r2!, {r9 - r14}
stmia r1!, {r9 - r14}
cmp r2, r3
blo 1b
add sp, r1, #128 @ relocate the stack
搬移完成后刷新 cache,因为代码地址变化了不能让 cache 再命中被内核覆盖的老地址。然后
跳转到新的地址继续执行
bl cache_clean_flush
add pc, r5, r0 @ call relocation code
注意——zImage 在解压后的搬移和跳转会给 gdb 调试内核带来麻烦。因为用来调试的符号表
是在编译是生成的,并不知道以后会被搬移到何处去,只有在内核解压缩完成之后,根据计算
出来的参数“告诉”调试器这个变化。以撰写本文时使用的 zImage 为例,内核自解压头重定向后,
reloc_start 地址由 0x30008360 变为 0x30533e60。故我们要把 vmlinux 的符号表也相应的从
0x30008000 后移到 0x30533b00 开始,这样 gdb 就可以正确的对应源代码和机器指令。
随着头部代码移动到新的位置,不会再和内核的目标地址冲突,可以开始内核自身的搬移了。
此时 r0 寄存器存放的是内核长度(严格的说是长度外加 128Byte 的栈),r4 存放的是内核的
目的地址 0x30008000,r5 是目前内核存放地址,r6 是 CPU ID,r7 是 machine ID,r8 是
剩余12页未读,继续阅读
资源评论
- chenzhengnan2017-02-22慢慢看,总有收获的。
cdwang101
- 粉丝: 0
- 资源: 10
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功