2017-01-18

文来自本人的旧博客 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

http://stackoverflow.com/questions/27655523/use-of-r0-lsr-32-in-the-return-sub-pc-lr-r0-lsr-32-with-mmu-cache-on

本文地址: https://awakening-fong.github.io/posts/arm/arm_qemu_01

转载请注明出处: https://awakening-fong.github.io


若无法评论, 请打开JavaScript, 并通过proxy.


blog comments powered by Disqus