1、解压zImage --- head.s 分析笔记

  1. start:

  1. .type start,#function
  2. .rept 8
  3. mov r0, r0 @ 空语句
  4. .endr
  5. b 1f
  6. /*魔数,和uboot的魔数相对应*/
  7. .word 0x016f2818 @ Magic numbers to help the loader
  8. .word start @ absolute load/run zImage address
  9. .word _edata @ zImage end address
  10. 1: mov r7, r1 @ save architecture ID
  11. mov r8, r2 @ save atags pointer
  12. #ifndef __ARM_ARCH_2__
  13. ......
  14. #else
  15. /*关中断*/
  16. teqp pc, #0x0c000003 @ turn off interrupts
  17. #endif
  18. /*
  19. * Note that some cache flushing and other stuff may
  20. * be needed here - is there an Angel SWI call for this?
  21. */
  22. /*
  23. * some architecture specific code can be inserted
  24. * by the linker here, but it should preserve r7, r8, and r9.
  25. */
  26. .text
  27. /*
  28. * LC0标签在下面定义,这里把LC0的地址装载到r0,和ldr不同,adr不需要考虑偏移
  29. * 下面ldmia命令把r0(LC0)的内容依次赋给r1,r2等寄存器,对应关系看下面LC0标签
  30. */
  31. adr r0, LC0
  32. ARM( ldmia r0, {r1, r2, r3, r4, r5, r6, r11, ip, sp})
  33. THUMB( ldmia r0, {r1, r2, r3, r4, r5, r6, r11, ip} )
  34. THUMB( ldr sp, [r0, #32] )
  35. /*这里 r0 = r0 - r1 并更新 N、Z、C 和 V 标记*/
  36. subs r0, r0, r1 @ calculate the delta offset
  37. @ if delta is zero, we are
  38. @ 如果运行当前运行地址和链接地址相等,则不需进行重定位。直接清除bss段
  39. beq not_relocated @ running at the address we
  40. ......

  1. not_relocated:

  1. mov r0, #0
  2. /* r2:bbs开始位置
  3. * r3: bbs结束位置
  4. * str命令: STR    Rd, [Rbase], Rindex  存储 Rd 到 Rbase 所包含的有效地址。把 Rbase
  5. * + Rindex 所合成的有效地址写回 Rbase。  
  6. * 下面4句str命令将清空 bss 32个字节 ,r2 累加 32
  7. * */
  8. 1: str r0, [r2], #4 @ clear bss r2+=4
  9. str r0, [r2], #4 @ clear bss r2+=4
  10. str r0, [r2], #4 @ clear bss r2+=4
  11. str r0, [r2], #4 @ clear bss r2+=4
  12. cmp r2, r3 @ 判断是否到bss的结束位置,
  13. blo 1b @ 若不是,继续清空
  14. /*
  15. * The C runtime environment should now be setup
  16. * sufficiently. Turn the cache on, set up some
  17. * pointers, and start decompressing.
  18. */
  19. bl cache_on
  20. /*r1、r2作为参数传给decompress_kernel */
  21. mov r1, sp @ malloc space above stack
  22. add r2, sp, #0x10000 @ 64k max 分配一段解压函数需要的内存缓冲 sp 栈指针,
  23. /*
  24. * Check to see if we will overwrite ourselves.
  25. * r4 = final kernel address 最终的内核开始地址,就是解压后的地址
  26. * r5 = start of this image 解压前的映像开始地址
  27. * r6 = size of decompressed image 解压前的映像大小
  28. * r2 = end of malloc space (and therefore this image)
  29. * We basically want:
  30. * r4 >= r2 -> OK
  31. * r4 + image length <= r5 -> OK
  32. * 内核映像解压后不会超过解压前的4倍大小
  33. * 调用decompress_kernel前,要准备4个参数:r0 (解压后的内核开始位置),r1(动态内存开始位置)
  34. * r2(动态内存结束位置),r3(结构ID))
  35. */
  36. cmp r4, r2 @ r4为内核执行地址,此时为0X50008000,r2此时为用户栈顶,
  37. @ 即解压函数所需内存缓冲的开始处
  38. bhs wont_overwrite
  39. add r0, r4, r6
  40. cmp r0, r5
  41. bls wont_overwrite
  42. mov r5, r2 @ decompress after malloc space
  43. mov r0, r5
  44. mov r3, r7
  45. bl decompress_kernel
  46. add r0, r0, #127 + 128 @ alignment + stack
  47. bic r0, r0, #127 @ align the kernel length
  48. /*
  49. * r0 = decompressed kernel length
  50. * r1-r3 = unused
  51. * r4 = kernel execution address
  52. * r5 = decompressed kernel start
  53. * r7 = architecture ID
  54. * r8 = atags pointer
  55. * r9-r12,r14 = corrupted
  56. */
  57. add r1, r5, r0 @ end of decompressed kernel
  58. adr r2, reloc_start
  59. ldr r3, LC1
  60. add r3, r2, r3
  61. 1: ldmia r2!, {r9 - r12, r14} @ copy relocation code
  62. stmia r1!, {r9 - r12, r14}
  63. ldmia r2!, {r9 - r12, r14}
  64. stmia r1!, {r9 - r12, r14}
  65. cmp r2, r3
  66. blo 1b
  67. mov sp, r1
  68. add sp, sp, #128 @ relocate the stack
  69. bl cache_clean_flush
  70. ARM( add pc, r5, r0 ) @ call relocation code
  71. THUMB( add r12, r5, r0 )
  72. THUMB( mov pc, r12 ) @ call relocation code
  73. /*
  74. * We're not in danger of overwriting ourselves. Do this the simple way.
  75. *
  76. * r4 = kernel execution address
  77. * r7 = architecture ID
  78. */

  1. wont_overwrite:

  1. mov r0, r4 @ 解压后的内核开始位置
  2. mov r3, r7 @ 结构ID
  3. bl decompress_kernel @ 这个是跳转到arch/arm/boot/compressed/misc.c的
  4. @ decompress_kernel 函数
  5. b call_kernel @ 解压完毕调用这个
  6. .align 2
  7. .type LC0, #object

  1. LC0:

  1. .word LC0 @ r1
  2. .word __bss_start @ r2
  3. .word _end @ r3
  4. .word zreladdr @ r4
  5. .word _start @ r5
  6. .word _image_size @ r6
  7. .word _got_start @ r11
  8. .word _got_end @ ip
  9. .word user_stack+4096 @ sp

  1. LC1:

  1. .word reloc_end - reloc_start
  2. .size LC0, . - LC0
  3. ......
  4. /*
  5. * Turn on the cache. We need to setup some page tables so that we
  6. * can have both the I and D caches on.
  7. *
  8. * We place the page tables 16k down from the kernel execution address,
  9. * and we hope that nothing else is using it. If we're using it, we
  10. * will go pop!
  11. *
  12. * On entry,
  13. * r4 = kernel execution address
  14. * r7 = architecture number
  15. * r8 = atags pointer
  16. * r9 = run-time address of "start" (???)
  17. * On exit,
  18. * r1, r2, r3, r9, r10, r12 corrupted
  19. * This routine must preserve:
  20. * r4, r5, r6, r7, r8
  21. */
  22. .align 5

  1. cache_on:

  1. mov r3, #8 @ cache_on function
  2. b call_cache_fn
  3. ......
  4. /*
  5. * Here follow the relocatable cache support functions for the
  6. * various processors. This is a generic hook for locating an
  7. * entry and jumping to an instruction at the specified offset
  8. * from the start of the block. Please note this is all position
  9. * independent code.
  10. *
  11. * r1 = corrupted
  12. * r2 = corrupted
  13. * r3 = block offset value和mask各占了4byte,
  14. * 所以在cache_on标签处被赋值为8,
  15. * 用于偏移到函数跳转的位置,具体看代码
  16. * r9 = corrupted
  17. * r12 = corrupted
  18. */

  1. call_cache_fn:

  1. adr r12, proc_types
  2. #ifdef CONFIG_CPU_CP15
  3. mrc p15, 0, r9, c0, c0 @ get processor ID
  4. #else
  5. ldr r9, =CONFIG_PROCESSOR_ID
  6. #endif
  7. /*上面找到processor ID放入 r9 , 下面标号1的代码循环调用,在proc_types中
  8. 查找和processor ID匹配的cache函数,找到后即调用
  9. */
  10. 1: ldr r1, [r12, #0] @ get value
  11. ldr r2, [r12, #4] @ get mask
  12. eor r1, r1, r9 @ (real ^ match)
  13. tst r1, r2 @ & mask
  14. /*若eq(匹配成功),跳到cache函数*/
  15. ARM( addeq pc, r12, r3 ) @ call cache function
  16. THUMB( addeq r12, r3 )
  17. THUMB( moveq pc, r12 ) @ call cache function
  18. add r12, r12, #4*5
  19. b 1b @ proc_types 是一个列表,要一个一个匹配,跳回标号1,匹配下一个
  20. /*
  21. * Table for cache operations. This is basically:
  22. * - CPU ID match
  23. * - CPU ID mask
  24. * - 'cache on' method instruction
  25. * - 'cache off' method instruction
  26. * - 'cache flush' method instruction
  27. *
  28. * We match an entry using: ((real_id ^ match) & mask) == 0
  29. *
  30. * Writethrough caches generally only need 'on' and 'off'
  31. * methods. Writeback caches _must_ have the flush method
  32. * defined.
  33. */
  34. .align 2
  35. .type proc_types,#object

  1. proc_types:

  1. .word 0x41560600 @ ARM6/610
  2. .word 0xffffffe0
  3. W(b) __arm6_mmu_cache_off @ works, but slow
  4. W(b) __arm6_mmu_cache_off
  5. mov pc, lr
  6. ......
  7. ... @ ARM7/710
  8. mov pc, lr
  9. ... @ ARM720T (writethrough)
  10. mov pc, lr
  11. ......这里忽略一些项
  12. @ These match on the architecture ID
  13. @ 这个是匹配ARMv4T的,如ARM920Ts3c2440等等
  14. .word 0x00020000 @ ARMv4T
  15. .word 0x000f0000
  16. W(b) __armv4_mmu_cache_on
  17. W(b) __armv4_mmu_cache_off
  18. W(b) __armv4_mmu_cache_flush
  19. ......这里忽略一些项
  20. /*目前我使用S5PV210是cortexA8的cpu,v7架构,匹配这个
  21. 上面的语句addeq pc, r12, r3将跳转到__armv7_mmu_cache_on,
  22. 因为r3事先被赋值为8。
  23. */
  24. .word 0x000f0000 @ new CPU Id 4 字节
  25. .word 0x000f0000 @ 4 字节
  26. W(b) __armv7_mmu_cache_on @ r12 偏移 r3 后,是这里
  27. W(b) __armv7_mmu_cache_off @ 在内核解压完毕,r3会被赋值为12,即调用这个
  28. W(b) __armv7_mmu_cache_flush @ 在内核解压完毕,r3会被赋值为16,即调用这个
  29. .word 0 @ unrecognised type
  30. .word 0
  31. mov pc, lr
  32. ......

  1. __setup_mmu:

  1. sub r3, r4, #16384 @ Page directory size 16384 是16K
  2. /*上面r4是zreladdr 内核执行地址*/
  3. bic r3, r3, #0xff @ Align the pointer 16K对齐
  4. bic r3, r3, #0x3f00 
  5.         /*为了容易理解注释,这里假设对齐后 r3 = 0x50004000*/
  6. /*
  7. * Initialise the page tables, turning on the cacheable and bufferable
  8. * bits for the RAM area only.
  9. */
  10. mov r0, r3 @ r0 = 0x50004000
  11. mov r9, r0, lsr #18 @ r0 先 lsr(逻辑右移)18位,再mov给r9
  12. mov r9, r9, lsl #18 @ r9 先 lsl(逻辑左移)18位,再mov给r9 = 0x50000000
  13. @ start of RAM
  14. add r10, r9, #0x10000000 @ a reasonable RAM size r10 = 0x60000000
  15. /*上面得到r9为256M对齐的地址,作为RAM的开始地址,r10作为RAM的结束地址*/
  16. /* r9 = 0x50004000 r10 = 0x50008000*/

  17. mov r1, #0x12 @ r1 = 0b 0000 0000 0001 0010
  18. orr r1, r1, #3 << 10 @ r1 = 0b 0000 1100 0001 0010 = 0xC12
  19. add r2, r3, #16384 @ r2 = 0x 5000 8000
  20.        /*下面一个循环,把虚拟空间的256MB映射的页表项 设置 缓存和写缓存*/
  21. 1: cmp r1, r9 @ if virt > start of RAM
  22. orrhs r1, r1, #0x0c @ set cacheable, bufferable
  23. cmp r1, r10 @ if virt > end of RAM
  24. bichs r1, r1, #0x0c @ clear cacheable, bufferable
  25. str r1, [r0], #4 @ 1:1 mapping
  26. add r1, r1, #1048576 @ 判断下一个 1M 的节区
  27. teq r0, r2
  28. bne 1b
for(r0=0x50004000,r1=0xc12; r0!=0x50008000; r0+=4,r1+=0x100000)
{
if(r1 > 0x50000000)
r1 = r1 or 0x0c; // 0xC12 -> 0xC1E 第2、3个bit为1,即set cacheable, bufferable
if(r1 > 0x60000000)
r1 = r1 xor 0x0c; // 0xC1E -> 0xC12 这样,从0x50000000到0x60000000的虚拟地址为cacheable, bufferable
*r0 = r1; // 把虚拟地址值直接写入到对应的页表物理空间
}
  1. /*
  2. * If ever we are running from Flash, then we surely want the cache
  3. * to be enabled also for our execution instance... We map 2MB of it
  4. * so there is no map overlap problem for up to 1 MB compressed kernel.
  5. * If the execution is in RAM then we would only be duplicating the above.
  6. */
  7. mov r1, #0x1e
  8. orr r1, r1, #3 << 10
  9. mov r2, pc, lsr #20
  10. orr r1, r1, r2, lsl #20
  11. add r0, r3, r2, lsl #2
  12. str r1, [r0], #4
  13. add r1, r1, #1048576
  14. str r1, [r0]
  15. mov pc, lr
  16. ENDPROC(__setup_mmu)

  1. __armv4_mmu_cache_on:

  1. mov r12, lr @ 保存返回地址到r12,因为下面调用bl __setup_mm
  2. @ 时会将返回地址lr更新掉
  3. #ifdef CONFIG_MMU
  4. bl __setup_mmu
  5. mov r0, #0
  6. /* 利用cp15将所有写缓冲的内容更新到内存,并清除指令缓存I-Cache
  7. 和数据缓存D-Cache、TLB等
  8. 读取CP15的控制寄存器内容,设置指令缓存激活位、RoundRobin缓存交替
  9. 策略激活位。这部分参考ARM Linux内核源码剖析
  10. mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
  11. mcr p15, 0, r0, c8, c7, 0 @ flush I,D TLBs
  12. mrc p15, 0, r0, c1, c0, 0 @ read control reg
  13. orr r0, r0, #0x5000 @ I-cache enable, RR cache replacement
  14. orr r0, r0, #0x0030
  15. #ifdef CONFIG_CPU_ENDIAN_BE8
  16. orr r0, r0, #1 << 25 @ big-endian page tables
  17. #endif
  18. /*__common_mmu_cache_on子程序使用了上面变更的域设置和“指令缓存”激活
  19. 、缓存循环交替策略。同时将页目录的起始地址值存入CP15专用寄存器
  20. */
  21. bl __common_mmu_cache_on
  22. @ 清除指令缓存、数据缓存、TLB
  23. mov r0, #0
  24. mcr p15, 0, r0, c8, c7, 0 @ flush I,D TLBs
  25. #endif
  26. mov pc, r12 @返回

  1. __armv7_mmu_cache_on:

  1. mov r12, lr
  2. #ifdef CONFIG_MMU
  3. mrc p15, 0, r11, c0, c1, 4 @ read ID_MMFR0
  4. tst r11, #0xf @ VMSA
  5. blne __setup_mmu
  6. mov r0, #0
  7. mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
  8. tst r11, #0xf @ VMSA
  9. mcrne p15, 0, r0, c8, c7, 0 @ flush I,D TLBs
  10. #endif
  11. mrc p15, 0, r0, c1, c0, 0 @ read control reg
  12. orr r0, r0, #0x5000 @ I-cache enable, RR cache replacement
  13. orr r0, r0, #0x003c @ write buffer
  14. #ifdef CONFIG_MMU
  15. #ifdef CONFIG_CPU_ENDIAN_BE8
  16. orr r0, r0, #1 << 25 @ big-endian page tables
  17. #endif
  18. orrne r0, r0, #1 @ MMU enabled
  19. movne r1, #-1
  20. mcrne p15, 0, r3, c2, c0, 0 @ load page table pointer
  21. mcrne p15, 0, r1, c3, c0, 0 @ load domain access control
  22. #endif
  23. mcr p15, 0, r0, c1, c0, 0 @ load control register
  24. mrc p15, 0, r0, c1, c0, 0 @ and read it back
  25. mov r0, #0
  26. mcr p15, 0, r0, c7, c5, 4 @ ISB
  27. mov pc, r12
  28. ......

  1. __common_mmu_cache_on:

  1. #ifndef CONFIG_THUMB2_KERNEL
  2. #ifndef DEBUG
  3. orr r0, r0, #0x000d @ Write buffer, mmu
  4. #endif
  5. mov r1, #-1
  6. mcr p15, 0, r3, c2, c0, 0 @ load page table pointer
  7. mcr p15, 0, r1, c3, c0, 0 @ load domain access control
  8. b 1f
  9. .align 5 @ cache line aligned
  10. 1: mcr p15, 0, r0, c1, c0, 0 @ load control register
  11. mrc p15, 0, r0, c1, c0, 0 @ and read it back to
  12. sub pc, lr, r0, lsr #32 @ properly flush pipeline
  13. #endif

  1. call_kernel:

  1. bl cache_clean_flush @清理缓存
  2. bl cache_off @关闭缓存
  3. mov r0, #0 @ must be zero
  4. mov r1, r7 @ restore architecture number
  5. mov r2, r8 @ restore atags pointer
  6. mov pc, r4 @ call kernel r4是解压后的内核开始地址
    
    
  1. /*
  2. * Clean and flush the cache to maintain consistency.
  3. *
  4. * On exit,
  5. * r1, r2, r3, r9, r11, r12 corrupted
  6. * This routine must preserve:
  7. * r0, r4, r5, r6, r7
  8. */
  9. .align 5

  1. cache_clean_flush:

  1. mov r3, #16 @ 在调用cache函数时,通过r3=16,偏移16字节,即调用
  2. b call_cache_fn
     
     
  1. /*
  2. * Turn off the Cache and MMU. ARMv3 does not support
  3. * reading the control register, but ARMv4 does.
  4. *
  5. * On exit, r0, r1, r2, r3, r9, r12 corrupted
  6. * This routine must preserve: r4, r6, r7
  7. */
  8. .align 5

  1. cache_off:

  1. mov r3, #12 @ cache_off function 在调用cache函数时,通过r3=12,偏移12字节,即调用
  2. b call_cache_fn
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值