1.之间差异。
bootm 加载linux镜像是加载uIamge,uIamge是由mkimage制作而来,和zIamge的差异是uIamge是zIamge压缩过的,bootm需要先对uIamge解压,解压地址为内核入口地址。当解压完成时uIamge和zIamge 几乎是相同的,具体差异可以论述。uboot目前只能支持uImage启动,不支持zImage启动
2.bootm解压过程
---------------------------------------------------------------------------
## Booting image at 08808000 ...
Image Name: Linux-2.6.14.7
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 989172 Bytes = 966 kB
Load Address: 08008000
Entry Point: 08008000
Verifying Checksum ... OK
OK uboot bootm命令对uIamge的解压操作
---------------------------------------------------------------------------
Starting kernel ...
传递内核参数将控制权交给arch/arm/boot/compressed]head.S
----------------------------------------------------------------------------
如mx1ADS班子内存的起始地址为0x0800_0000,通过tftp 下载到0x0800_8000 +offset ,offset大于0x80_0000,即tftp 0x0880_8000 然后bootm 0x0880_8000 即
将0x0880_8000处的uIamge解压,解压地址即为mkimage 设置的kernel入口地址0x0800_8000。
2.bootm内核启动分析
通过分析uboot把控制权交给kernel的瞬间,我们可以知道bootm启动linux内核,它究竟做了哪些工作。
具体源码在uboot1.16 lib_arm/Armlinux.c do_bootm_linux(),大家有兴趣可以看下源码,这里不仔细分析了,网上资料超多。
void (*theKernel)(int zero, int arch, uint params) 通过对这个函数指针的操作实现控制权从uboot到linux的交接。
该函数可以等价于set pc=0x0800_8000 ,r0=0 ,r1=0xA0(mx1ads 芯片的id),r2=0x08000100(bootargs参数基址)。
我通过仿真器,设置了一个指令断点在0x0800_8000,可以看到该瞬间uboot做的操作。
>BKM>dr //查看当前时刻通用寄存器值
R00 = 00000000 R01 = 000000A0 R02 = 08000100 R03 = 08008000
R04 = 00000000 R05 = 08000124 R06 = 083DC0A9 R07 = 0841BC9C
R08 = 083DBFDC R09 = 083E0260 R10(SL) = 00000000 R11(FP) = 00000002
R12(IP) = 083DBFC0 R13(SP) = 083DBD44 R14(LR) = 08413984 PC = 08008000
CPSR = 600000D3 SPSR = B00000FF
>BKM>di 0x08008000 // 反汇编该地址区域代码
08008000: mov r0,r0
08008004: mov r0,r0
08008008: mov r0,r0
0800800c: mov r0,r0
08008010: mov r0,r0
08008014: mov r0,r0
08008018: mov r0,r0
0800801c: mov r0,r0
08008020: b 0x8008030
08008024: .long 0x16F2818
08008028: andeq r0,r0,r0
0800802c: streqd r1,[pc],-r4
08008030: mov r7,r1
08008034: mov r8,#0
08008038: mrs r2,cpsr
0800803c: tst r2,#3
08008040: bne 0x800804C
08008044: mov r0,#0x17
08008048: swi 0x123456
0800804c: mrs r2,cpsr
08008050: orr r2,r2,#0xC0
08008054: msr cpsr_c,r2
08008058: andeq r0,r0,r0
0800805c: andeq r0,r0,r0
08008060: add r0,pc,#0xC8
08008064: ldmia r0,{r1,r2,r3,r4,r5,r6,r12,r13}
08008068: sub r0,r0,r1
0800806c: beq 0x800809C
>BKM>dml 0x08000100 0x50 //uboot bootargs
08000100: 00000005 54410001 00000000 00000000 ....TA..........
08000110: 00000000 00000004 54410002 04000000 ........TA......
08000120: 08000000 0000000F 54410009 736E6F63 ........TA..snoc
08000130: 3D656C6F 53797474 2C30584D 32353131 =eloSytt,0XM2511
08000140: 386E3030 3D706920 746F6F62 6F722070 8n00=pi toobor p
08000150: 2F3D746F 2F766564 0073666E 00000000 /=to/ved.sfn....
08000160: 00000000 00000000 00000000 00000000 ................
通过仿真器可以很清晰的看到bootm先后完成了2部分工作。大家可以分析bootm源码
1.set bootargs 传递参数
2.set pc=0x0800_8000 ,r0=0 ,r1=0xA0
3.对比zImage 分析
通过tftp 0x0800_8000 命令直接将zImage下载到0x0800_8000地址
此时对0x08008000 反汇编可以得到和arch/arm/boot/compressed/head.S一致的汇编代码,说明这是kernel的入口
08008000: msr cpsr_c,#0xD3
08008004: bl 0x8008150
08008008: mov r10,r5
0800800c: beq 0x8008148
08008010: bl 0x80081B0
08008014: mov r8,r5
08008018: beq 0x8008148
0800801c: bl 0x80080D8
08008020: ldr r13,[pc,#+4]
08008024: add r14,pc,#0x68
08008028: add pc,r10,#0xC
0800802c: andgt r8,r0,r0,asr r0
08008030: andgt r2,r11,r0
08008034: andgt r2,r11,r0
08008038: andgt r2,r12,r0,lsl #1
0800803c: ldrgth r14,[r13],-r12
08008040: andgt r5,r12,r12,asr #1
08008044: mulgts r12,r12,r0
08008048: andgt r5,r11,r12,asr #0x13
0800804c: ldrgtsh r3,[r11],-r8
08008050: sub r3,pc,#0x28
08008054: ldmia r3!,{r4,r5,r6,r7}
08008058: cmp r4,r5
0800805c: cmpne r5,r6
08008060: ldrne r11,[r4],#+4
08008064: strne r11,[r5],#+4
08008068: bne 0x800805C
0800806c: mov r11,#0
08008070: cmp r6,r7
08008074: strcc r11,[r6],#+4
08008078: bcc 0x8008070
0800807c: ldmia r3,{r4,r5,r6,r13}
08008080: str r9,[r4,#+0]
此时用go命令 go 0x08008000,go命令本质就是改变当前pc值,即pc=go 0x08008000
断点位置为 0x08008000 ,使用go 会在 0x08008000处停下来
>BKM>dr //此时通用寄存器值为
R00 = 00000000 R01 = 083E0264 R02 = 000F0000 R03 = 0000000C
R04 = 08008000 R05 = 08808000 R06 = 41129200 R07 = 083E0264
R08 = 08000000 R09 = 18000000 R10(SL) = 00000000 R11(FP) = 00000020
R12(IP) = 08808354 R13(SP) = 088E9464 R14(LR) = 08808298 PC = 08008000
CPSR = 400000D3 SPSR = B00000FF
//uboot bootargs
08000100: 00000000 00000000 00000000 00000000 ................
08000110: 00000000 00000000 00000000 00000000 ................
08000120: 00000000 00000000 00000000 00000000 ................
08000130: 00000000 00000000 00000000 00000000 ................
08000140: 00000000 00000000 00000000 00000000 ................
08000150: 00000000 00000000 00000000 00000000 ................
08000160: 00000000 00000000 00000000 00000000 ................
08000170: 00000000 00000000 00000000 00000000 ................
08000180: 00000000 00000000 00000000 00000000 ................
08000190: 00000000 00000000 00000000 00000000 ................
080001A0: 00000000 00000000 00000000 00000000 ................
这个时候发现kernel无法正确启动zImage
4,通过仿真器对go命令加以改造
a.将通用寄存器值改成
R00 = 00000000 R01 = 000000A0 R02 = 08000100 R03 = 0000000C
R04 = 08008000 R05 = 08808000 R06 = 41129200 R07 = 083E0264
R08 = 08000000 R09 = 18000000 R10(SL) = 00000000 R11(FP) = 00000020
R12(IP) = 08808354 R13(SP) = 088E9464 R14(LR) = 08808298 PC = 08008000
CPSR = 400000D3 SPSR = B00000FF
b.通过仿真器修改 0x08000100 地址的值
sml 0x08000100 00000005 54410001 00000000 00000000 00000000 00000004 54410002 04000000 08000000 0000000F 54410009 736E6F63
sml 0x08000130 3D656C6F 53797474 2C30584D 32353131 386E3030 3D706920 746F6F62 6F722070 2F3D746F 2F766564 0073666E 00000000
>BKM>dml 0x08000100 0x50
08000100: 00000005 54410001 00000000 00000000 ....TA..........
08000110: 00000000 00000004 54410002 04000000 ........TA......
08000120: 08000000 0000000F 54410009 736E6F63 ........TA..snoc
08000130: 3D656C6F 53797474 2C30584D 32353131 =eloSytt,0XM2511
08000140: 386E3030 3D706920 746F6F62 6F722070 8n00=pi toobor p
08000150: 2F3D746F 2F766564 0073666E 00000000 /=to/ved.sfn....
08000160: 00000000 00000000 00000000 00000000 ................
然后让程序执行,这样通过uboot也可以让zImage得以执行。
可见go和bootm差异就是 go只是改写pc值,而bootm传递r0,r1,r2还有bootargs
有疑问加站长微信联系(非本文作者)