微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM Linux 的启动过程

ARM Linux 的启动过程

时间:11-09 来源:互联网 点击:

  1. ddress.
  2. */
  3. /*r3=((pc>>20)<20)|r7,即取PC以1M向下对齐的地址。R6=pc>>20也即r6=0x300(pgd_idx),
  4. *即PC对所有1M内存空间,在页表中的下标。
  5. *R7值表明该目录项是section,即它映射的大小是1M。故刚好一个目录项就可以映射kernel上的1M空间。
  6. *这个暂时的va=pa映射只建立1M大小内存的,而不需要建立整个kernel镜像范围的映射。
  7. *因为这个va=pa的映射只有当前汇编语言才使用,一量跳进start_kernl后,这将不会用到了。而汇编代码在链接时,
  8. *已将它安排到代码段的最前面了。
  9. movr6,pc,lsr#20@startofkernelsection
  10. orrr3,r7,r6,lsl#20@flags+kernelbase
  11. /*将目录内空写到页表相应位置,即((uint32_t*)r4)[pgd_idx]=r3*/
  12. strr3,[r4,r6,lsl#2]@identitymapping
  13. /*上面代码段为[pc&(~0xfffff),(pc+0xfffff)&(~0xfffff)]的物理内存空间建立了va=pa的映射关系。*/
  14. /*下面为kernel镜像所占有空间,即KERNL_START到KERNEL_END建立内存映射,
  15. *映射关系为:va=pa–PHYS+PAGR_OFFSET。注意,这里的KENEL_START是kernel空间开始的虚拟地址。
  16. *这里的目录表项同样是section,即一个项映射1M的内存。
  17. */
  18. /*KERNEL_START=PAGE_OFFSET+TEXT_OFFSET,
  19. *r0=((uint32_t*)(r4))[(KERNEL_START&0xff000000)>>20],
  20. *即r0指向KERNEL_START&0xff000000(即kernel以16M向下对齐的)虚拟地址,所在项表目录中的位置。
  21. addr0,r4,#(KERNEL_START&0xff000000)>>18
  22. /*r0=((uint32_t*)r0)[(KERNEL_START&0x00f00000)>>20]
  23. *执行前r0指向kernel以16M向下对齐的虚执地址,而这里再加上KERNEL_START未以16M向对齐部分的偏移量。
  24. *将原来r3的值写到页表目录中。R3的值就是之前已建立好va=pa映射的那个PA值。
  25. */
  26. strr3,[r0,#(KERNEL_START&0x00f00000)>>18]!
  27. /*r6为kernel镜像的尾部虚拟地址。*/
  28. ldrr6,=(KERNEL_END-1)
  29. /*指向下一个即将要填写的目录项*/
  30. addr0,r0,#4
  31. /*r6指向KERNEL_END-1虚拟地址所在的目录表项的位置*/
  32. addr6,r4,r6,lsr#18
  33. 1:cmpr0,r6
  34. /*每填一个目录项,后一个比前一个所指向的物理地址大1M。*/
  35. addr3,r3,#1<20
  36. strlsr3,[r0],#4
  37. bls1b
  38. #ifdefCONFIG_XIP_KERNEL
  39. /*忽略,不分析这种情况*/
  40. #endif
  41. /*通常kernel的启动参数由bootloader放到了物理内存的第1个M上,所以需要为RAM上的第1个M建立映射。
  42. *上面已为PHYS_OFFSET+TEXT_OFFSET建立了映射,如果TEXT_OFFSET小于0x00100000的话,
  43. *上面代码应该也为SDRAM的第一个M建立了映射,但如果大于0x0010000则不会。
  44. *所以这里无论如何均为SDRAM的第一个M建立映射(不知分析对否,还请指正)。
  45. */
  46. addr0,r4,#PAGE_OFFSET>>18
  47. orrr6,r7,#(PHYS_OFFSET&0xff000000)
  48. .if(PHYS_OFFSET&0x00f00000)
  49. orrr6,r6,#(PHYS_OFFSET&0x00f00000)
  50. .endif
  51. strr6,[r0]
  52. #ifdefCONFIG_DEBUG_LL
  53. /*略去*/
  54. #ifdefined(CONFIG_ARCH_NETWINDER)||defined(CONFIG_ARCH_CATS)
  55. /*略去*/
  56. #endif
  57. #ifdefCONFIG_ARCH_RPC
  58. /*略去*/
  59. #endif
  60. #endif
  61. movpc,lr
  62. ENDPROC(__create_page_tables)

一口气将__create_pages_table分析完,但里涉及的代码还是需要细细品读。尤其是右移20位和18位两个地方与页表目录项的地址关系比较复杂。执行完该函数后,虚拟内存和物理内存的映射关系如下图所示:

6. 开启MMU

看完页表的建立,想必开启MMU的代码也是小菜一碟吧。此函数的主要功能是将页表的基址加到cp15中的面表指针寄存器,同时设置域访问(domain access)寄存器。

[cpp]view plaincopy

  1. /*
  2. *SetupcommonbitsbeforefinallyenablingtheMMU.Essentially
  3. *thisisjustloadingthepagetablepointeranddomainaccess
  4. *registers.
  5. */
  6. __enable_mmu:
  7. /*这里设置是否为非对齐内存访问产生异常*/
  8. #ifdefCONFIG_ALIGNMENT_TRAP
  9. orrr0,r0,#CR_A
  10. #else
  11. bicr0,r0,#CR_A
  12. #endif
  13. /*是否禁用数据缓存功能*/
  14. #ifdefCONFIG_CPU_DCACHE_DISABLE
  15. bicr0,r0,#CR_C
  16. #endif
  17. /*是否禁用CPU_BPREDICT?,不是很清楚此选项*/
  18. #ifdefCONFIG_CPU_BPREDICT_DISABLE
  19. bicr0,r0,#CR_Z
  20. #endif
  21. /*是否禁用指令缓存功能*/
  22. #ifdefCONFIG_CPU_ICACHE_DISABLE
  23. bicr0,r0,#CR_I
  24. #endif
  25. /*设置域访问寄存器的值。这里设置每个domain的属性是否上面建立的页表中,
  26. *每个目录项的damon值一起进行访问控制检查。具体情况请参考ARM处理器手册。
  27. */
  28. movr5,#(domain_val(DOMAIN_USER,DOMAIN_MANAGER)|\
  29. domain_val(DOMAIN_KERNEL,DOMAIN_MANAGER)|\
  30. domain_val(DOMAIN_TABLE,DOMAIN_MANAGER)|\
  31. domain_val(DOMAIN_IO,DOMAIN_CLIENT))
  32. mcrp15,0,r5,c3,c0,0@loaddomainaccessregister
  33. mcrp15,0,r4,c2,c0,0@loadpagetablepointer
  34. b__turn_mmu_on
  35. ENDPROC(__enable_mmu)
  36. /*
  37. *EnabletheMMU.Thiscomple

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top