S3C6410之uboot回炉再造(1)start.S - SVC模式设置
虽然已经写了几篇关于uboot移植的、但是觉得整体对uboot的理解还是只停留在copy的层面。
狠下心来,从代码进行uboot的分析,并从新移植一次uboot。
这次更侧重于记录代码分析心得。
使用uboot的版本仍为2010.3版本。
这里有一个很是详尽的start.S分析网站,分析过程借鉴了网站的方法,但也有一些不同的地方
http://www.crifan.com/files/doc/docbook/uboot_starts_analysis/release/html/uboot_starts_analysis.html
总的不同有如下
在网站的分析中,基于代码为arm920t,即ARM9系列芯片,ARM9系列芯片的初始化过程为:
1、设置CPU模式 2、关闭看门狗 3、关闭中断 4、设置堆栈sp指针 5、清除bss段 6、异常中断处理
然后我现在选择的修改模板是arm1176,即ARM11系列芯片,ARM11系列芯片的初始化过程为:
1、设置CPU模式 // -- 关闭看门狗 // -- 关闭中断 2、初始化MMU // ++ 3、设置堆栈sp指针 4、清除bss段 5、异常中断处理
两种芯片的start.S的区别一目了然。
接着开始分析代码了。
一切的开始:start.S (文件路径为/cpu/arm1176/start.S)
为了方便跳转阅读,启用行号。
为避免误导,在此说明:
此时我使用的是未经修改的uboot2010版本的start.S,在这篇分析中不会对它进行任何修改。
在随后的blog中才对start.S进行修改并阐述理由,修改处必有类似 git diff 的说明
1、头文件
1 /* 2 * …… 3 */ 4 5 #include <config.h> 6 #include <version.h> 7 #ifdef CONFIG_ENABLE_MMU 8 #include <asm/proc/domain.h> 9 #endif 10 #include <asm/arch/s3c6410.h> 11 12 #if !defined(CONFIG_ENABLE_MMU) && !defined(CONFIG_SYS_PHY_UBOOT_BASE) 13 #define CONFIG_SYS_PHY_UBOOT_BASE CONFIG_SYS_UBOOT_BASE 14 #endif
头文件部分不必赘述,但是这里有一个不得不说的地方
13 #define CONFIG_SYS_PHY_UBOOT_BASE CONFIG_SYS_UBOOT_BASE
为了解析这个定义,找到了 /include/configs/smdk6400.h
/* NAND U-Boot load and start address */ #define CONFIG_SYS_UBOOT_BASE (CONFIG_SYS_MAPPED_RAM_BASE + 0x07e00000)
继续跳转搜索 CONFIG_SYS_MAPPED_RAM_BASE:
#ifdef CONFIG_ENABLE_MMU #define CONFIG_SYS_MAPPED_RAM_BASE 0xc0000000 #define CONFIG_BOOTCOMMAND "nand read 0xc0018000 0x60000 0x1c0000;" \ "bootm 0xc0018000" #else #define CONFIG_SYS_MAPPED_RAM_BASE CONFIG_SYS_SDRAM_BASE #define CONFIG_BOOTCOMMAND "nand read 0x50018000 0x60000 0x1c0000;" \ "bootm 0x50018000" #endif
很显然了,在MMU工作的状态下:
#define CONFIG_SYS_MAPPED_RAM_BASE 0xc0000000
MMU工作就是开发板播到从NAND flash启动的状态。
而在MMU未工作的状态下:
#define CONFIG_SYS_MAPPED_RAM_BASE CONFIG_SYS_SDRAM_BASE .... #define CONFIG_SYS_SDRAM_BASE 0x50000000
从这里,可以理解在使用dnw下载的时候,Download Address为
#define CONFIG_SYS_UBOOT_BASE (CONFIG_SYS_MAPPED_RAM_BASE + 0x07e00000) // 0x5000000 + 0x07e00000 = 0x57e00000
uboot是bootloader的一种,要更为准确地描述这两种状态可以说为
1、启动加载(Boot loading)模式,即自主"(Autonomous)模式;
2、下载(Downloading)模式。
更为详细的描述可以参详
http://blog.csdn.net/r91987/article/details/6695007
接下来进入正文分析了
1 /* 2 ************************************************************************* 3 * 4 * Jump vector table as in table 3.1 in [1] 5 * 6 ************************************************************************* 7 */ 8 9 .globl _start 10 _start: b reset //跳转到reset处执行,即下一段代码的44行 //但此时不必急着看reset的执行代码,可以继续顺序往下 11 #ifndef CONFIG_NAND_SPL //定义NAND_SPL时 12 ldr pc, _undefined_instruction //ldr = Load Register 13 ldr pc, _software_interrupt //软件中断 14 ldr pc, _prefetch_abort //预取指中止 15 ldr pc, _data_abort //数据中止 16 ldr pc, _not_used //保留 17 ldr pc, _irq //IRQ中断 18 ldr pc, _fiq //FIQ中断 19 //这里的七种异常就是ARM的七种异常处理类型,对应的声明在 20 - 33行 20 _undefined_instruction: //.word = 32bit , 这里可以理解为 _undef.. = &undef.. 21 .word undefined_instruction //这里将地址放入 _undef.. ,而_undef的地址又放入pc 22 _software_interrupt: //双层取址,所以最终送入pc的数据为 undefined_instruction 23 .word software_interrupt //以下含义相同 24 _prefetch_abort: 25 .word prefetch_abort //pc 是 ARM 的指令寄存器 26 _data_abort: //将这些异常送入 pc ,意为让 ARM 运行这些指令的初始化代码(后文可见) 27 .word data_abort 28 _not_used: 29 .word not_used 30 _irq: 31 .word irq 32 _fiq: 33 .word fiq 34 _pad: 35 .word 0x12345678 /* now 16*4=64 */ 36 #else 37 . = _start + 64 38 #endif 39 40 .global _end_vect 41 _end_vect: 42 .balignl 16,0xdeadbeef // .balignl 为对其指令,意为让以下的代码按16位对其 //不足为则补上0xdeadbeef //很有意思的dead beef,为数不多的能用16进制表示的单词
接下来为正式的启动指令了
1 /* 2 ************************************************************************* 3 * 4 * Startup Code (reset vector) 5 * 6 * do important init only if we don't start from memory! 7 * setup Memory and board specific bits prior to relocation. 8 * relocate armboot to ram 9 * setup stack 10 * 11 ************************************************************************* 12 */ 13 14 _TEXT_BASE: 15 .word TEXT_BASE //这里是 .text 的 base ,即代码段的基址 16 17 /* 18 * Below variable is very important because we use MMU in U-Boot. 19 * Without it, we cannot run code correctly before MMU is ON. 20 * by scsuh. 21 */ 22 _TEXT_PHY_BASE: //上面的注释很清晰了 23 .word CONFIG_SYS_PHY_UBOOT_BASE 24 25 .globl _armboot_start //此处声明了 _armboot_start 指向 _start 26 _armboot_start: 27 .word _start 28 29 /* 30 * These are defined in the board-specific linker script. 31 */ 32 .globl _bss_start //此处的标号其实最终指向的是链接脚本文件(.lds)中的定义 33 _bss_start: 34 .word __bss_start 35 36 .globl _bss_end //同上 37 _bss_end: 38 .word _end 39 40 /* 41 * the actual reset code 42 */ 43 44 reset: //这里就是start之后跳转的地方了 45 /* 46 * set the cpu to SVC32 mode 47 */ //SVC模式也成为管理模式,是操作系统的一种保护模式 48 mrs r0, cpsr //mrs为读寄存器指令 49 bic r0, r0, #0x3f //清除r0的低7位 50 orr r0, r0, #0xd3 //将r0置为0b1101_0011,我们只看低5位 51 msr cpsr, r0 //查CPSR处理器模式位知SVC模式位就是0b1_0011
至此,CPU的SVC模式设置成功了。
最后补充一个内容,.lds文件是编译脚本文件,展开可以看成ld script。
这里的 ld 对应于编译器的 arm-linux-ld。
有关于.lds文件的说明,可以参阅
http://blog.csdn.net/pottichu/article/details/4261289
在后面的篇幅中,也会涉及.lds文件的修改。