Linux-3.7.1 arm启动过程笔记
最新的linux-3.7.1发布,和linux-2.6.xx在arm启动部分有些修改,主要去掉了查找板子型号,采用新的dtb描述板级信息。
内核被解压缩程序解压到PHY_OFFSET+0x8000,即物理内存偏移0x8000处(当然这也不是绝对,arch/arm/Makefile中textofs-y决定这个值)。
解压后内核的入口arch/arm/kernel/head.S:79stext.在head.S:59开始的注释里解压缩代码调用此地址,需要MMU=off,D-cache=off,I-cache=don’tcare,
r0= 0,r1=machine nr,r2 = atags or dtb pointer
接下来主要过程如下:
safe_svcmode_maskallr9 ;切换到SVC模式,并禁止所有中断
mrc p15,0, r9, c0, c0 ;获取cpuidr9
__lookup_processor_type; 获取cpuid相关procinfo地址r5;并r5r10
ldrr8, =PHYS_OFFSET ; 板子物理内存偏移r8
现在r1machineno , r2 = atags or dtb, r8 = phys_offset, r9 = cpuid, r10 = procinfo
__vet_atags ;检查r2atags or dtb合法性,非法r2返回0;arm/kernel/head-common.S
__create_page_tables ;建立页表
ldrr13, =__mmap_switched
adrlr, BSYM(1f) @ return (PIC) address
movr8, r4 @ set TTBR1 to swapper_pg_dir
ARM(add pc, r10, #PROCINFO_INITFUNC)
1: b __enable_mmu
接下来直接用图说话,万恶的word,把我码的字毁了
我们使用qemu模拟arm启动,并在到start_kernel之前导出内存镜像
下载qemu-1.3 并编译,安装,具体怎么做baidu or google
下载内核源码linux-3.7.1 交叉编译,我使用cpu是realview-pb-a8
制作文件系统,我们使用initramfs 把内核和文件系统做在一起
直接看图
输入qemu-system-arm-M realview-pb-a8 -kernel ./zImage -append "noinitrdinit=/linuxrc console=ttyAMA0 mem=128M" -s -S
此时qemu会处于Stopped状态,等待gdb连接
进入内核目录,输入arm-none-linux-gnueabi-gdb./vmlinux 运行如下
输入targetremote localhost:1234,在start_kernel处设置断点linit/main.c:400
Start_kernel处于init/main.c:468行,设置断点b468;接着继续运行
Gdb出现断点停住后,鼠标进入qemu界面里(鼠标在qemu黑框里点一下),按ctrl+alt+2切换到控制台,想切换回来使用ctrl+alt+1
导出当前内存只导出1M,保存文件名为mem.log,在qemu控制台输入memsave0xc0000000 1024*1024 mem.log.注意此时mmu已经开启所以为0xc0000000.接下来我们分析一下内存镜像
我们使用hexdump打开来看
其中*表示这之间的内容全为0
Arm启动代码中,说明一级页表描述符是从内存偏移16K处建立,即0xc0004000.从内存镜像我们可以看出一级页表描述符
0x4000-0x5c03全为0
0x5c04:0x70100c0e
0x5c08-0x6fff全为0
0x7000-0x7027:0x7000 0c0e
0x7010 0c0e
0x70200c0e
…….
0x70800c0e
0x70900c0e
0x7028-0x7fff全为0
一级页描述符(Level1 Descriptor),一个这样的表项占4个字节,可以是以下四种格式之一:
如果描述符的最低两位是00,属于Fault格式,表示该范围的VA没有映射到PA。如果描述符的最低两位是10,属于Section格式,这种格式没有二级页表而是直接映射到物理页面,一个Section是1M的大页面,描述符中[31:20]位就是这个页面的基地址,基地址的[19:0]低位全为0,对齐到1M地址边界,描述符中的Domain和AP位控制访问权限,C、B两位控制缓存。
Realview的内存物理地址0x7000 0000.一级页表从0x7000 4000 建立,则Cp15 TTB=0x7000 4000
当CPU发出虚拟地址VA时候
CP15 TTB [31..14]à一级页表基地址,(16K对齐)
VA[31..20]>>20 一级页表偏移。
------------->物理首地址 TTB & 0xffff c000 | (VA&0xfff0 0000 >>20)
VA[19..0] 代表物理首地址偏移。
VA 对应物理地址 *(TTB & 0xffff c000 | (VA&0xfff0 0000 >>20))+VA & 0x000f ffff
例:
Cpu 寻址 0xc000 2210
页表基址:TTB = 0x7000 4000 ,TTB & 0xffffc000 =0x7000 4000
页表偏移:VA[31..20] = 0xc000 2210 & 0xfff0 0000 >>20 0xc000 0000 >>20=0xc00
最终物理首地址 *(0x7000 4000+0xc00)=0x0000 0000
0x7000 4c00没有映射物理地址,访问失败
根据上述镜像,我可以得出:
0x5c04 :0x7010 0c0e
页内偏移=0x5c04-0x4000=0x1c04 因为4Byte对齐 0x1c04>>2=0x701
VA[31..20]=0x1c04<<20=0x7010 0000
由此可以看出VA=0x701x xxxx被mmu映射到0x701x xxxx的物理地址上,一一映射
0x7000 :0x7000 0c0e
页内偏移=0x7000-0x4000=0x3000 因为4Byte对齐 0x3000>>2=0xc00
VA[31..20]=0xc00<<20=0xc000 0000
由此可以看出VA=0xc00x xxxx被mmu映射到0x700x xxxx的物理地址上
0x7004 :0x7010 0c0e 页内偏移=0x7004-0x4000=0x3004 因为4Byte对齐 0x3004>>2=0xc01
VA[31..20]=0xc01<<20=0xc010 0000
由此可以看出VA=0xc01x xxxx被mmu映射到0x701x xxxx的物理地址上
……..
为什么会有0x5c04 à0x7010 0c0e.内核在开启mmu后….