u-boot分析3---源码分析

          U-Boot 属于两阶段的 Bootloader,第一阶段的文件为 cpu/arm920t/start.S和board/100ask24x0/lowlevel_init.S,前者是平台相关的,后者是开发板相关的.

1、U-Boot 第一阶段代码分析

(1)硬件设备初始化。

          依次完成如下设置:将 CPU 的工作模式设为管理模式(svc),关闭 WATCHDOG,设置FCLK、HCLK、PCLK 的比例(即设置 CLKDIVN 寄存器),关闭 MMU、CACHE。
          代码都在 cpu/arm920t/start.S 中,注释也比较完善,读者有不明白的地方可以参考前面硬件实验的相关章节。

硬件初始化步骤:

  1. 设SVC模式
  2. 关看门狗
  3. 屏蔽中断
  4. 初始化SDRAM
  5. 设置栈
  6. 配置时钟
  7. 代码(FLASH➡SDRAM)
  8. 清除BSS段
  9. 跳转C函数(start_armboot)
(2)为加载 Bootloader 的第二阶段代码准备 RAM 空间。

         所谓准备 RAM 空间,就是初始化内存芯片,使它可用。对于 S3C2410/S3C2440,通过在 start.S 中调用 lowlevel_init 函数来设置存储控制器,使得外接的 SDRAM 可用。代码在board/100ask24x0/lowlevel_init.S 中。
          lowlevel_init 函数并不复杂,只是要注意这时的代码、数据都只保存在 NOR Flash 上,内存中还没有,所以读取数据时要变换地址。代码如下

129 _TEXT_BASE:
130 .word TEXT_BASE
131
132 .globl lowlevel_init
133 lowlevel_init:
134 /* memory control configuration */
135 /* make r0 relative the current location so that it */
136 /* reads SMRDATA out of FLASH rather than memory ! */
137 ldr r0, =SMRDATA
138 ldr r1, _TEXT_BASE
139 sub r0, r0, r1
140 ldr r1, =BWSCON /* Bus Width Status Controller */
141 add r2, r0, #13*4
142 0:
143 ldr r3, [r0], #4
144 str r3, [r1], #4
145 cmp r2, r0
146 bne 0b
147
148 /* everything is fine now */
149 mov pc, lr
150
151 .ltorg
152 /* the literal pools origin */
153
154 SMRDATA: /* 13 个寄存器的值 */
155 .word ……
156 .word ……

         第 137~139 行进行地址变换,因为这时候内存中还没有数据,不能使用连接程序时确定的地址来读取数据。
         第 137 行中 SMRDATA 表示这 13 个寄存器的值存放的开始地址(连接地址),值为0x33F8xxxx,处于内存中。
         第 138 行获得代码段的起始地址,它就是第 130 行中的“TEXT_BASE”,其值在board/100ask24x0/config.mk 中定义为“TEXT_BASE = 0x33F80000”。
         第 139 行将 0x33F8xxxx 与 0x33F80000 相减,这就是 13 个寄存器值在 NOR Flash 上存放的开始地址。

(3)复制 Bootloader 的第二阶段代码到 RAM 空间中。

         这里将整个 U-Boot 的代码(包括第一、第二阶段)都复制到 SDRAM 中,这在cpu/arm920t/start.S 中实现,如下所示:

164 relocate: /* 将 U-Boot 复制到 RAM 中 */
165 adr r0, _start /* r0:当前代码的开始地址 */
166 ldr r1, _TEXT_BASE /* r1:代码段的连接地址 */
167 cmp r0, r1 /* 测试现在是在 Flash 中还是在 RAM 中 */
168 beq stack_setup /* 如果已经在RAM 中(这通常是调试时直接下载到RAM 中),
				     * 则不需要复制
                     */
169
170 ldr r2, _armboot_start/* _armboot_start 在前面定义,是第一条指令的运行地址 */
171 ldr r3, _bss_start /* 在连接脚本U-Boot.lds中定义,是代码段的结束地址 */
172 sub r2, r3, r2 /* r2 = 代码段长度 */
173 add r2, r0, r2 /* r2 = NOR Flash 上代码段的结束地址 */
174
175 copy_loop:
176 ldmia r0!, {r3-r10} /* 从地址[r0]处获得数据 */
177 stmia r1!, {r3-r10} /* 复制到地址[r1]处 */
178 cmp r0, r2 /* 判断是否复制完毕 */
179 ble copy_loop /* 没复制完,则继续 */
(4)设置好栈。

         栈的设置灵活性很大,只要让 sp 寄存器指向一段没有使用的内存即可。

182 /* Set up the stack */
183 stack_setup:
184 ldr r0, _TEXT_BASE /* _TEXT_BASE 为代码段的开始地址,值为0x33F80000 */
185 sub r0, r0, #CFG_MALLOC_LEN /* 代码段下面,留出一段内存以实现 malloc */
186 sub r0, r0, #CFG_GBL_DATA_SIZE /* 再留出一段内存,存一些全局参数 */
187 #ifdef CONFIG_USE_IRQ
188 sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ) /*
                   IRQ、FIQ 模式的栈 */
189 #endif
190 sub sp, r0, #12 /* 最后,留出 12 字节的内存给 abort 异常,
                     * 往下的内存就都是栈了
                     */
191

         到了这一步,读者可以知道内存的使用情况了,如图所示(图中与上面的划分稍有不同,这是因为在 cpu/arm920t/cpu.c 中的 cpu_init 函数中才真正为 IRQ、FIQ 模式划分了栈)
在这里插入图片描述
         现在,C 函数的运行环境已经完全准备好,通过如下命令直接跳转(这之后,程序才在内存中执行),它将调用 lib_arm/board.c 中的 start_armboot 函数,这是第二阶段的入口点
在这里插入图片描述
在这里插入图片描述
uboot终极目的启动内核:①从FLASH读取内核(nand read.jffs2 0x30007FC0 0x00060000 0x00200000)
②启动内核(bootm 0x30007FC0:目的是不在移动真正的内核)

FLASH上存的内核:uImage = 头部(0x30003FC0) + zImage(真正内核:0x30008000)
头部中含有:加载地址(0x30008000)和入口地址;bootm先读取加载地址,发现真正的内核不在加载地址,就先将真正的内核移动到加载地址,在执行入口地址

bootm的工作:
①根据头部移动内核到真正的地址
②启动内核
在这里插入图片描述
do_bootm_linux的工作:
①设置启动参数(uboot告诉内核一些参数)
②跳到入口地址启动内核
在这里插入图片描述
设置启动参数的步骤

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值