作者 : 韩曙亮

博客地址 : 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 用户目录下解压;

  1. [root@localhost arm]# cd /home/samba/
  2. [root@localhost samba]# ls
  3. ARM-tools uboot.tar.gz
  4. [root@localhost samba]#
  5. [root@localhost samba]#
  6. [root@localhost samba]# tar -xvzf uboot.tar.gz
  7. uboot/
  8. uboot/README
  9.  
  10. ... ...

-- 映射网络驱动器 : 复制 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;

  1. OVERVIEW
  2. In recent times, NOR flash memory gets high in price while an SDRAM and a NAND flash memory is comparatively
  3. economical , motivating some users to execute the boot code on a NAND flash and execute the main code on an
  4. SDRAM.
  5. S3C2440A boot code can be executed on an external NAND flash memory. In order to support NAND flash boot
  6. loader, the S3C2440A is equipped with an internal SRAM buffer called Steppingstone’. When booting, the first 4
  7. KBytes of the NAND flash memory will be loaded into Steppingstone and the boot code loaded into Steppingstone
  8. will be executed.
  9. Generally, the boot code will copy NAND flash content to SDRAM. Using hardware ECC, the NAND flash data
  10. 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 文件, 可以找到下面的内容 :

  1. smdk2440_config : unconfig
  2. @$(MKCONFIG) $(@:_config=) arm s3c24xx smdk2440 samsung s3c2440

-- 2440 开发板相关配置 : 第二行的第三项 "smdk2440" 是开发板相关的配置目录;

-- 2440 开发板相关文件 : 与该芯片对应的各种硬件相关文件在 \board\samsung\smdk2440 目录, 下面是目录内容;

  1. [root@localhost uboot]# cd board/samsung/smdk2440/
  2. [root@localhost smdk2440]# ls
  3. config.mk libsmdk2440.a Makefile smdk2440_val.h
  4. flash.c lowlevel_init.o smdk2440.c u-boot.lds
  5. flash.o lowlevel_init.S smdk2440.o

-- u-boot.lds 链接器脚本内容 : 分析 "cpu/s3c24xx/start.o (.text)" 内容, 可以知道 cpu/s3c24xx/start.o 是程序入口;

  1. OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
  2. OUTPUT_ARCH(arm)
  3. ENTRY(_start)
  4. SECTIONS
  5. {
  6. . = 0x00000000;
  7. . = ALIGN(4);
  8. .text :
  9. {
  10. cpu/s3c24xx/start.o (.text)
  11. cpu/s3c24xx/s3c2440/cpu_init.o (.text)
  12. *(.text)
  13. }
  14. . = ALIGN(4);
  15. .rodata : { *(.rodata) }
  16. . = ALIGN(4);
  17. .data : { *(.data) }
  18. . = ALIGN(4);
  19. .got : { *(.got) }
  20.  
  21. . = .;
  22. __u_boot_cmd_start = .;
  23. .u_boot_cmd : { *(.u_boot_cmd) }
  24. __u_boot_cmd_end = .;
  25.  
  26. . = ALIGN(4);
  27. .mmudata : { *(.mmudata) }
  28.  
  29. . = ALIGN(4);
  30. __bss_start = .;
  31. .bss : { *(.bss) }
  32. _end = .;
  33. }

-- 找到 start.o 对应文件 : start.S 是对应的文件, 在上面的 u-boot.lds 链接器脚本中有 "ENTRY(_start)" 说明 _start 是程序入口, 下面是 start.S 中_start 程序入口代码;

  1. /*
  2. *************************************************************************
  3. *
  4. * Jump vector table as in table 3.1 in [1]
  5. *
  6. *************************************************************************
  7. */
  8.  
  9. .globl _start
  10. _start:
  11. b reset
  12. ldr pc, _undefined_instruction
  13. ldr pc, _software_interrupt
  14. ldr pc, _prefetch_abort
  15. ldr pc, _data_abort
  16. ldr pc, _not_used
  17. ldr pc, _irq
  18. ldr pc, _fiq
  19.  
  20. _undefined_instruction:
  21. .word undefined_instruction
  22. _software_interrupt:
  23. .word software_interrupt
  24. _prefetch_abort:
  25. .word prefetch_abort
  26. _data_abort:
  27. .word data_abort
  28. _not_used:
  29. .word not_used
  30. _irq:
  31. .word irq
  32. _fiq:
  33. .word fiq
  34.  
  35. .balignl 16,0xdeadbeef

