历史上的今天
返回首页

历史上的今天

今天是:2024年12月26日(星期四)

正在发生

2019年12月26日 | arm-linux启动过程

2019-12-26 来源:eefocus

     1. kernel运行的史前时期和内存布局

     在 arm平台下,zImage.bin压缩镜像是由bootloader加载到物理内存,然后跳到zImage.bin里一段程序,它专门于将被压缩的 kernel解压缩到KERNEL_RAM_PADDR开始的一段内存中,接着跳进真正的kernel去执行。该kernel的执行起点是stext函数,定义于arch/arm/kernel/head.S。


     1在分析stext函数前,先介绍此时内存的布局如下图所示

     在开发板tqs3c2440中,SDRAM连接到内存控制器的Bank6中,它的开始内存地址是0x30000000,大小为64M,即 0x20000000。 arm Linux kernel将SDRAM的开始地址定义为PHYS_OFFSET。经bootloader加载kernel并由自解压部分代码运行后,最终kernel 被放置到KERNEL_RAM_PADDR(=PHYS_OFFSET + TEXT_OFFSET,即0x30008000)地址上的一段内存,经此放置后,kernel代码以后均不会被移动。


     1在进入kernel代码前,即bootloader和自解压缩阶段,arm未开启MMU功能。因此kernel启动代码一个重要功能是设置好相应的页表,并开启MMU功能。为了支持MMU功能,kernel镜像中的所有符号,包括代码段和数据段的符号,在链接时都生成了它在开启MMU时,所在物理内存地址映射到的虚拟内存地址。


     1以arm kernel第一个符号(函数)stext为例,在编译链接,它生成的虚拟地址是0xc0008000,而放置它的物理地址为0x30008000(还记得这是PHYS_OFFSET+TEXT_OFFSET吗?)。实际上这个变换可以利用简单的公式进行表示:va = pa – PHYS_OFFSET + PAGE_OFFSET。arm linux最终的kernel空间的页表,就是按照这个关系来建立。


     之所以较早提及arm linux 的内存映射,原因是在进入kernel代码,里面所有符号地址值为清一色的0xCXXXXXXX地址,而此时arm未开启MMU功能,故在执行stext 函数第一条执行时,它的PC值就是stext所在的内存地址(即物理地址,0x30008000)。因此,下面有些代码,需要使用地址无关技术。


     2.一览stext函数

     stext函数定义在Arch/arm/kernel/head.S,它的功能是获取处理器类型和机器类型信息,并创建临时的页表,然后开启MMU功能,并跳进第一个C语言函数start_kernel。

     stext函数的在前置条件是:MMU, D-cache, 关闭; r0 = 0, r1 = machine nr, r2 = atags prointer.

     代码如下:


  1.   .section ".text.head", "ax" 


  2. (stext) 


  3. /* 设置CPU运行模式为SVC,并关中断 */ 


  4.   msr  cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode 


  5.                                      @ and irqs disabled 


  6.   mrc p15, 0, r9, c0, c0        @ get processor id 


  7.   bl    __lookup_processor_type         @ r5=procinfo r9=cupid 


  8. /* r10指向cpu对应的proc_info记录 */ 


  9.    movs  r10, r5                         @ invalid processor (r5=0)? 


  10.   beq __error_p                    @ yes, error 'p' 


  11.   bl    __lookup_machine_type            @ r5=machinfo 


  12. /* r8 指向开发板对应的arch_info记录 */ 


  13.    movs  r8, r5                           @ invalid machine (r5=0)? 


  14.   beq __error_a                    @ yes, error 'a' 


  15. /* __vet_atags函数涉及bootloader造知kernel物理内存的情况,我们暂时不分析它。 */ 


  16.   bl    __vet_atags 


  17. /*  创建临时页表 */ 


  18.   bl    __create_page_tables 




  19.   /*


  20.    * The following calls CPU specific code in a position independent


  21.    * manner.  See arch/arm/mm/proc-*.S for details.  r10 = base of


  22.    * xxx_proc_info structure selected by __lookup_machine_type


  23.    * above.  On return, the CPU will be ready for the MMU to be


  24.    * turned on, and r0 will hold the CPU control register value.


  25.    */ 


  26. /* 这里的逻辑关系相当复杂,先是从proc_info结构中的中跳进__arm920_setup函数,


  27.   * 然后执__enable_mmu 函数。最后在__enable_mmu函数通过mov pc, r13来执行__switch_data,


  28.   * __switch_data函数在最后一条语句,鱼跃龙门,跳进第一个C语言函数start_kernel。

  29.    */ 


  30.   ldr   r13, __switch_data             @ address to jump to after 


  31.                                      @ mmu has been enabled 


  32.   adr  lr, __enable_mmu        @ return (PIC) address 


  33.   add pc, r10, #PROCINFO_INITFUNC 


  34. OC(stext) 


     3 __lookup_processor_type 函数

     __lookup_processor_type 函数是一个非常讲究技巧的函数,如果你将它领会,也将领会kernel了一些魔法。


     Kernel 代码将所有CPU信息的定义都放到.proc.info.init段中,因此可以认为.proc.info.init段就是一个数组,每个元素都定义了一个或一种CPU的信息。目前__lookup_processor_type使用该元素的前两个字段cpuid和mask来匹配当前CPUID,如果满足 CPUID & mask == cpuid,则找到当前cpu的定义并返回。


     下面是tqs3c2440开发板,CPU的定义信息,cpuid = 0x41009200,mask = 0xff00fff0。如果是码是运行在tqs3c2440开发板上,那么函数返回下面的定义:


  1.        .section ".proc.info.init", #alloc, #execinstr 




  2.        .type       __arm920_proc_info,#object 


  3. __arm920_proc_info: 


  4.        .long       0x41009200 


  5.        .long       0xff00fff0 


  6.        .long   PMD_TYPE_SECT |  


  7.               PMD_SECT_BUFFERABLE |  


  8.               PMD_SECT_CACHEABLE |  


  9.               PMD_BIT4 |  


  10.               PMD_SECT_AP_WRITE |  


  11.               PMD_SECT_AP_READ 


  12.        .long   PMD_TYPE_SECT |  


  13.               PMD_BIT4 |  


  14.               PMD_SECT_AP_WRITE |  


  15.               PMD_SECT_AP_READ 


  16.       /* __arm920_setup函数在stext的未尾被调用,请往回看。*/ 


  17.        b     __arm920_setup 


  18.        .long       cpu_arch_name 


  19.        .long       cpu_elf_name 


  20.        .long       HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB 


  21.        .long       cpu_arm920_name 


  22.        .long       arm920_processor_functions 


  23.        .long       v4wbi_tlb_fns 


  24.        .long       v4wb_user_fns 


  25. #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 


  26.        .long       arm920_cache_fns 


  27. #else 


  28.        .long       v4wt_cache_fns 


  29. #endif 


  30.        .size __arm920_proc_info, . - __arm920_proc_info 


  1. /*

  2. * Read processor ID register (CP#15, CR0), and look up in the linker-built

  3. * supported processor list.  Note that we can't use the absolute addresses

  4. * for the __proc_info lists since we aren't running with the MMU on

  5. * (and therefore, we are not in the correct address space).  We have to

  6. * calculate the offset.

  7. *

  8. *   r9 = cpuid

  9. * Returns:

  10. *   r3, r4, r6 corrupted

  11. *   r5 = proc_info pointer in physical address space

  12. *   r9 = cpuid (preserved)

  13. */  

  14. __lookup_processor_type: 

  15.       /* adr 是相对寻址,它的寻计算结果是将当前PC值加上3f符号与PC的偏移量,

  16.        * 而PC是物理地址,因此r3的结果也是3f符号的物理地址 */ 


  17.        adr  r3, 3f 


  18.       /* r5值为__proc_info_bein, r6值为__proc_ino_end,而r7值为.,

  19.        * 也即3f符号的链接地址。请注意,在链接期间,__proc_info_begin和

  20.        * __proc_info_end以及.均是链接地址,也即虚执地址。

  21.        */ 


  22.        ldmda     r3, {r5 - r7} 


  23.      /* r3为3f的物理地址,而r7为3f的虚拟地址。结果是r3为虚拟地址与物理地址的差值,即PHYS_OFFSET - PAGE_OFFSET。*/ 


  24.        sub  r3, r3, r7                     @ get offset between virt&phys 


  25.      /* r5为__proc_info_begin的物理地址, 即r5指针__proc_info数组的首地址 */ 


  26.        add r5, r5, r3                     @ convert virt addresses to 


  27.      /* r6为__proc_info_end的物理地址 */ 


  28.        add r6, r6, r3                     @ physical address space 


  29.      /* 读取r5指向的__proc_info数组元素的CPUID和mask值 */ 


  30. 1:    ldmia      r5, {r3, r4}                  @ value, mask 


  31.      /* 将当前CPUID和mask相与,并与数组元素中的CPUID比较是否相同

  32.       * 若相同,则找到当前CPU的__proc_info定义,r5指向访元素并返回。

  33.       */ 


  34.        and  r4, r4, r9                     @ mask wanted bits 

