qemu观察arm linux启动过程01
文来自本人的旧博客 http://blog.163.com/awaken_ing/blog/static/12061319720157611510386
1. 方法
qemu-system-arm -M versatilepb -m 128M -kernel /opt/qemu_arm/linux-2.6.35.7/arch/arm/boot/compressed/vmlinux -S -s
需要留意, 这里-kernel的参数不是/opt/qemu_arm/linux-2.6.35.7/vmlinux
arm-none-linux-gnueabi-gdb -tui -q /opt/qemu_arm/linux-2.6.35.7/arch/arm/boot/compressed/vmlinux
Reading symbols from /opt/qemu_arm/linux-2.6.35.7/arch/arm/boot/compressed/vmlinux...done.
(gdb) target extended-remote localhost:1234
Remote debugging using localhost:1234
warning: Source file is more recent than executable.
start () at arch/arm/boot/compressed/head.S:115
(gdb) b __setup_mmu
Breakpoint 1 at 0x200: file arch/arm/boot/compressed/head.S, line 409.
(gdb) c
Continuing.
Breakpoint 1, __setup_mmu () at arch/arm/boot/compressed/head.S:409
(gdb) i r r3 r4
r3 0x4000 16384
r4 0x8000 32768
这里r3 r4的值来自
linux-2.6.35.7/arch/arm/mach-versatile/Makefile.boot
zreladdr-y := 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
2下面主要看看_setupmmu
__setup_mmu: sub r3, r4, #16384 @ Page directory size
...ignore some code here...
1: cmp r1, r9 @ if virt > start of RAM
orrhs r1, r1, #0x0c @ set cacheable, bufferable
cmp r1, r10 @ if virt > end of RAM
bichs r1, r1, #0x0c @ clear cacheable, bufferable
str r1, [r0], #4 @ 1:1 mapping
add r1, r1, #1048576
teq r0, r2
bne 1b
在这个循环结束时
(gdb) i r r0 r2 r9 r10
r0 0x8000 32768
r2 0x8000 32768
r9 0x0 0
r10 0x10000000 268435456
r10==0x10000000 除以 1M后, 等于0x100
所以, 临界是0x4000+0x100*4=0x4400
打印出这个表:
(gdb) p /x *(unsigned int*)0x43f0@0x10
$49 = {0xfc00c1e, 0xfd00c1e, 0xfe00c1e, 0xff00c1e, 0x10000c12, 0x10100c12, 0x10200c12, 0x10300c12, 0x10400c12, 0x10500c12, 0x10600c12,
0x10700c12, 0x10800c12, 0x10900c12, 0x10a00c12, 0x10b00c12}
(gdb) p /x *(unsigned int*)0x43fc
$64 = 0xff00c1e
(gdb) p /x *(unsigned int*)(0x43fc+4)
$65 = 0x10000c12
(gdb) p /x *(unsigned int*)0x4000@0x101
$70 = {0xc1e, 0x100c1e, 0x200c1e, 0x300c1e, 0x400c1e, 0x500c1e, 0x600c1e, 0x700c1e,
省略部分打印
0xb500c1e, 0xb600c1e, 0xb700c1e, 0xb800c1e, 0xb900c1e, 0xba00c1e, 0xbb00c1e, 0xbc00c1e, 0xbd00c1e, 0xbe00c1e, 0xbf00c1e, 0xc000c1e,
0xc100c1e, 0xc200c1e, 0xc300c1e, 0xc400c1e, 0xc500c1e, 0xc600c1e, 0xc700c1e...}
本例中zreladdr小于1M, 算比较特殊. 下图是较常见的情况, 图片来自<<ARM Linux内核源码剖析>> 的图5-4
这个表建立后, 接着建表
/*
* If ever we are running from Flash, then we surely want the cache
* to be enabled also for our execution instance... We map 2MB of it
* so there is no map overlap problem for up to 1 MB compressed kernel.
* If the execution is in RAM then we would only be duplicating the above.
*/
mov r1, #0x1e
orr r1, r1, #3 << 10
mov r2, pc, lsr #20
orr r1, r1, r2, lsl #20
add r0, r3, r2, lsl #2
str r1, [r0], #4
add r1, r1, #1048576
str r1, [r0]
mov pc, lr
@ r0内容:
@ 31 14 13 2 1 0
@ 页表基址 页表index(pc高12bit) 0 0
@ r1内容:
@ 31 20 19 12 11 10 9 8 5 4 3 2 1 0
@ PC高12bit 0 AP 0 域 1 C B 1 0
@ PC高12bit 0 11 0 0000 1 1 1 1 0
3再看看使能cache on
这里qemu模拟的是versatilepb, 体系为ARMv5TEJ
__common_mmu_cache_on:
....ignore some code here...
.align 5 @ cache line aligned
1: mcr p15, 0, r0, c1, c0, 0 @ load control register
mrc p15, 0, r0, c1, c0, 0 @ and read it back to
sub pc, lr, r0, lsr #32 @ properly flush pipeline
概括地说, 通过r0建立起前后语句的dependency, 实现barrier功能. 详细的, 请参考文末的相关资料.
4出错了
继续运行,发现出错了
(gdb) bt
#0 0x000008c4 in error (x=0x3f37 "uncompression error") at arch/arm/boot/compressed/misc.c:177
#1 0x00002d94 in gunzip (buf=0x3f4b "\037\213\b", len=<value optimized out>,
out_buf=0x1d61c0 "\323\360!\343\020\237\020", <incomplete sequence \356\272>, pos=0x0, flush=0, fill=0xbf0 <nofill>,
error_fn=<value optimized out>) at arch/arm/boot/compressed/../../../../lib/decompress_inflate.c:152
#2 0x00003004 in do_decompress (input=<value optimized out>, len=<value optimized out>, output=<value optimized out>,
error=<value optimized out>) at arch/arm/boot/compressed/decompress.c:49
#3 0x00000a7c in decompress_kernel (output_start=<value optimized out>, free_mem_ptr_p=<value optimized out>,
free_mem_ptr_end_p=<value optimized out>, arch_id=<value optimized out>) at arch/arm/boot/compressed/misc.c:209
#4 0x000000e8 in not_relocated () at arch/arm/boot/compressed/head.S:266
5原因和处理方法
5.1 原因
由于使用的是vmlinux, 所以没有bootloader对内核的搬运动作, 且
arch/arm/boot/compressed/Makefile中 ZTEXTADDR := 0,
arch/arm/mach-versatile/Makefile.boot中 zreladdr-y:= 0x00008000
内核大小>0x00008000, 所以,执行解压缩时会导致覆盖.
5.2要解决这个问题, 可以
修改arch/arm/boot/compressed/Makefile中 ZTEXTADDR:= 0x200000
并rm arch/arm/boot/compressed/vmlinux.lds
另外, 没有了bootloader, 就要内核自己设置bootargs了,
可以修改.config中CONFIG_CMDLINE为
CONFIGCMDLINE="mem=128M root=/dev/nfs nfsroot=10.0.2.2:/opt/qemuarm/busybox-1.19.3/_install rw ip=10.0.2.15::10.0.2.1:255.255.255.0 init=/sbin/init console=ttyAMA0"
然后重编内核
运行时还要传递合适的machine id, 对于versatilepb, 值为0x183
5.3下面验证下是否正常运行
# /opt/tools_src/qemu-2.2.0/out/bin/qemu-system-arm -M versatilepb -m 128M -kernel /opt/qemu_arm/linux-2.6.35.7/arch/arm/boot/compressed/vmlinux -S -s -nographic
[root@localhost qemu_arm]# arm-none-linux-gnueabi-gdb -q linux-2.6.35.7/arch/arm/boot/compressed/vmlinux
Reading symbols from /opt/qemu_arm/linux-2.6.35.7/arch/arm/boot/compressed/vmlinux...done.
(gdb) target extended-remote localhost:1234
Remote debugging using localhost:1234
start () at arch/arm/boot/compressed/head.S:115
115 #ifdef DEBUG
(gdb) set $r1=0x183
(gdb) c
Continuing.
可以看到一切正常.
6相关资料
[韩] 尹锡训 ARM Linux内核源码剖析
http://stackoverflow.com/questions/11423784/qemu-arm-linux-kernel-boot-debug-no-source-code
本文地址: https://awakening-fong.github.io/posts/arm/arm_qemu_01
转载请注明出处: https://awakening-fong.github.io
若无法评论, 请打开JavaScript, 并通过proxy.
blog comments powered by Disqus