(2) S3C2440 BL1 工作流程

分析 Linux 内核 驱动 Bootloader 原则 :

-- 先看功能 : 看注释, 看代码功能做了什么, 暂时不关心如何实现的, 实现细节最后看;

BL1 阶段代码分析 :

-- 设置中断向量表 : Line 63;

  1. /*
  2. *************************************************************************
  3. *
  4. * Jump vector table as in table 3.1 in [1]
  5. *
  6. *************************************************************************
  7. */
  8.  
  9. .globl _start
  10. _start:
  11. b reset
  12. ldr pc, _undefined_instruction
  13. ldr pc, _software_interrupt
  14. ldr pc, _prefetch_abort
  15. ldr pc, _data_abort
  16. ldr pc, _not_used
  17. ldr pc, _irq
  18. ldr pc, _fiq

-- 设置处理器工作模式 : Line 147, 设置处理器 SVC 模式;

  1. reset:
  2. /*
  3. * set the cpu to SVC32 mode
  4. */
  5. mrs r0,cpsr
  6. bic r0,r0,#0x1f
  7. orr r0,r0,#0xd3
  8. msr cpsr,r0

-- 刷新 I/D Cache : Line 176;

  1. /*
  2. * we do sys-critical inits only at reboot,
  3. * not when booting from ram!
  4. */
  5. cpu_init_crit:
  6. /*
  7. * flush v4 I/D caches
  8. */
  9. mov r0, #0
  10. mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
  11. mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */

-- 关闭 MMU 和 cache : Line 187;

  1. /*
  2. * disable MMU stuff and caches
  3. */
  4. mrc p15, 0, r0, c1, c0, 0
  5. bic r0, r0, #0x00002300 /* clear bits 13, 9:8 (--V- --RS) */
  6. bic r0, r0, #0x00000087 /* clear bits 7, 2:0 (B--- -CAM) */
  7. orr r0, r0, #0x00000002 /* set bit 2 (A) Align */
  8. 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 中, 如何查看 : 点击方法, 然后点击 书 图标, 可以看到该方法在很多类中定义, 在右侧搜索栏找到 与本开发板相关的定义位置;

  1. /*
  2. * Go setup Memory and board specific bits prior to relocation.
  3. */
  4. bl lowlevel_init /* go setup pll,mux,memory */

-- 关闭看门狗 : lowlevel_init.S Line 79;

  1. /* Disable Watchdog */
  2. ldr r0, =ELFIN_WATCHDOG_BASE
  3. mov r1, #0
  4. str r1, [r0]

