Linux内核加载过程
通常,Linux内核都是经过gzip加载过之后的映像文件。
- 
bootloader复制压缩内核到内存空间。 
- 
内核自解压。 
- 
运行内核。 
编译完成的Linux内核存放在哪里?
- 
./vmlinux elf格式未压缩内核。 
- 
arch/arm/boot/compressed/vmlinux 压缩以后的elf格式内核。 
- 
arch/arm/boot/zImage 压缩内核。 
压缩内核(zImage)的入口
- 
/arch/arm/boot/compressed/vmlinux.lds 该文件为编译器指定link顺序。 
- 
ENTRY(_start) 压缩内核从.start段开始执行。 
- 
在/arch/arm/boot/compressed/head.S中执行以下爱操作: 
 (1)检测系统空间。
 (2)初始化C代码空间。
 (3)跳转到C代码decompress_kernel,
 arch/arm/boot/compressed/misc.c中。
解压之前的串口输出
- 
include/asm-arm/arch-s3c2410/uncompress.h 中定义了puts作为串口输出函数。 
- 
解压结束之后,程序跳转到r5:解压之后内核的起始地址。 
开始真正的Linux内核
1、入口在arch/arm/kernel/head-armv.S
2、查找处理器类型
- 
__lookup_processor_type 
- 
__lookup_architecture_type 
3、初始化页表:__creat_page_tables
4、初始化C代码空间
5、跳转到C代码中,start_kernel
ARM的MMU单元
MMU:内存管理单元
作用:
- 
虚拟地址到物理地址的映射 
- 
存储器访问权限 
- 
控制Cache 
通过MMU的访存
- 
MMU会先查找TLB中的虚拟地址表 
- 
如果TLB中没有虚拟地址的入口,硬件从主存储器中的转换表中获取转换与访问权限。 
ARM的MMU访存原理
ARM的MMU页表格式
MMU支持基于节或者页的存储器访问。
- 
节:1MB的存储器块 
- 
大页:64KB的存储器块 
- 
小页:4KB的存储器块 
- 
微页:1KB的存储器块 
页表的级别
存在主存储器内的转换页表有两个级别:
- 
第一级表:存储节转换表与指向第二级表的指针 
- 
第二级表: (1)存储大页和小页的转换表。 (2)存储微页的转换表。 
一级页表的地址
第一级表占用空间16KB,必须16KB对齐
第一级描述符
一级表每个入口描述了它所关联的1MB虚拟地址是如何映射的。
节描述符
- 
Bits[1:0] 描述符类型(10b 表示节描述符) 
- 
Bits[3:2] 高速缓存(cache)和缓冲位(buffer) 
- 
Bits[4] 由具体实现定义 
- 
Bits[8:5] 控制的节的16 种域之一 
- 
Bits[9] 现在没有使用,应该为零 
- 
Bits[11:10] 访问控制(AP) 
- 
Bits[19:12] 现在没有使用,应该为零 
- 
Bits[31:20] 节基址,形成物理地址的高12 位 
节的转换过程
临时内核页表的创建 __create_page_tables
__create_page_tables:
pgtbl r4 @ page table address 0x30008000-0x4000
mov r0, r4 @r0=0x30004000
mov r3, #0
add r2, r0, #0x4000
1: str r3, [r0], #4
str r3, [r0], #4
str r3, [r0], #4
str r3, [r0], #4
teq r0, r2
bne 1b
把一级页表0x30004000-0xa0080000清空
krnladr r2, r4 @ start of kernel
r4=0xa0004000,r2 = 内核起始地址所在1MB对齐空间,0x30000000
add r3, r8, r2 @ flags + kernel base
r8 为从处理器信息中得到的MMU 页表标志,r8=0xc0e, r3=0x30000c0e
str r3, [r4, r2, lsr #18]@ identity mapping
地址:0x300068000, value:0x30000c0e
add r0, r4, #(TEXTADDR & 0xff000000) >> 18 
@ start of kernel
bic r2, r3, #0x00f00000
str r2, [r0] @ PAGE_OFFSET + 0MB
add r0, r0, #(TEXTADDR & 0x00f00000) >> 18
str r3, [r0], #4 @ KERNEL + 0MB
......
映射表内容
映射结果
进入C代码
init/main.c中的start_kernel函数,进入到了Linux内核代码中。
- 
printk函数 
- 
重新初始化页表 
- 
初始化中断,trap_init 
- 
设置系统定时器、控制台… 
- 
创建内核进程init 
以上就是良许教程网为各位朋友分享的Linu系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你 !

 
		

 微信扫一扫打赏
			    	微信扫一扫打赏
			     支付宝扫一扫打赏
			    	支付宝扫一扫打赏	
			    

.png) 
		        