作者 : 韩曙亮
博客地址 : http://blog.csdn.net/shulianghan/article/details/42462795
转载请著名出处
相关资源下载 :
-- u-boot 源码 : http://download.csdn.net/detail/han1202012/8342761
-- S3C2440 文档 : http://download.csdn.net/detail/han1202012/8342701
-- S5PV210_iROM_ApplicationNote_Preliminary_20091126 文档 : http://download.csdn.net/detail/han1202012/8342709
-- S3C6410_Internal_ROM_Bootin 文档 : http://download.csdn.net/detail/han1202012/8342725
-- S3C6410X 文档 : http://download.csdn.net/detail/han1202012/8342731
-- S5PV210_UM_REV1.1 文档 : http://download.csdn.net/detail/han1202012/8342745
一. Bootloader 简介
1. Bootloader 简介
Bootloader 作用 : 启动系统时将 Kernel 带入到内存中, 之后 Bootloader 就没有用处了;
-- Bootloader 在 Linux 系统中的层次 : Bootloader --> Boot parameters --> Kernel --> root filesystems;
-- 最常用的 bootloader : uboot 是 bootloader 中最优秀的;
uboot 简介 :
-- 支持 CPU : MIPS, x86, ARM 等;
-- 引导的系统 : Linux, Android, VxWorks, QNX;
uboot 模式 :
-- 自主模式 : 如果开机, 我们什么操作都不做就是自主模式;
-- 开发模式 : 开机后立刻按下 空格键, 会进入 uboot 的命令行模式, 即开发模式;
2. 使用 Source Insight 阅读 uboot 源码
Source Insight 使用流程 :
-- 创建工程 : "菜单栏" --> "Project" --> New Project 弹出下面的对话框, 在对话框中输入代码的保存路径 和 工程名;
-- 每个工程有自己的文件 : 点击 OK 后, 在下面的对话框选择第一个选项, 其它默认;
-- 弹出选择源码界面 : 这里现在这里暂停下, 也可以关掉, 从 "菜单" --> "Project" --> "Add and Remove Project Files";
-- 解压 uboot 源码 : 使用 Samba 文件共享, 将 uboot 源码在 linux 目录下解压, 由于编码和文件系统特性, 在 windows 目录下解压会出错, 通过 直接在 Samba 用户目录下解压;
- [root@localhost arm]# cd /home/samba/
- [root@localhost samba]# ls
- ARM-tools uboot.tar.gz
- [root@localhost samba]#
- [root@localhost samba]#
- [root@localhost samba]# tar -xvzf uboot.tar.gz
- uboot/
- uboot/README
-
- ... ...
-- 映射网络驱动器 : 复制 Samba 中存放 uboot 源码的共享文件路径为 "\\192.168.0.111\samba\uboot", 打开 "我的电脑", 选择 "计算机" 菜单;
-- 添加映射地址 : 在映射网络驱动器对话框中, 填入 Samba 目录;
-- 生成了一个 Z 盘 :
-- 导入代码 : 选择 "菜单" --> "Project" --> "Add and Remove Project Files", 在弹出的对话框中选中 uboot 目录, 并进入其跟目录, 选择 右侧 "Add all" 按钮, 在弹出的对话框中选择两个选项都选择, 以便其子目录中的文件也能被加载进入;
-- 查看加载完成的工程 : 发现没有 .S 汇编文件;
-- 加载汇编文件 : 选择 "菜单" --> "Options" --> "Document Options", 在 C Source File 中选择 *.s;*.S, 结果为 "*.c;*.h;*.s;*.S";
-- 继续添加工程文件 : 选择 "菜单" --> "Project" --> "Add and Remove Project file";
-- 此时汇编文件出现了 :
二. ARM 处理器启动流程 (启动方式 | 内存映射 | 启动流程)
1. S3C2440 芯片启动流程
(1) S3C2440 启动方式
2440 启动方式 :
-- Nor Flash : Nor Flash 大小只有 2M;
-- Nand Flash : Nand Flash 大小 256M;
(2) S3C2440 内存映射
内存映射 : S3C2440 文档, Page 221, 第六章 Nand Flash Memory Mapping, 也可以搜索 Mapping 关键词;
-- 左图 : Nor Flash 启动地址映射;
-- 右图 : Nand Flash 启动地址映射;
(3) S3C2440 启动流程
Nor Flash 指令加载 : CPU 上电 读取指令 : 从 0x0 地址读取指令;
Nand Flash 指令加载 :
-- 启动 0 地址 : Nand Flash 不能被直接访问到, 没有参与 ARM 的编址, BootSRAM 是片内的 RAM;
-- BootRAM 简介 : BootSRAM 又名 Setpping stone (垫脚石), Bootloader 最前端 4K 自动复制到 BootRAM, 剩下的 复制到 内存中, 4K 的代码运行完之后会跳转到内存继续执行剩下的代码;
-- 内存地址 : 在下面的 Nand Flash Memory Mapping 图中, s3c2440 芯片内存起始地址是 0x3000_0000;
-- 文档参考 : Page 213, 章节6 Nand Flash Contorller;
- OVERVIEW
- In recent times, NOR flash memory gets high in price while an SDRAM and a NAND flash memory is comparatively
- economical , motivating some users to execute the boot code on a NAND flash and execute the main code on an
- SDRAM.
- S3C2440A boot code can be executed on an external NAND flash memory. In order to support NAND flash boot
- loader, the S3C2440A is equipped with an internal SRAM buffer called ‘Steppingstone’. When booting, the first 4
- KBytes of the NAND flash memory will be loaded into Steppingstone and the boot code loaded into Steppingstone
- will be executed.
- Generally, the boot code will copy NAND flash content to SDRAM. Using hardware ECC, the NAND flash data
- validity will be checked. Upon the completion of the copy, the main program will be executed on the SDRAM.
2. S3C6410 芯片启动流程
(1) S3C6410 启动方式
s3c6410 启动方式介绍 :
-- SROM 启动 : 即 Nor Flash 启动, 6410 也支持 Nor Flash 启动;
-- OneNand 启动 : 特殊的 Nand Flash, 同时具有 Nor Flash 和 Nand Flash 的特性;
-- MODEM 启动 : 详情参考文档;
-- IROM 启动 : IROM 是处理器内部的组件, 该启动方式包括 SD 卡启动 和 Nand Flash 启动;
-- 启动方式文档 : S3C6410X 文档, 搜索关键词 booting, Page 123, 3.3.3 章节;
(2) S3C6410 地址映射
启动设备地址布局 :
-- IROM (Internal ROM) : 0x0800_000 地址, 64M;
-- Stepping Stone (Boot Loader) : 0x0C00_0000 地址, 64M;
-- 地址布局文档 : S3C6410X 文档, Page 116, 2.2 章节, Device Specific Address Space 图表 设备特殊地址空间;
0 地址映射介绍 :
-- 镜像区域 : Booting Device Region by XOM Setting (XOM设置的引导设备区域), 根据不同的启动设置, 将对应的启动设备映射到该区域;
-- IROM 启动 : 会将 IROM 映射到该镜像区域;
-- Nor Flash 启动 : 将 Nor Flash 映射到该镜像区域;
-- 文档参考 : 从上面的文档截图 :
(3) S3C6410 启动流程
启动流程 : S3C6410_Internal_ROM_Booting 文档, Page 6, 2.1 章节;
-- 1. IROM 初始化 : IROM 中固化了软件, 称为 bootloader0, 是 0阶段的 bootloader, 该 BL0 执行 初始化时钟, D-TCM, 设备特殊控制器, 引导设备;
-- 2. 加载 BL1 : 加载 BL1 到 Stepping Stone (垫脚石), 将放在 nand flash 中的 bootloader1 (即 Bootloader 最前面的 8K) 拷贝到 Stepping Stone 中;
-- 3. 执行 BL1 : BL1 初始化系统时钟, UART, SDRAM, Stepping Stone 执行完 8K Bootloader 后, 将剩余的 bootloader (BL2) 拷贝到 SDRAM 中运行;
-- 4. 执行 BL2 : 跳转到 SDRAM 中执行 BL2, 加载内核;
-- 对比 2440 : 上电后 6410 先运行 IROM 中的代码, 不是先运行 Bootloader;
-- 文档参考 :
3. S5PV210 芯片启动流程
(1) S5PV210启动方式
S5PV210 启动方式简介 :
-- IROM 启动方式 : 包括 Nand Flash 启动, SD 卡启动;
-- First boot URAT --> USB 启动方式 : USB , 串口等启动方式;
-- 文档位置 : S5PV210_UM_REV1.1 文档, Page 523, 6.2.4 章节;
(2) S5PV210地址映射
S5PV210 地址映射 :
-- IROM : 首地址 0xD000_0000, 大小 64KB;
-- IRAM : 这是 Stepping Stone (垫脚石), 首地址 0xD002_0000, 大小 96KB;
-- 零地址 : Boot area, 是一个映射区域, 与启动模式(boot model)相关. 该地址不固定于某一个设备, 如果使用 IRAM 启动, 就会将 IRAM 地址映射到 零地址处;
-- 内存 : 内存 首地址 0x2000_0000, DRAM0 位置;
-- 文档位置 : Page 30, 2.1.1 章节, Device Specific Address Space 表;
(3) S5PV210启动过程
名词解释 :
-- IROM : 引导区域, 该区域的镜像取决与启动模式, 根据启动模式装载不用的设备映像到该 IROM 区域;
-- I-SRAM | SRAM : 这里的 SRAM 是 Stepping Stone (垫脚石), 用于存放拷贝的 bootloader 第一 和 第二阶段的代码;
-- BL1 : bootloader 第一阶段;
-- BL2 : bootloader 第二阶段;
-- SDRAM Controller : 内存控制器;
-- SDRAM | DRAM : 内存;
S5PV210 启动过程 :
-- 1. IROM 初始化 : 初始化系统时钟, 初始化设备特别控制器, 引导设备;
-- 2. 装载 BL1 : 将 BL1 (16KB) 拷贝到 IRAM (Strpping Stone 96KB 明显比arm11 要大) 中, IROM 会在安全引导模式下验证 BL1 完整性;
-- 3. 执行 BL1 : 将 BL2 (80KB) 拷贝到 I-SRAM (Internal 内部 SRAM ) 中, BL1 会在安全引导模式下验证 BL2 完整性;
-- 4. 执行 BL2 : 初始化内存控制器, 如果 Stepping Stone 还不够, 那么就将剩余的拷贝到 SDRAM(内存) 中, 然后装载操作系统到内存中;
-- 5. 执行操作系统 : 跳转到内存中, 执行 剩余的 BL 或者 执行操作系统代码;
-- 参考文档 : S5PV210_iROM_ApplicationNote_Preliminary_20091126 文档, Page 7, 2.1 章节, Operating Sequence 图;
作者 : 韩曙亮
博客地址 : http://blog.csdn.net/shulianghan/article/details/42462795
转载请著名出处
相关资源下载 :
-- u-boot 源码 : http://download.csdn.net/detail/han1202012/8342761
-- S3C2440 文档 : http://download.csdn.net/detail/han1202012/8342701
-- S5PV210_iROM_ApplicationNote_Preliminary_20091126 文档 : http://download.csdn.net/detail/han1202012/8342709
-- S3C6410_Internal_ROM_Bootin 文档 : http://download.csdn.net/detail/han1202012/8342725
-- S3C6410X 文档 : http://download.csdn.net/detail/han1202012/8342731
-- S5PV210_UM_REV1.1 文档 : http://download.csdn.net/detail/han1202012/8342745
三. U-Boot 工作流程详解
1. S3C2440 芯片的 U-Boot 工作流程
(1) S3C2440 BL 程序入口
S3C2440 uboot 入口分析 :
-- Makefile 分析 : 查看uboot 源码根目录下的 Makefile 文件, 可以找到下面的内容 :
- smdk2440_config : unconfig
- @$(MKCONFIG) $(@:_config=) arm s3c24xx smdk2440 samsung s3c2440
-- 2440 开发板相关配置 : 第二行的第三项 "smdk2440" 是开发板相关的配置目录;
-- 2440 开发板相关文件 : 与该芯片对应的各种硬件相关文件在 \board\samsung\smdk2440 目录, 下面是目录内容;
- [root@localhost uboot]# cd board/samsung/smdk2440/
- [root@localhost smdk2440]# ls
- config.mk libsmdk2440.a Makefile smdk2440_val.h
- flash.c lowlevel_init.o smdk2440.c u-boot.lds
- flash.o lowlevel_init.S smdk2440.o
-- u-boot.lds 链接器脚本内容 : 分析 "cpu/s3c24xx/start.o (.text)" 内容, 可以知道 cpu/s3c24xx/start.o 是程序入口;
- OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
- OUTPUT_ARCH(arm)
- ENTRY(_start)
- SECTIONS
- {
- . = 0x00000000;
- . = ALIGN(4);
- .text :
- {
- cpu/s3c24xx/start.o (.text)
- cpu/s3c24xx/s3c2440/cpu_init.o (.text)
- *(.text)
- }
- . = ALIGN(4);
- .rodata : { *(.rodata) }
- . = ALIGN(4);
- .data : { *(.data) }
- . = ALIGN(4);
- .got : { *(.got) }
-
- . = .;
- __u_boot_cmd_start = .;
- .u_boot_cmd : { *(.u_boot_cmd) }
- __u_boot_cmd_end = .;
-
- . = ALIGN(4);
- .mmudata : { *(.mmudata) }
-
- . = ALIGN(4);
- __bss_start = .;
- .bss : { *(.bss) }
- _end = .;
- }
-- 找到 start.o 对应文件 : start.S 是对应的文件, 在上面的 u-boot.lds 链接器脚本中有 "ENTRY(_start)" 说明 _start 是程序入口, 下面是 start.S 中_start 程序入口代码;
- /*
- *************************************************************************
- *
- * Jump vector table as in table 3.1 in [1]
- *
- *************************************************************************
- */
-
-
- .globl _start
- _start:
- b reset
- ldr pc, _undefined_instruction
- ldr pc, _software_interrupt
- ldr pc, _prefetch_abort
- ldr pc, _data_abort
- ldr pc, _not_used
- ldr pc, _irq
- ldr pc, _fiq
-
- _undefined_instruction:
- .word undefined_instruction
- _software_interrupt:
- .word software_interrupt
- _prefetch_abort:
- .word prefetch_abort
- _data_abort:
- .word data_abort
- _not_used:
- .word not_used
- _irq:
- .word irq
- _fiq:
- .word fiq
-
- .balignl 16,0xdeadbeef
(2) S3C2440 BL1 工作流程
分析 Linux 内核 驱动 Bootloader 原则 :
-- 先看功能 : 看注释, 看代码功能做了什么, 暂时不关心如何实现的, 实现细节最后看;
BL1 阶段代码分析 :
-- 设置中断向量表 : Line 63;
- /*
- *************************************************************************
- *
- * Jump vector table as in table 3.1 in [1]
- *
- *************************************************************************
- */
-
-
- .globl _start
- _start:
- b reset
- ldr pc, _undefined_instruction
- ldr pc, _software_interrupt
- ldr pc, _prefetch_abort
- ldr pc, _data_abort
- ldr pc, _not_used
- ldr pc, _irq
- ldr pc, _fiq
--
设置处理器工作模式
: Line 147, 设置处理器 SVC 模式;
- reset:
- /*
- * set the cpu to SVC32 mode
- */
- mrs r0,cpsr
- bic r0,r0,#0x1f
- orr r0,r0,#0xd3
- msr cpsr,r0
--
刷新 I/D Cache
: Line 176;
- /*
- * we do sys-critical inits only at reboot,
- * not when booting from ram!
- */
- cpu_init_crit:
- /*
- * flush v4 I/D caches
- */
- mov r0, #0
- mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
- mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
--
关闭 MMU 和 cache
: Line 187;
- /*
- * disable MMU stuff and caches
- */
- mrc p15, 0, r0, c1, c0, 0
- bic r0, r0, #0x00002300 /* clear bits 13, 9:8 (--V- --RS) */
- bic r0, r0, #0x00000087 /* clear bits 7, 2:0 (B--- -CAM) */
- orr r0, r0, #0x00000002 /* set bit 2 (A) Align */
- orr r0, r0, #0x00001000 /* set bit 12 (I) I-Cache */
-- lowlevel_init 方法 : Line 243定义, lowlevel_init 在 lowlevel_init.S 中定义, 这里的方法定义在 /board/samsung/smdk2440/lowlevel_init.S 中, 如何查看 : 点击方法, 然后点击 书 图标, 可以看到该方法在很多类中定义, 在右侧搜索栏找到 与本开发板相关的定义位置;
- /*
- * Go setup Memory and board specific bits prior to relocation.
- */
- bl lowlevel_init /* go setup pll,mux,memory */
-- 关闭看门狗 : lowlevel_init.S Line 79;
- /* Disable Watchdog */
- ldr r0, =ELFIN_WATCHDOG_BASE
- mov r1, #0
- str r1, [r0]
-- 关闭所有中断 : lowlevel_init.S Line 85;
- /* mask all IRQs by setting all bits in the INTMR - default */
- ldr r0, =ELFIN_INTERRUPT_BASE
- mov r1, #0xffffffff
- str r1, [r0, #INTMSK_OFFSET]
- ldr r1, =0x000007ff
- str r1, [r0, #INTSUBMSK_OFFSET]
-- 初始化系统时钟 : 在 lowlevel_init.S 中定义的 lowlevel_init 方法, Line 45;
- /* init system clock */
- bl system_clock_init
-- 初始化串口 :
- /* for UART */
- bl uart_asm_init
-- Nand Flash 简单初始化 :
- /* simple init for NAND */
- bl nand_asm_init
-- 内存初始化 : 判断 uboot 是否运行在内存中的, 如果没有运行在内存中, 说明是从 Nand Flash 启动, 这时需要对内存进行初始化;
- /* when we already run in ram, we don't need to relocate U-Boot.
- * and actually, memory controller must be configured before U-Boot
- * is running in ram.
- */
- ldr r0, =0xf0000fff
- bic r1, pc, r0 /* r0 <- current base addr of code */
- ldr r2, _TEXT_BASE /* r1 <- original base addr in ram */
- bic r2, r2, r0 /* r0 <- current base addr of code */
- cmp r1, r2 /* compare r0, r1 */
- beq 1f /* r0 == r1 then skip sdram init */
-
- adrl r0, mem_cfg_val
- bl mem_con_init
-- 返回到上一级代码处 :
- 1: mov lr, r12
- mov pc, lr
-- 查询时 Nand Flash 启动还是 Nor Flash 启动 : 这里我们只说 Nand Flash 启动的情况;
- /* check boot device is nand or nor */
- ldr r0, =0x00000000
- ldr r3, [r0]
- ldr r1, =0xfffffffe
- str r1, [r0]
-
- ldr r2, [r0]
- str r3, [r0]
- cmp r1, r2
-- 复制 Nand Flash 到内存中 :
- nand_copy:
- mov r0, #0x1000
- bl copy_from_nand
-- 设置堆栈 : 为 C 语言编程准备, Line 365;
- /* Set up the stack */
- tack_setup:
-- 清除 bss 段 : Line 379;
- clear_bss:
- ldr r0, _bss_start /* find start of bss segment */
- ldr r1, _bss_end /* stop here */
- mov r2, #0x00000000 /* clear */
-- 跳转到 arm_boot : PC 指针跳转到 _start_armboot 函数运行;
- ldr pc, _start_armboot
-
- start_armboot:
- .word start_armboot
-- _start_armboot 函数位置 : 该函数式 /lib_arm/Border.c 中的一个函数
- void start_armboot (void)
- {
- init_fnc_t **init_fnc_ptr;
- char *s;
(3) S3C2440 BL2 工作流程
分析 BL2 执行流程 :
-- BL2 程序入口 : /lib_arm/board.c 中的 Line 268, start_armboot 函数, 在这个函数中执行了一个循环 :
- for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
- if ((*init_fnc_ptr)() != 0) {
- hang ();
- }
- }
-- init_sequence 指针函数 数组定义 :
- init_fnc_t *init_sequence[] = {
- cpu_init, /* basic cpu dependent setup */
- board_init, /* basic board dependent setup */
- interrupt_init, /* set up exceptions */
- env_init, /* initialize environment */
-
- init_baudrate, /* initialze baudrate settings */
- serial_init, /* serial communications setup */
- console_init_f, /* stage 1 init of console */
- display_banner, /* say that we are here */
- #if defined(CONFIG_DISPLAY_CPUINFO)
- print_cpuinfo, /* display cpu info (and speed) */
- #endif
- #if defined(CONFIG_DISPLAY_BOARDINFO)
- checkboard, /* display board info */
- #endif
- dram_init, /* configure available RAM banks */
- display_dram_config,
-
- NULL,
- };
--
串口 初始化
:
serial_init
, 在Line 253 的
init_sequence
指针函数 数组中定义, 这里我们只讨论硬件初始化问题, 软件初始化问题暂不讨论;
-- lcd 初始化 : Line 344 行定义;
- size = lcd_setmem (addr);
--
初始化网卡
: Line 484 , 中 "
eth_initialize(gd->bd);
" ;
-- 初始化 led : Line 487, "led_init(); /*led all off --forlinx add */";
-- 执行用户输入命令 : 初始化 led 之后进入主循环, main_loop 解析用户控制台输入命令解析, 并执行用户输入的命令;
- led_init(); /*led all off --forlinx add */
-
- /* main_loop() can return to retry autoboot, if so just run it again. */
- for (;;) {
- main_loop ();
- }
-
- /* NOTREACHED - no way out of command loop except booting */
2. S3C2440 芯片 u-boot 分析
(1) S3C2440 uboot 配置编译
uboot 配置和编译 :
-- 找到 Makefile 中的 2440 目标项 : 目标是 smdk2440_config;
- smdk2440_config : unconfig
- @$(MKCONFIG) $(@:_config=) arm s3c24xx smdk2440 samsung s3c2440
-- 配置编译环境 : 执行 make smdk2440_config 命令;
- [root@localhost uboot]# make smdk2440_config
- Configuring for smdk2440 board which boot from ...
-- 进行编译 : 执行 make 命令;
-- 反编译 u-boot elf 文件 : 使用 arm-linux-objdump -S -D u-boot > uboot_dump 命令, 反编译, 分析反编译结果 :
- [root@localhost uboot]# arm-linux-objdump -S -D u-boot > uboot_dump
- [root@localhost uboot]# gedit uboot_dump
-
-
- 30009100 :
-
- NULL,
- };
-
- void start_armboot (void)
- {
- 30009100: e92d4070 push {r4, r5, r6, lr}
-
- gd_base = CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE - sizeof(gd_t);
- #ifdef CONFIG_USE_IRQ
- gd_base -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);
- #endif
- gd = (gd_t*)gd_base;
- 30009104: e59f8190 ldr r8, [pc, #400] ; 3000929c
-
- NULL,
- };
(2) S3C2440 uboot 链接地址分析
链接地址分析 :
-- 查看连接器脚本 : 查看 /board/samsung/smdk2440/u-boot.lds 链接器脚本, 代码段的起始地址是 0x00000000;
- OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
- OUTPUT_ARCH(arm)
- ENTRY(_start)
- SECTIONS
- {
- . = 0x00000000;
- . = ALIGN(4);
- .text :
- {
- cpu/s3c24xx/start.o (.text)
- cpu/s3c24xx/s3c2440/cpu_init.o (.text)
- *(.text)
- }
-
- ... ...
-- 查看 config.mk 脚本 : Line 189 行, "LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS)" 内容, -Ttext $(TEXT_BASE) 会把链接器脚本中的地址覆盖掉;
-- TEXT_BASE 变量定义 : 在 /board/samsung/smdk2440/config.mk 中 "TEXT_BASE = 0x30008000" 定义了该变量;
-- 查看反编译中的地址 : 代码的起始地址果然是 30008000;
- octopus@octopus:~/arm/uboot/uboot$ more uboot_dump
-
- u-boot: file format elf32-littlearm
-
- Disassembly of section .text:
-
- 30008000 <_start>:
- */
-
-
- .globl _start
- _start:
- b reset
- 30008000: ea000013 b 30008054
- ldr pc, _undefined_instruction
- 30008004: e59ff014 ldr pc, [pc, #20] ; 30008020 <_undefined_instruction>
- ldr pc, _software_interrupt
- 30008008: e59ff014 ldr pc, [pc, #20] ; 30008024 <_software_interrupt>
- ldr pc, _prefetch_abort
- 3000800c: e59ff014 ldr pc, [pc, #20] ; 30008028 <_prefetch_abort>
- ldr pc, _data_abort
- 30008010: e59ff014 ldr pc, [pc, #20] ; 3000802c <_data_abort>
- ldr pc, _not_used
- 30008014: e59ff014 ldr pc, [pc, #20] ; 30008030 <_not_used>
- ldr pc, _irq
- 30008018: e59ff014 ldr pc, [pc, #20] ; 30008034 <_irq>
-
(3) S3C2440 uboot 中的相对地址跳转 和 绝对地址跳转
相对地址和绝对地址跳转 :
-- 相对跳转 : 不会对 PC 造成实质性的影响, B 指令, 首先计算一个相对值, 在 PC 原有基础上;
-- 相对跳转示例 : 如 之前的初始化的方法 "bl lowlevel_init", 该行代码的地址是 0x30008000, lowlevel_init 在 0x30008010 地址处, 执行到了该行代码, 30008010 是链接地址, 但是此时 PC 指针指向的值 还在 垫脚石中, 小于4K, 如此时 PC = 100, 如果进行链接地址跳转 PC = 100 + (0x30008010 - 300080000) 地址, 之后 PC = 110, PC 还是在垫脚石中, 相对地址跳转不会对 PC 造成实质性的影响;
-- 绝对跳转 : 直接修改 PC 指针的值, PC 直接跳到内存中, ldr pc #0x30008010, PC 就会编程 0x30008010;
(4) S3C2440 内存分布角度分析启动流程
内存分布角度分析启动流程 :
-- arm 内存前 4K : 内存中前 4K 是 Stepping Stone;
-- 拷贝 BL1 : 启动时, 会将 Nand Flash 拷贝到 Stepping Stone 中, 主要是将 start.S 拷贝进去;
-- 执行 BL1 : 之后执行 start.S 的 _start 开始执行;
-- 拷贝 BL2 : 执行到 BL1 最后会将 BL2 代码拷贝到内存中去;
-- 执行 BL2 : BL1 执行完后, PC 指针会跳转到内存中接着运行 BL2 的代码;
(5) S3C2440 地址跳转角度分析启动流程
地址跳转角度分析启动流程
:
-- arm 地址空间 : 前面 4K 是 Stepping Stone (垫脚石);
-- nand flash 地址空间 : 前 4K 会被复制到垫脚石中;
-- PC 指针 : 此时 PC 指针指向 0, 会取 arm 中的 垫脚石中的指令, 执行这些指令;
-- 拷贝剩余 BL : 执行到一定程度, 会将 nand flash 中的剩余 BL 复制到 0x30008000 地址;
-- PC 跳转到内存 : PC 跳转到 0x30008000 执行, 之前 PC 指针值一直小于 4K, 但是跳转后顺便值变成 0x30008000 之后的地址了;
2. S3C6410 芯片的 U-Boot 工作流程
(1) S3C6410 BL 程序入口
S3C6410程序入口分析 :
-- 分析 Makefile 文件 : Line 1953 处定义了 forlinx_nand_ram256_config 目标, 对应开发板是 smdk6410;
- forlinx_nand_ram256_config : unconfig
- @$(MKCONFIG) smdk6410 arm s3c64xx smdk6410 samsung s3c6410 NAND ram256
--
smdk6410 开发板相关配置文件 :
-- 分析链接器脚本 u-boot.lds : 可以看到程序入口是 cpu/s3c64xx/start.S 汇编文件;
- ... ...
-
- SECTIONS
- {
- . = 0x00000000;
-
- . = ALIGN(4);
- .text :
- {
- cpu/s3c64xx/start.o (.text)
- cpu/s3c64xx/s3c6410/cpu_init.o (.text)
- cpu/s3c64xx/onenand_cp.o (.text)
- cpu/s3c64xx/nand_cp.o (.text)
- cpu/s3c64xx/movi.o (.text)
- *(.text)
- lib_arm/div0.o
- }
-
- ... ...
--
分析 start.S 代码
:
_start
是程序入口;
- ... ...
-
- .globl _start
- _start: b reset
- ldr pc, _undefined_instruction
- ldr pc, _software_interrupt
- ldr pc, _prefetch_abort
- ldr pc, _data_abort
- ldr pc, _not_used
- ldr pc, _irq
- ldr pc, _fiq
-
- ... ...
(2) S3C6410 BL1 流程分析
S3C6410 BL1 流程分析 :
-- 初始化向量表 : start.S Line 52;
- ldr pc, _undefined_instruction
- ldr pc, _software_interrupt
- ldr pc, _prefetch_abort
- ldr pc, _data_abort
- ldr pc, _not_used
- ldr pc, _irq
- ldr pc, _fiq
--
设置 CPU 为 SVC 模式
:
start.S
Line 136;
- /*
- * the actual reset code
- */
-
- reset:
- /*
- * set the cpu to SVC32 mode
- */
- mrs r0,cpsr
- bic r0,r0,#0x1f
- orr r0,r0,#0xd3
- msr cpsr,r0
--
刷新 I/D Cache
:
start.S
Line 163;
- /*
- * flush v4 I/D caches
- */
- mov r0, #0
- mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
- mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
--
关闭 MMU 和 Cache
:
start.S
Line 170;
- /*
- * disable MMU stuff and caches
- */
- mrc p15, 0, r0, c1, c0, 0
- bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
- bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
- orr r0, r0, #0x00000002 @ set bit 2 (A) Align
- orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
- mcr p15, 0, r0, c1, c0, 0
--
外设基地址初始化 (6410 独有)
:
start.S
Line 178;
- /* Peri port setup */
- ldr r0, =0x70000000
- orr r0, r0, #0x13
- mcr p15,0,r0,c15,c2,4 @ 256M(0x70000000-0x7fffffff)
--
调用 lowlevel_init 方法
:
start.S
Line 240;
- /*
- * Go setup Memory and board specific bits prior to relocation.
- */
- bl lowlevel_init /* go setup pll,mux,memory */
-
- /* when we already run in ram, we don't need to relocate U-Boot.
- * and actually, memory controller must be configured before U-Boot
- * is running in ram.
- */
--
lowlevel_init 方法定义位置
: /board/samsung/smdk6410/lowlevel_init.S 中定义该方法, 入口是
lowlevel_init.S
Line 41;
- ... ...
-
- .globl lowlevel_init
- lowlevel_init:
- mov r12, lr
-
- ldr r0, =ELFIN_GPIO_BASE
-
- ... ...
-- LED 点亮 : lowlevel_init.S Line 62;
- /* LED on only #8 */
- ldr r0, =ELFIN_GPIO_BASE
- ldr r1, =0x00111111
- str r1, [r0, #GPMCON_OFFSET]
-
- ldr r1, =0x00000555
- str r1, [r0, #GPMPUD_OFFSET]
-
- ldr r1, =0x002a
- str r1, [r0, #GPMDAT_OFFSET]
-
-
-
- ldr r1, =0 /*0x55555555 phantom*/
- str r1, [r0, #MEM1DRVCON_OFFSET]
--
关闭看门狗
:
lowlevel_init.S Line 78;
- /* Disable Watchdog */
- ldr r0, =0x7e000000 @0x7e004000
- orr r0, r0, #0x4000
- mov r1, #0
- str r1, [r0]
--
关闭所有中断
:
lowlevel_init.S
Line 91;
- @ Disable all interrupts (VIC0 and VIC1)
- mvn r3, #0x0
- str r3, [r0, #oINTMSK]
- str r3, [r1, #oINTMSK]
--
初始化时钟
:
lowlevel_init.S
Line 109;
- /* init system clock */
-
-
- bl system_clock_init
-- 初始化串口 : lowlevel_init.S Line 113;
- /* for UART */
- bl uart_asm_init
--
初始化内存
:
lowlevel_init.S
Line 127;
- /* simple init for NAND */
- nand_asm_init
--
返回到 start.S
:
lowlevel_init.S Line 156;
--
复制 nand flash 内容到内存
: start.S Line 276;
- #ifdef CONFIG_BOOT_NAND
- mov r0, #0x1000
- bl copy_from_nand
--
堆栈初始化
: start.S Line 398;
- /* Set up the stack */
- stack_setup:
- #ifdef CONFIG_MEMORY_UPPER_CODE
- ldr sp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0xc)
- #else
- ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
- sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
- sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
- #ifdef CONFIG_USE_IRQ
- sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
- #endif
- sub sp, r0, #12 /* leave 3 words for abort-stack */
-
- #endif
--
清除 BSS 段
: start.S Line 412;
- clear_bss:
- ldr r0, _bss_start /* find start of bss segment */
- ldr r1, _bss_end /* stop here */
- mov r2, #0x00000000 /* clear */
-- 执行 BL2 : start.S Line 245;
- ldr pc, _start_armboot
-
- start_armboot:
- .word start_armboot
--
6410 与 2440 的 BL2 阶段是相同, 因为 start_armboot 不管是什么开发板, BL2 指向的 该函数都是在一个文件中
;
3. S5PV210 芯片的 U-Boot 工作流程
(1) S5PV210 BL1 执行流程
S5VP 210 BL1 流程 :
-- 1. 设置中断向量表;
--
2. 设置 CPU svc 工作模式;
--
3. 关闭 L1 (一级的) I/D Cache 失效;
--
4. 关闭 MMU 和 Cache;
--
5. 检查 reset 状态;
--
6. IO 引脚初始化;
--
7. 关闭看门狗;
--
8. SRAM 和 SROM 初始化;
--
9. 时钟初始化;
--
10. 内存初始化;
--
11. UART 简单初始化;
--
12. 取消存储保护区;
--
13. nand flash 简单初始化;
--
14. 关闭 ABB;
--
15. 设置堆栈;
--
16. 将 BL2 到 RAM 中;
--
17. 跳转到 RAM 中 运行 BL2;
(2) S5PV210 BL2 复制分析
BL2 复制相关问题 :
--
BL2 复制到内存中什么位置 : 到代码中寻找, 这个地址在头文件中定义, 0x23100000 位置;
--
BL1 如何找到 BL2 : nand flash 写入后 BL1 与 BL2 间距 是 8KB, BL1 是 16KB + 8KB, BL2 在 24KB 地址开始的位置;
--
BL2 大小要求 : 复制 512KB 到内存中去;
(3) S5PV210 BL 启动分析
S5PV210 启动流程 : BL1 和 BL2 在 210 上被划分成了两部分;
-- iROM 映射 : iROM 通过映射 被映射到 arm 0 地址处, 里面是一个固件程序, 是三星烧写好的;
-- iRAM 垫脚石 : 96KB, Stepping Stone 垫脚石, 在 irom 上面;
-- 拷贝 BL1 : iROM 固化程序将 BL1 (16KB) 复制到 iRAM 中;
-- 拷贝 BL2 : BL1 在 iRAM 中执行, 如果 BL2 小于 80K, 复制 BL2 到 iRAM 中; 如果 BL2 大于 80K, 复制 BL2 到 内存中; uboot 编译后大于80K, 因此 BL2 复制到 内存中;
四. Bootloader 架构设计
H-Boot BL1 程序设计 : 汇编代码编写;
-- 1. 核心初始化 : a. 设置中断向量表, b. 设置 CPU svc 模式, c. 关闭看门狗, d. 关闭中断, e. 关闭 MMU 和 Cache, f. 外设基地址初始化 (f 为6410独有);
-- 2. C 语言编程环境设置 : a. 设置堆栈, b. 清除 BSS 段;
-- 3. LED 初始化 ;
-- 4. 初始化系统时钟;
-- 5. 内存初始化 : a. 取消存储保护区 (a 位 210 独有), b. iRAM 和 iROM 初始化 (b 为 210 独有);
-- 6. 复制 nand flash 到内存 : a. 简单初始化 nand flash, b. 复制代码到内存, c. 跳转到 BL2 入口;
H-Boot BL2 程序设计 : 汇编代码编写;
-- 1. MMU 初始化;
-- 2. 中断初始化 : a. 中断初始化, b. 按键初始化;
-- 3. 初始化串口 : a. 串口初始化, b. 移植 printf 函数;
-- 4. 网卡初始化;
-- 5. LCD 初始化 : a. 触摸板初始化, b. LCD 初始化;
-- 6. 解析执行用户命令 : a. 移植 TFTP 命令, b. 移植 BOOTM 命令;
作者 : 韩曙亮
博客地址 : http://blog.csdn.net/shulianghan/article/details/42462795
转载请著名出处
相关资源下载 :
-- u-boot 源码 : http://download.csdn.net/detail/han1202012/8342761
-- S3C2440 文档 : http://download.csdn.net/detail/han1202012/8342701
-- S5PV210_iROM_ApplicationNote_Preliminary_20091126 文档 : http://download.csdn.net/detail/han1202012/8342709
-- S3C6410_Internal_ROM_Bootin 文档 : http://download.csdn.net/detail/han1202012/8342725
-- S3C6410X 文档 : http://download.csdn.net/detail/han1202012/8342731
-- S5PV210_UM_REV1.1 文档 : http://download.csdn.net/detail/han1202012/8342745