下面进行源码内容的分析及修改:
由上面的分析可以知道,最终将所有obj文件链接生成u-boot可执行文件时,用到了/board/mini2440/u-boot.lds这个链接脚本,查看其内容:
------- /board/mini2440/u-boot.lds -------
24 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
25 /*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
26 OUTPUT_ARCH(arm)
27 ENTRY(_start)
28 SECTIONS
29 {
30 . = 0x00000000;
31
32
33 . = ALIGN(4);
34 .text :
35 {
36 cpu/arm920t/start.o (.text)
37 *(.text)
38 }
...
同时查看u-boot.dis文件:
------- u-boot.dis -------
1
2 u-boot: file format elf32-littlearm
3
4 Disassembly of section .text:
5
6 33f80000 <_start>:
7 33f80000: ea000012 b 33f80050 8 33f80004: e59ff014 ldr pc, [pc, #20] ; 33f80020 <_undefined_instruction> 9 33f80008: e59ff014 ldr pc, [pc, #20] ; 33f80024 <_software_interrupt> 可知代码段中放在最前的是/cpu/arm920t/start.S,同时上电之后最开始执行的标号是/cpu/arm920t/start.S中的_start,因此从这里开始分析。 /cpu/arm920t/start.S: 找到start.S中的_start标号: ------- /cpu/arm920t/start.S ------- 41 .globl _start 42 _start: b reset 43 ldr pc, _undefined_instruction 44 ldr pc, _software_interrupt 45 ldr pc, _prefetch_abort 46 ldr pc, _data_abort 47 ldr pc, _not_used 48 ldr pc, _irq 49 ldr pc, _fiq 50 51 _undefined_instruction: .word undefined_instruction 52 _software_interrupt: .word software_interrupt 53 _prefetch_abort: .word prefetch_abort 54 _data_abort: .word data_abort 55 _not_used: .word not_used 56 _irq: .word irq 57 _fiq: .word fiq 58 59 .balignl 16,0xdeadbeef ... 75 _TEXT_BASE: 76 .word TEXT_BASE 77 78 .globl _armboot_start 79 _armboot_start: 80 .word _start 81 82 /* 83 * These are defined in the board-specific linker script. 84 */ 85 .globl _bss_start 86 _bss_start: 87 .word __bss_start 88 89 .globl _bss_end 90 _bss_end: 91 .word _end 第41行,.global是编译的关键词,告诉编译器这是一个全局可见的名字(可能是变量,也可能是函数名),在这里_start是一个标号(GNU汇编编译器的默认入口标号),用.global关键字将其定义为一个全局可见的标号,以便在编译链接过程中能够找到。 第59行,.balignl表示结束的地址必须为后面第一个参数(16)的整数倍,如果不是整数倍,则进行填充使其达到整数倍,填充的内容为0xdeadbeef,这条指令用于将后面的指令对齐在16的整数倍的地址上。 第75行到第91行,定义一些标号: _TEXT_BASE:TEXT_BASE(0x33F80000); _armboot_start:_start(0x33F80000); _bss_start:__bss_start(u-boot.lds中定义的BSS起始地址); _bss_end:_end(u-boot.lds中定义的BSS结束地址,也是最后的结束地址) _start标号下第一条指令就是跳转指令,b reset指令表示无条件跳转到reset标号继续执行。 后面为S3C2440的7个中断向量地址,并使用跳转指令指向中断服务程序,当发生中断时,程序指针PC会跳转到相应的中断向量,执行中断程序。 找到reset标号: ------- /cpu/arm920t/start.S ------- 106 /* 107 * the actual reset code 108 */ 109 110 reset: 111 /* 112 * set the cpu to SVC32 mode 113 */ reset标号下首先对S3C2440的当前程序状态寄存器(CPSR)进行操作,使芯片工作在超级用户模式下(Supervisor)。 查看S3C2440手册中关于CPSR寄存器的说明: 寄存器高4位是程序运行标志位,低8位是状态控制位,手册中具体说明如下: 第7位——中断禁止位,置1时禁止中断; 第6位——快速中断禁止位,置1时禁止中断; 第5位——芯片运行状态位,置1时运行在THUMB状态下,否则运行在ARM状态下; 第4~0位——运行模式选择位,其模式设置如下: 10000:User Mode,普通用户模式 10001:FIQ Mode,快速中断模式 10010:IRQ Mode,中断模式 10011:Supervisor Mode,超级用户模式 10111:Abort Mode 11011:Undefined Mode 11111:System Mode 使用状态寄存器访问指令MRS和MSR进行访问: MRS:状态寄存器(CPSR或SPSR)内容传送到通用寄存器(Rd) 格式:MRS{ MSR:将操作数(opt)的内容传送到状态寄存器(CPSR或SPSR)的特定域中 格式:MSR{ 位[31:24]为条件标志位域,用f表示; 位[23:16]为状态位域,用s表示; 位[15:8]为扩展位域,用x表示; 位[7:0]为控制位域,用c表示。 其中SPSR为程序状态保存寄存器。 CPSR: Current Program Status Register SPSR: Saved Program Status Register 因此reset标号下的指令: ------- /cpu/arm920t/start.S ------- 110 reset: 111 /* 112 * set the cpu to SVC32 mode 113 */ 114 mrs r0,cpsr 115 bic r0,r0,#0x1f 116 orr r0,r0,#0xd3 117 msr cpsr,r0 首先通过MRS指令将CPSR的值读到R0中,然后在R0中对CPSR的值进行操作,再通过MSR指令将改变后的值写入CPSR中。 其中: BIC{ 清除操作数1(Opt1)中的某些位,并将结果写入目的寄存器(Rd)中,操作数2(Opt2)为32位掩码,掩码中置1的位在操作数1中将会被清0。 ORR{ 将两个操作数进行或运算,并将结果写入目的寄存器(Rd)中,常用于将操作数1的某些位置1。 因此首先将CPSR的值传送到R0中: ------- /cpu/arm920t/start.S ------- 114 mrs r0,cpsr 然后清除R0的低5位: ------- /cpu/arm920t/start.S ------- 115 bic r0,r0,#0x1f 将R0的值或上0b11010010(0xD3),即用于模式选择的低5位[4:0]置为10011,即Supervisor Mode,超级用户模式,并将[7:6]置1,禁止中断: ------- /cpu/arm920t/start.S ------- 116 orr r0,r0,#0xd3 最后再将修改好的值写入CPSR: ------- /cpu/arm920t/start.S ------- 117 msr cpsr,r0 接下来利用宏定义设置和看门狗、中断以及时钟相关的寄存器: ------- /cpu/arm920t/start.S ------- 120 #if defined(CONFIG_S3C2400) 121 # define pWTCON 0x15300000 122 # define INTMSK 0x14400008 /* Interupt-Controller base addresses */ 123 # define CLKDIVN 0x14800014 /* clock divisor register */ 124 #elif defined(CONFIG_S3C2410) 125 # define pWTCON 0x53000000 126 # define INTMSK 0x4A000008 /* Interupt-Controller base addresses */ 127 # define INTSUBMSK 0x4A00001C 128 # define CLKDIVN 0x4C000014 /* clock divisor register */ 129 #endif 添加对S3C2440的支持,添加修改如下,因为S3C2440这4个寄存器的地址与S3C2410一致,所以也可直接在124行添加对S3C2440的判断: ------- /cpu/arm920t/start.S ------- 120 #if defined(CONFIG_S3C2400) 121 # define pWTCON 0x15300000 122 # define INTMSK 0x14400008 /* Interupt-Controller base addresses */ 123 # define CLKDIVN 0x14800014 /* clock divisor register */ 124 #elif defined(CONFIG_S3C2410) 125 # define pWTCON 0x53000000 126 # define INTMSK 0x4A000008 /* Interupt-Controller base addresses */ 127 # define INTSUBMSK 0x4A00001C 128 # define CLKDIVN 0x4C000014 /* clock divisor register */ 129 #elif defined(CONFIG_S3C2440) 130 # define pWTCON 0x53000000 131 # define INTMSK 0x4A000008 /* Interupt-Controller base addresses */ 132 # define INTSUBMSK 0x4A00001C 133 # define CLKDIVN 0x4C000014 /* clock divisor register */ 134 #endif 接下来关闭看门狗: ------- /cpu/arm920t/start.S ------- 136 #if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) 137 ldr r0, =pWTCON 138 mov r1, #0x0 139 str r1, [r0] 屏蔽中断: ------- /cpu/arm920t/start.S ------- 141 /* 142 * mask all IRQs by setting all bits in the INTMR - default 143 */ 144 mov r1, #0xffffffff 145 ldr r0, =INTMSK 146 str r1, [r0] 147 # if defined(CONFIG_S3C2410) 148 ldr r1, =0x3ff 149 ldr r0, =INTSUBMSK 150 str r1, [r0] 151 # endif 以及设置时钟分频: ------- /cpu/arm920t/start.S ------- 153 /* FCLK:HCLK:PCLK = 1:2:4 */ 154 /* default FCLK is 120 MHz ! */ 155 ldr r0, =CLKDIVN 156 mov r1, #3 157 str r1, [r0] 158 #endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */ S3C2440的看门狗、中断设置与S3C2410相似,具体操作见S3C2440数据手册。但两者时钟设置上稍微有些区别,S3C2440内部有两个锁相环(PLL),一个用于FCLK、HCLK、PCLK,另一个用于USB模块(通常设置为48MHz)。FCLK即为CPU运行频率,HCLK用于AHB总线上的外设,PCLK用于APB总线上的外设。 S3C2440通过MPLLCON与UPLLCON两个寄存器来设置时钟频率(注意如果要同时设置MPLL与UPLL时,应该先设置UPLL,中间间隔大约7个时钟周期,然后再设置MPLL): 在刚上电时钟频率默认为晶振频率,即12MHz,通过设置时钟倍频,获得实际工作的时钟频率,计算公式如下,其中Fin在这里为晶振频率,即12MHz,MPLL计算的结果即为FCLK的值,而S3C2410的MPLL计算略有不同(MPLL少乘一个2): S3C2440通过CLKDIVN寄存器设置FCLK、HCLK、PLCK的分频: 并且,在HDIVN不为0时,需要将CPU的总线模式从快速总线模式改变为其他模式,而S3C2440不支持同步总线模式,因此将其设置为异步总线模式,否则CPU将按HCLK的频率运行: 在ARM920T的技术手册中有详细说明,ARM处理器使用协处理器15(CP15)的寄存器来控制cache、TCM和MMU等,CP15包含了编号为0~15的共16个32位的寄存器,其中总线模式控制在寄存器1(Register 1, control register),其说明与访问指令如下: 总线模式的控制位是第[31:30]位,设置方式如下: 因此,根据上述分析进行修改,首先添加对S3C2440的支持: ------- /cpu/arm920t/start.S ------- 136 #if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) 看门狗的设置与S3C2410一致,不需要修改。中断屏蔽寄存器INTMSK的设置也一致,而S3C2440的中断子屏蔽寄存器INTSUBMSK中位[14:0]均需要进行屏蔽,添加修改如下: ------- /cpu/arm920t/start.S ------- 151 # elif defined(CONFIG_S3C2440) 152 ldr r1, =0x7fff 153 ldr r0, =INTSUBMSK 154 str r1, [r0] 由于S3C2440的时钟设置与S3C2410不同,同时为了后续程序(SDRAM等)的设置,将S3C2440的时钟频率FCLK设置为200MHz,且分频比为1:2:4,即FCLK : HLCK : PCLK=200MHz : 100MHz : 50MHz,因此添加修改: ------- /cpu/arm920t/start.S ------- 157 # if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) 158 /* FCLK:HCLK:PCLK = 1:2:4 */ 159 /* default FCLK is 120 MHz ! */ 160 ldr r0, =CLKDIVN 161 mov r1, #3 162 str r1, [r0] 163 # elif defined(CONFIG_S3C2440) 164 /* FCLK:HCLK:PCLK = 200MHz:100MHz:50MHz */ 165 # define MPLLCON 0x4C000004 166 # define MPLL_200MHz ((0x5C<<12)|(0x01<<4)|(0x02)) 167 ldr r0, =MPLLCON
上一篇:U-Boot-1.1.6移植到MINI2440开发板(4) —— 源码分析第二阶段(1)
下一篇:U-Boot-1.1.6移植到MINI2440开发板(1) —— 移植前分析
推荐阅读