推荐阅读

史海拾趣

HBControls公司的发展小趣事
如果电源正常,检查压缩机是否运行。压缩机是冰箱制冷的核心部件,如果压缩机不工作,可能是电机故障或压缩机过热保护启动。
GE公司的发展小趣事
不要将过多电器插在同一插座上,以免电路负载过大导致跳闸或保险丝熔断。
Digi International公司的发展小趣事

Digi International与UR集团达成了战略协议,共同关注铁路、公共汽车和智慧城市等领域的发展。这一合作不仅为公司带来了新的市场机会,也促进了其在智能交通系统领域的业务拓展。通过与UR集团的紧密合作,Digi International的智能铁路解决方案在英国市场上得到了广泛应用,提高了铁路运输的效率和安全性。

EREM公司的发展小趣事

随着电子行业的不断发展,EREM公司也面临着越来越多的挑战。为了保持市场领先地位,EREM投入大量资金进行技术研发,推出了一系列具有创新性的产品。其中,一种新型的高硬度碳化钨合金剪钳因其卓越的耐用性和精度而备受好评。这一技术突破不仅为EREM赢得了更多客户,也进一步巩固了其在电子行业中的地位。

Alpha Semiconductor公司的发展小趣事

随着技术的不断积累和市场的变化,Alpha Semiconductor于1988年开始为OEM厂家设计定制产品。这一转型是公司发展历程中的重要一步,它使得Alpha Semiconductor能够更深入地了解客户需求,提供更加贴合市场需求的产品解决方案。通过不断的创新和改进,Alpha Semiconductor逐渐在半导体市场中树立了良好的口碑。