-- 关闭所有中断 : lowlevel_init.S Line 85;

  1. /* mask all IRQs by setting all bits in the INTMR - default */
  2. ldr r0, =ELFIN_INTERRUPT_BASE
  3. mov r1, #0xffffffff
  4. str r1, [r0, #INTMSK_OFFSET]
  5. ldr r1, =0x000007ff
  6. str r1, [r0, #INTSUBMSK_OFFSET]

-- 初始化系统时钟 : 在 lowlevel_init.S 中定义的 lowlevel_init 方法, Line 45;

  1. /* init system clock */
  2. bl system_clock_init

-- 初始化串口

  1. /* for UART */
  2. bl uart_asm_init

-- Nand Flash 简单初始化

  1. /* simple init for NAND */
  2. bl nand_asm_init

-- 内存初始化 : 判断 uboot 是否运行在内存中的, 如果没有运行在内存中, 说明是从 Nand Flash 启动, 这时需要对内存进行初始化;

  1. /* when we already run in ram, we don't need to relocate U-Boot.
  2. * and actually, memory controller must be configured before U-Boot
  3. * is running in ram.
  4. */
  5. ldr r0, =0xf0000fff
  6. bic r1, pc, r0 /* r0 <- current base addr of code */
  7. ldr r2, _TEXT_BASE /* r1 <- original base addr in ram */
  8. bic r2, r2, r0 /* r0 <- current base addr of code */
  9. cmp r1, r2 /* compare r0, r1 */
  10. beq 1f /* r0 == r1 then skip sdram init */
  11.  
  12. adrl r0, mem_cfg_val
  13. bl mem_con_init

-- 返回到上一级代码处

  1. 1: mov lr, r12
  2. mov pc, lr

-- 查询时 Nand Flash 启动还是 Nor Flash 启动 : 这里我们只说 Nand Flash 启动的情况;

  1. /* check boot device is nand or nor */
  2. ldr r0, =0x00000000
  3. ldr r3, [r0]
  4. ldr r1, =0xfffffffe
  5. str r1, [r0]
  6.  
  7. ldr r2, [r0]
  8. str r3, [r0]
  9. cmp r1, r2

-- 复制 Nand Flash 到内存中

  1. nand_copy:
  2. mov r0, #0x1000
  3. bl copy_from_nand

-- 设置堆栈 : 为 C 语言编程准备, Line 365;

  1. /* Set up the stack */
  2. stack_setup:

-- 清除 bss 段 : Line 379;

  1. clear_bss:
  2. ldr r0, _bss_start /* find start of bss segment */
  3. ldr r1, _bss_end /* stop here */
  4. mov r2, #0x00000000 /* clear */

-- 跳转到 arm_boot : PC 指针跳转到 _start_armboot 函数运行;

  1. ldr pc, _start_armboot
  2.  
  3. _start_armboot:
  4. .word start_armboot

-- _start_armboot 函数位置 : 该函数式 /lib_arm/Border.c 中的一个函数

  1. void start_armboot (void)
  2. {
  3. init_fnc_t **init_fnc_ptr;
  4. char *s;

(3) S3C2440 BL2 工作流程

分析 BL2 执行流程 :

-- BL2 程序入口 : /lib_arm/board.c 中的 Line 268, start_armboot 函数, 在这个函数中执行了一个循环 :

  1. for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
  2. if ((*init_fnc_ptr)() != 0) {
  3. hang ();
  4. }
  5. }

-- init_sequence 指针函数 数组定义 :

  1. init_fnc_t *init_sequence[] = {
  2. cpu_init, /* basic cpu dependent setup */
  3. board_init, /* basic board dependent setup */
  4. interrupt_init, /* set up exceptions */
  5. env_init, /* initialize environment */
  6.  
  7. init_baudrate, /* initialze baudrate settings */
  8. serial_init, /* serial communications setup */
  9. console_init_f, /* stage 1 init of console */
  10. display_banner, /* say that we are here */
  11. #if defined(CONFIG_DISPLAY_CPUINFO)
  12. print_cpuinfo, /* display cpu info (and speed) */
  13. #endif
  14. #if defined(CONFIG_DISPLAY_BOARDINFO)
  15. checkboard, /* display board info */
  16. #endif
  17. dram_init, /* configure available RAM banks */
  18. display_dram_config,
  19.  
  20. NULL,
  21. };

-- 串口 初始化serial_init, 在Line 253 的 init_sequence 指针函数 数组中定义, 这里我们只讨论硬件初始化问题, 软件初始化问题暂不讨论;

-- lcd 初始化 : Line 344 行定义;

  1. size = lcd_setmem (addr);

-- 初始化网卡 : Line 484 , 中 "eth_initialize(gd->bd);" ;

-- 初始化 led : Line 487, "led_init();     /*led all off --forlinx add */";

-- 执行用户输入命令 : 初始化 led 之后进入主循环, main_loop 解析用户控制台输入命令解析, 并执行用户输入的命令;

  1. led_init(); /*led all off --forlinx add */
  2.  
  3. /* main_loop() can return to retry autoboot, if so just run it again. */
  4. for (;;) {
  5. main_loop ();
  6. }
  7.  
  8. /* NOTREACHED - no way out of command loop except booting */

2. S3C2440 芯片 u-boot 分析

(1) S3C2440 uboot 配置编译

uboot 配置和编译 :

-- 找到 Makefile 中的 2440 目标项 : 目标是 smdk2440_config;

  1. smdk2440_config : unconfig
  2. @$(MKCONFIG) $(@:_config=) arm s3c24xx smdk2440 samsung s3c2440

-- 配置编译环境 : 执行 make smdk2440_config 命令;

  1. [root@localhost uboot]# make smdk2440_config
  2. Configuring for smdk2440 board which boot from ...

-- 进行编译 : 执行 make 命令;

-- 反编译 u-boot elf 文件 : 使用 arm-linux-objdump -S -D u-boot > uboot_dump 命令, 反编译, 分析反编译结果 :

  1. [root@localhost uboot]# arm-linux-objdump -S -D u-boot > uboot_dump
  2. [root@localhost uboot]# gedit uboot_dump
  3.  
  4. 30009100 <start_armboot>:
  5.  
  6. NULL,
  7. };
  8.  
  9. void start_armboot (void)
  10. {
  11. 30009100: e92d4070 push {r4, r5, r6, lr}
  12.  
  13. gd_base = CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE - sizeof(gd_t);
  14. #ifdef CONFIG_USE_IRQ
  15. gd_base -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);
  16. #endif
  17. gd = (gd_t*)gd_base;
  18. 30009104: e59f8190 ldr r8, [pc, #400] ; 3000929c <start_armboot+0x19c>
  19.  
  20. NULL,
  21. };

(2) S3C2440 uboot 链接地址分析

链接地址分析 :

-- 查看连接器脚本 : 查看 /board/samsung/smdk2440/u-boot.lds 链接器脚本, 代码段的起始地址是 0x00000000;

  1. OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
  2. OUTPUT_ARCH(arm)
  3. ENTRY(_start)
  4. SECTIONS
  5. {
  6. . = 0x00000000;
  7. . = ALIGN(4);
  8. .text :
  9. {
  10. cpu/s3c24xx/start.o (.text)
  11. cpu/s3c24xx/s3c2440/cpu_init.o (.text)
  12. *(.text)
  13. }
  14.  
  15. ... ...

-- 查看 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;

  1. octopus@octopus:~/arm/uboot/uboot$ more uboot_dump
  2.  
  3. u-boot: file format elf32-littlearm
  4.  
  5. Disassembly of section .text:
  6.  
  7. 30008000 <_start>:
  8. */
  9.  
  10. .globl _start
  11. _start:
  12. b reset
  13. 30008000: ea000013 b 30008054 <reset>
  14. ldr pc, _undefined_instruction
  15. 30008004: e59ff014 ldr pc, [pc, #20] ; 30008020 <_undefined_instruction>
  16. ldr pc, _software_interrupt
  17. 30008008: e59ff014 ldr pc, [pc, #20] ; 30008024 <_software_interrupt>
  18. ldr pc, _prefetch_abort
  19. 3000800c: e59ff014 ldr pc, [pc, #20] ; 30008028 <_prefetch_abort>
  20. ldr pc, _data_abort
  21. 30008010: e59ff014 ldr pc, [pc, #20] ; 3000802c <_data_abort>
  22. ldr pc, _not_used
  23. 30008014: e59ff014 ldr pc, [pc, #20] ; 30008030 <_not_used>
  24. ldr pc, _irq
  25. 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;

  1. forlinx_nand_ram256_config : unconfig
  2. @$(MKCONFIG) smdk6410 arm s3c64xx smdk6410 samsung s3c6410 NAND ram256

-- smdk6410 开发板相关配置文件

-- 分析链接器脚本 u-boot.lds : 可以看到程序入口是 cpu/s3c64xx/start.S 汇编文件;

  1. ... ...
  2.  
  3. SECTIONS
  4. {
  5. . = 0x00000000;
  6.  
  7. . = ALIGN(4);
  8. .text :
  9. {
  10. cpu/s3c64xx/start.o (.text)
  11. cpu/s3c64xx/s3c6410/cpu_init.o (.text)
  12. cpu/s3c64xx/onenand_cp.o (.text)
  13. cpu/s3c64xx/nand_cp.o (.text)
  14. cpu/s3c64xx/movi.o (.text)
  15. *(.text)
  16. lib_arm/div0.o
  17. }
  18.  
  19. ... ...

-- 分析 start.S 代码_start 是程序入口;

  1. ... ...
  2.  
  3. .globl _start
  4. _start: b reset
  5. ldr pc, _undefined_instruction
  6. ldr pc, _software_interrupt
  7. ldr pc, _prefetch_abort
  8. ldr pc, _data_abort
  9. ldr pc, _not_used
  10. ldr pc, _irq
  11. ldr pc, _fiq
  12.  
  13. ... ...

(2) S3C6410 BL1 流程分析

S3C6410 BL1 流程分析 :

-- 初始化向量表 : start.S Line 52;

  1. ldr pc, _undefined_instruction
  2. ldr pc, _software_interrupt
  3. ldr pc, _prefetch_abort
  4. ldr pc, _data_abort
  5. ldr pc, _not_used
  6. ldr pc, _irq
  7. ldr pc, _fiq

-- 设置 CPU 为 SVC 模式 : start.S Line 136;

  1. /*
  2. * the actual reset code
  3. */
  4.  
  5. reset:
  6. /*
  7. * set the cpu to SVC32 mode
  8. */
  9. mrs r0,cpsr
  10. bic r0,r0,#0x1f
  11. orr r0,r0,#0xd3
  12. msr cpsr,r0

-- 刷新 I/D Cache : start.S Line 163;

  1. /*
  2. * flush v4 I/D caches
  3. */
  4. mov r0, #0
  5. mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
  6. mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */

-- 关闭 MMU 和 Cache : start.S Line 170;

  1. /*
  2. * disable MMU stuff and caches
  3. */
  4. mrc p15, 0, r0, c1, c0, 0
  5. bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
  6. bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
  7. orr r0, r0, #0x00000002 @ set bit 2 (A) Align
  8. orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
  9. mcr p15, 0, r0, c1, c0, 0

-- 外设基地址初始化 (6410 独有) : start.S Line 178;

  1. /* Peri port setup */
  2. ldr r0, =0x70000000
  3. orr r0, r0, #0x13
  4. mcr p15,0,r0,c15,c2,4 @ 256M(0x70000000-0x7fffffff)

-- 调用 lowlevel_init 方法 : start.S Line 240;

  1. /*
  2. * Go setup Memory and board specific bits prior to relocation.
  3. */
  4. bl lowlevel_init /* go setup pll,mux,memory */
  5.  
  6. /* when we already run in ram, we don't need to relocate U-Boot.
  7. * and actually, memory controller must be configured before U-Boot
  8. * is running in ram.
  9. */

-- lowlevel_init 方法定义位置 : /board/samsung/smdk6410/lowlevel_init.S 中定义该方法, 入口是 lowlevel_init.S Line 41;

  1. ... ...
  2.  
  3. .globl lowlevel_init
  4. lowlevel_init:
  5. mov r12, lr
  6.  
  7. ldr r0, =ELFIN_GPIO_BASE
  8.  
  9. ... ...

-- LED 点亮 : lowlevel_init.S Line 62;

  1. /* LED on only #8 */
  2. ldr r0, =ELFIN_GPIO_BASE
  3. ldr r1, =0x00111111
  4. str r1, [r0, #GPMCON_OFFSET]
  5.  
  6. ldr r1, =0x00000555
  7. str r1, [r0, #GPMPUD_OFFSET]
  8.  
  9. ldr r1, =0x002a
  10. str r1, [r0, #GPMDAT_OFFSET]
  11.  
  12. ldr r1, =0 /*0x55555555 phantom*/
  13. str r1, [r0, #MEM1DRVCON_OFFSET]

-- 关闭看门狗 : lowlevel_init.S Line 78;

  1. /* Disable Watchdog */
  2. ldr r0, =0x7e000000 @0x7e004000
  3. orr r0, r0, #0x4000
  4. mov r1, #0
  5. str r1, [r0]

-- 关闭所有中断 : lowlevel_init.S Line 91;

  1. @ Disable all interrupts (VIC0 and VIC1)
  2. mvn r3, #0x0
  3. str r3, [r0, #oINTMSK]
  4. str r3, [r1, #oINTMSK]

-- 初始化时钟 : lowlevel_init.S Line 109;

  1. /* init system clock */
  2.  
  3. bl system_clock_init

-- 初始化串口 : lowlevel_init.S Line 113;

  1. /* for UART */
  2. bl uart_asm_init

-- 初始化内存 : lowlevel_init.S Line 127;

  1. /* simple init for NAND */
  2. bl nand_asm_init

-- 返回到 start.S : lowlevel_init.S Line 156;

  1. mov pc, lr

-- 复制 nand flash 内容到内存 : start.S Line 276;

  1. #ifdef CONFIG_BOOT_NAND
  2. mov r0, #0x1000
  3. bl copy_from_nand

-- 堆栈初始化 : start.S Line 398;

  1. /* Set up the stack */
  2. stack_setup:
  3. #ifdef CONFIG_MEMORY_UPPER_CODE
  4. ldr sp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0xc)
  5. #else
  6. ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
  7. sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
  8. sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
  9. #ifdef CONFIG_USE_IRQ
  10. sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
  11. #endif
  12. sub sp, r0, #12 /* leave 3 words for abort-stack */
  13.  
  14. #endif

-- 清除 BSS 段 : start.S Line 412;

  1. clear_bss:
  2. ldr r0, _bss_start /* find start of bss segment */
  3. ldr r1, _bss_end /* stop here */
  4. mov r2, #0x00000000 /* clear */

-- 执行 BL2 : start.S Line 245;

  1. ldr pc, _start_armboot
  2.  
  3. _start_armboot:
  4. .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

【嵌入式开发】 Bootloader 详解 ( 代码环境 | ARM 启动流程 | uboot 工作流程 | 架构设计)的更多相关文章

  1. Nginx详解二十九:基于Nginx的中间件架构设计

    基于Nginx的中间件架构 一:了解需求 1.定义Nginx在服务体系中的角色 1.静态资源服务 2.代理服务 3.动静分离 2.静态资源服务的功能设计 3.代理服务 二:设计评估 三:配置注意事项

  2. ext.js的mvc开发模式详解

    ext.js的mvc开发模式详解和环境配置 在JS的开发过程中,大规模的JS脚本难以组织和维护,这一直是困扰前端开发人员的头等问题.Extjs为了解决这种问题,在Extjs 4.x版本中引入了MVC开 ...

  3. 《python开发技术详解》|百度网盘免费下载|Python开发入门篇

    <python开发技术详解>|百度网盘免费下载|Python开发入门篇 提取码:2sby  内容简介 Python是目前最流行的动态脚本语言之一.本书共27章,由浅入深.全面系统地介绍了利 ...

  4. 《Android NFC 开发实战详解 》简介+源码+样章+勘误ING

    <Android NFC 开发实战详解>简介+源码+样章+勘误ING SkySeraph Mar. 14th  2014 Email:skyseraph00@163.com 更多精彩请直接 ...

  5. Cocos2d-x 3.X手游开发实例详解

    Cocos2d-x 3.X手游开发实例详解(最新最简Cocos2d-x手机游戏开发学习方法,以热门游戏2048.卡牌为例,完整再现手游的开发过程,实例丰富,代码完备,Cocos2d-x作者之一林顺和泰 ...

  6. 《iOS 7 应用开发实战详解》

    <iOS 7 应用开发实战详解> 基本信息 作者: 朱元波    管蕾 出版社:人民邮电出版社 ISBN:9787115343697 上架时间:2014-4-25 出版日期:2014 年5 ...

  7. hadoop应用开发技术详解

    <大 数据技术丛书:Hadoop应用开发技术详解>共12章.第1-2章详细地介绍了Hadoop的生态系统.关键技术以及安装和配置:第3章是 MapReduce的使用入门,让读者了解整个开发 ...

  8. 《Hadoop应用开发技术详解》

    <Hadoop应用开发技术详解> 基本信息 作者: 刘刚 丛书名: 大数据技术丛书 出版社:机械工业出版社 ISBN:9787111452447 上架时间:2014-1-10 出版日期:2 ...

  9. Thrift实现C#调用Java开发步骤详解

    概述 Thrift实现C#调用Java开发步骤详解 详细 代码下载:http://www.demodashi.com/demo/10946.html Apache Thrift 是 Facebook ...

随机推荐

  1. B/S与C/S架构

    1.CS.BS架构定义 CS(Client/Server):客户端----服务器结构.C/S结构在技术上很成熟,它的主要特点是交互性强.具有安全的存取模式.网络通信量低.响应速度快.利于处理大量数据. ...

  2. String 类

    一.String类String类在java.lang包中,java使用String类创建一个字符串变量,字符串变量属于对象.java把String类声明的final类,不能有类.String类对象创建 ...

  3. 如何在Eclipse中快速添加main方法

    在创建类时自动添加,只需要勾选"public static void main(String[]   args)"

  4. java常用的几种线程池比较

    1. 为什么使用线程池 诸如 Web 服务器.数据库服务器.文件服务器或邮件服务器之类的许多服务器应用程序都面向处理来自某些远程来源的大量短小的任务.请求以某种方式到达服务器,这种方式可能是通过网络协 ...

  5. UDP网络编程

    概念: UDP协议(用户数据报协议)是无连接,不可靠的,无序的.速度比较快, UDP协议以数据报作为数据传输的载体 进行数据传输时,首先将传输的数据定义成数据报(Datagram),在数据报中指明数据 ...

  6. 从头开始搭建一个VSCode+NetCore的项目

    看这个前,先要对VS开发C#有所了解 获取作案工具 NetCore SDK https://www.microsoft.com/net/learn/get-started/windows 安装 建立工 ...

  7. Jmeter(十七)_驱动浏览器做GUI测试

    jmeter不光可以完成性能测试.接口测试,现在也可以依靠WebDriver来完成GUI的功能自动化测试了,是不是很神奇? 1:下载JMeterPlugins-WebDriver-1.3.1.zip, ...

  8. Kafka系列之-Kafka Protocol实例分析

    本文基于A Guide To The Kafka Protocol文档,以及Spark Streaming中实现的org.apache.spark.streaming.kafka.KafkaClust ...

  9. 简单将sublime text 配置为lua或c#一键编译运行环境

    lua { "cmd": "luajit $file", "selector":"source.lua" } C { & ...

  10. 数据库的case when 使用实例

    本文作者:苏生米沿 本文地址:http://blog.csdn.net/sushengmiyan/article/details/50471210 需求很简单,我有一个部门和部门的请假申请表.表数据简 ...