当前虽然编译成功了,但是对于我们自己的目标板并不太适用。还得做一系列得修改。
一、lds 文件分析
u-boot 中最重要得链接文件即是,u-boot.lds。我们可以查看我们编译出来得 u-boot.lds 文件进行分析,原始文件在 arch/arm/cpu/ 下,编译出来得去掉了不想关得选项。
u-boot.lds脚本文件告诉链接器linker如何布局代码段、数据段、bss段等,已经配置了u-boot自拷贝(从flash到RAM的copy)的内容。另外,还简要的涉及了动态链接技术等。
1 /* 指定输出的可执行文件 elf 格式,32位,小端 */ 2 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") 3 /* 指定输出可执行文件的平台为 arm */ 4 OUTPUT_ARCH(arm) 5 /* 指定输出可执行文件的起始代码段为_start */ 6 ENTRY(_start) 7 /* 指定可执行文件的全局入口点,通常这个地址都放在ROM(flash)0x0位置。 8 * 必须使编译器知道这个地址 */ 9 SECTIONS 10 { 11 /* 从0x0位置开始 */ 12 . = 0x00000000; 13 /* 代码以4字节对齐 */ 14 . = ALIGN(4); 15 /* 代码段 */ 16 .text : 17 { 18 /* u-boot将自己copy到RAM,此为需要copy的程序的start */ 19 *(.__image_copy_start) 20 /* ./arch/arm/lib/vectors.S,异常向量表 */ 21 *(.vectors) 22 /* ./arch/arm/cpu/arm920t/start.S */ 23 arch/arm/cpu/arm920t/start.o (.text*) 24 /* 其他的代码段放在这里,即 start.S/vector.S 之后 */ 25 *(.text*) 26 } 27 /* 代码段结束后,有可能4bytes不对齐了,此时做好4bytes对齐,以开始后面的.rodata段 */ 28 . = ALIGN(4); 29 /* 在代码段之后,存放read only数据段 */ 30 .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } 31 /* 4bytes对齐,以开始接下来的.data段 */ 32 . = ALIGN(4); 33 /* 可读写数据段 */ 34 .data : { 35 *(.data*) 36 } 37 /* 4字节对齐 */ 38 . = ALIGN(4); 39 /* 当前地址为4字节对齐后的地址 */ 40 . = .; 41 /* 4字节对齐 */ 42 . = ALIGN(4); 43 /* .data段结束后,紧接着存放u-boot自有的一些function,例如u-boot command等 */ 44 .u_boot_list : { 45 KEEP(*(SORT(.u_boot_list*))); 46 } 47 . = ALIGN(4); 48 /* UEFI支持, */ 49 .__efi_runtime_start : { 50 *(.__efi_runtime_start) 51 } 52 /* */ 53 .efi_runtime : { 54 *(efi_runtime_text) 55 *(efi_runtime_data) 56 } 57 /* */ 58 .__efi_runtime_stop : { 59 *(.__efi_runtime_stop) 60 } 61 /* */ 62 .efi_runtime_rel_start : 63 { 64 *(.__efi_runtime_rel_start) 65 } 66 /* */ 67 .efi_runtime_rel : { 68 *(.relefi_runtime_text) 69 *(.relefi_runtime_data) 70 } 71 /* UEFI结束 */ 72 .efi_runtime_rel_stop : 73 { 74 *(.__efi_runtime_rel_stop) 75 } 76 /* 4字节对齐 */ 77 . = ALIGN(4); 78 /* 至此,u-boot需要自拷贝的内容结束,总结一下,包括代码段,数据段,以及u_boot_list */ 79 .image_copy_end : 80 { 81 *(.__image_copy_end) 82 } 83 /* 在老的uboot中,如果我们想要uboot启动后把自己拷贝到内存中的某个地方,只要把要拷贝的地址写给TEXT_BASE即可, 84 * 然后boot启动后就会把自己拷贝到TEXT_BASE内的地址处运行,在拷贝之前的代码都是相对的,不能出现绝对的跳转,否则会跑飞。 85 * 在新版的uboot里,TEXT_BASE的含义改变了。它表示用户要把这段代码加载到哪里,通常是通过串口等工具。 86 * 然后搬移的时候由uboot自己计算一个地址来进行搬移。新版的uboot采用了动态链接技术,在lds文件中有__rel_dyn_start和__rel_dyn_end, 87 * 这两个符号之间的区域存放着动态链接符号,只要给这里面的符号加上一定的偏移,拷贝到内存中代码的后面相应的位置处, 88 * 就可以在绝对跳转中找到正确的函数。 */ 89 .rel_dyn_start : 90 { 91 *(.__rel_dyn_start) 92 } 93 /* 动态链接符存放在的段 */ 94 .rel.dyn : { 95 *(.rel*) 96 } 97 /* 动态链接符段结束 */ 98 .rel_dyn_end : 99 { 100 *(.__rel_dyn_end) 101 } 102 .end : 103 { 104 *(.__end) 105 } 106 /* bin文件结束 */ 107 _image_binary_end = .; 108 . = ALIGN(4096); 109 .mmutable : { 110 *(.mmutable) 111 } 112 113 /* .bss节包含了程序中所有未初始化的全局变量 */ 114 .bss_start __rel_dyn_start (OVERLAY) : { 115 KEEP(*(.__bss_start)); 116 __bss_base = .; 117 } 118 .bss __bss_base (OVERLAY) : { 119 *(.bss*) 120 . = ALIGN(4); 121 __bss_limit = .; 122 } 123 /* bss段结束 */ 124 .bss_end __bss_limit (OVERLAY) : { 125 KEEP(*(.__bss_end)); 126 } 127 128 .dynsym _image_binary_end : { *(.dynsym) } 129 .dynbss : { *(.dynbss) } 130 .dynstr : { *(.dynstr*) } 131 .dynamic : { *(.dynamic*) } 132 .plt : { *(.plt*) } 133 .interp : { *(.interp*) } 134 .gnu.hash : { *(.gnu.hash) } 135 .gnu : { *(.gnu*) } 136 .ARM.exidx : { *(.ARM.exidx*) } 137 .gnu.linkonce.armexidx : { *(.gnu.linkonce.armexidx.*) } 138 }
二、norflash 介绍
ARM的启动都是从0地址开始,所不同的是地址的映射不一样。在 arm 上电的时候,要想让 arm 知道以某种方式(地址映射方式)运行,不可能通过你写的某段程序控制,因为这时候你的程序还没启动,这时候arm会通过引脚的电平来判断。
2.1 硬件
2.1.1 存储器地址
s3c2440 的存储器控制器为访问外部存储的需要器提供了存储器控制信号。 存储器控制器的地址空间总共有 8 个 bank,每个bank 为128M,总共为1G。除了 BANK0(16/32 位)之外,其它全部 BANK 都可编程访问位宽(8/16/32 位) 。
- 8 个存储器 Bank
- 6 个存储器 Bank 为 ROM,SRAM 等
- 其余 2 个存储器 Bank 为 ROM,SRAM,SDRAM 等
- 7 个固定的存储器 Bank 起始地址
- 1 个可变的存储器 Bank 起始地址并 Bank 大小可编程
- 所有存储器 Bank 的访问周期可编程
- OM管脚是使能NAND Flash 的管脚,当OM=00时,是表示使用 NAND Flash 为引导 ROM。
- nGCS0 为片选信号控制
- 0x0000_0000 这些为存储器地址。
- BANK 6 和 BANK 7 必须为相同的存储器大小
2.1.2 OM管脚
OM有两个管脚,用来控制存储器。
BANK0(nGCS0)的数据总线应当配置为 16 位或 32 位的宽度。因为 BANK0 是作为引导 ROM 的 bank(映射到 0x0000_0000),应当在第一个 ROM 访问前决定 BANK0 的总线宽度,其依赖于复位时 OM[1:0]的逻辑电平。
2.1.3 存储器概念
- SDRAM(Synchronous Dynamic Random Access Memory):同步动态随机存取存储器,
- 同步是指Memory工作需要步时钟,内部的命令的发送与数据的传输都以它为基准;
- 动态是指存储阵列需要不断的刷新来保证数据不丢失;
- 随机是指数据不是线性依次存储,而是由指定地址进行数据读写,简单的说,它就是cpu使用的外部内存,即我们常说的内存条。
- 主要用于程序执行时的程序存储、执行或计算
- SRAM是英文Static RAM的缩写,它是一种具有静止存取功能的内存,不需要刷新电路即能保存它内部存储的数据,速度比SDRAM快,一般用作高速缓冲存储器(Cache)。
- norflash:非易失闪存,是一种外部存储介质,芯片内执行(XIP,eXecute In Place),这样应用程序可以直接在flash闪存内运行,不必再把代码读到系统RAM中,
- 由于它有地址总线,cpu可以直接从norflash中取指,直接从FLASH中运行程序,但是工艺复杂,价格比较贵,容量较小(1~4M),NOR的传输效率很高,擦初和写操作效率很低
- nandflash:它也是非易失闪存(掉电不丢失)的一种,但是它虽然有数据总线,但是没有地址总线,所以cpu不能直接从nandflash中取指运行,由于它价格便宜,所以常常用来存储大量数据,和我们常说的硬盘类似。
2.2 norflash 启动
- S3C2440的启动时读取的第一条指令是在0x00上,分别为nand flash和nor flash上启动。
- Nor flash的有自己的地址线和数据线,可以采用类似于memory的随机访问方式,在nor flash上可以直接运行程序,所以nor flash可以直接用来做 boot,采用 nor flash 启动的时候会把地址映射到 0x00 上。
- 任何flash器件的写入操作只能在空或已擦除的单元内进行
- 擦除NOR器件时是以64~128KB的块进行的,执行一个写入/擦除操作的时间为5s,NORFLASHSECTOR擦除时间视品牌、大小不同而不同,比如,4MFLASH,有的SECTOR擦除时间为60ms,而有的需要最大6S
- Nand flash是IO设备,数据、地址、控制线都是共用的,需要软件区控制读取时序,所以不能像nor flash、内存一样随机访问,不能EIP(片上运行),因此不能直接作为boot。
- 在u-boot 启动中,需要把 程序拷贝到 SDRAM中去运行,也可以不用拷贝。
- nor 启动的时候,CPU的0地址就指向 norflash
2.2.1 norflash 电路
运行的目标开发板为 JZ2440 开发板。norflash 型号为 MX29LV160DBTI,16M存储空间,
2.2.2 代码修改