三环(CCTC)公司的发展小趣事

随着科技的不断进步和市场环境的变化,三环(CCTC)公司认识到科技创新是企业持续发展的关键。因此,公司加大了研发投入力度,引进和培养了一批高素质的研发人才,建立了以博士、硕士为主组成的技术研发团队。同时,公司积极承担并完成多个国家、省级重点科研项目,不断开展新材料、新产品、新技术的研究与创新。这些努力使公司在多个领域取得了突破性的成果,实现了转型升级。

问答坊 | AI 解惑

基于FPGA的直接数字频率合成器的设计和实现

概述   直接数字频率合成技术(Direct Digital Frequency Synthesis,即DDFS,一般简称DDS),是从相 位概念出发直接合成所需要波形的一种新的频率合成技术。目前各大芯片制造厂商都相继推出采用先进 CMOS工艺生产的高性能、多功能的DDS芯 ...…

查看全部问答>

一种偏僻野外的设备供电想法~~

请教下,用风力发电做动力给超级电容充电,然后再用超级电容来供电给很多偏僻野外的设备供电,大家觉得这个方式可靠吗?…

查看全部问答>

基于PID算法的有刷直流电机PWM调速

请问各位:基于PID算法的有刷直流电机PWM调速系统中对有刷直流电机调速用到的算法是模拟 PID控制原理还是增量式PID控制或者别的PID控制原理?能否将PID算法式子告诉我?谢谢各位了!!QQ:286410824…

查看全部问答>

请教VxWorks 下的声卡驱动

谁知道哪个地方可以买到带有Vxworks驱动的声卡?或者哪里可以下载到Vxworks声卡的驱动?…

查看全部问答>

WinCE驱动开发

我刚开始学习WinCE驱动开发,请各位大侠推荐些学习的资料,入门级别的,谢谢。…

查看全部问答>

IAR汇编程序中多次使用RSEG伪指令是什么意思?

如题!IAR汇编程序中多次使用RSEG伪指令是什么意思?IAR汇编程序中多次使用RSEG伪指令是什么意思?IAR汇编程序中多次使用RSEG伪指令是什么意思?IAR汇编程序中多次使用RSEG伪指令是什么意思?…

查看全部问答>

救命啊:EVC中致命的应用程序错误

PC系统为2000,所用工具是EVC3.0 PDA为操作系统为WINCE,PPC2002,所用连接软件是ActiveSync,编译一个没有错误的程序时,在PDA上显示 Application *.EXE has performed an illegal operation and will be shut down .If the problem persists,con ...…

查看全部问答>

关于USB升级的问题

听说STM32F103VCT6的Load是采用串口升级的,那我们设备与外通讯仅仅有USB接口,如果我们用IAP方式进行升级,万一出现意外擦除了,那岂不是很麻烦! 有人碰到这个问题吗?怎么解决呢? 谢谢了!…

查看全部问答>

电压调节问题

请教一个问题,pwm波输出,要实现电压数字可调,电压范围为0~5V ,调节步进为10mv,有什么可行性方案?…

查看全部问答>