移植u-boot-1.3.4到S3C2440一.
预备知识:
1. 首先,U-Boot1.3.4还没有支持s3c2440,移植仍是用2410的文件稍作修改而成的。
2. 2440和2410的区别:
2440和2410的区别主要是2440的主频更高,增加了摄像头接口和AC‘97音频接口;寄存器方面,除了新增模 块的寄存器外,移植所要注意的是NAND FlASH控制器的寄存器有较大的变化、芯片的时钟频率控制寄存器(芯片PLL的寄存器)有一定的变化。其他寄存器基本是兼容的。
3. 你开发板的boot方式是什么,开发板上电以后是怎么执行的。
一般来说三星的开发板有三种启动方式:nand、nor、ram。具体用那一种方式来启动决定于CPU的0M[0:1]这两个引脚,具体请参考S3C2440的datasheet nand:对于2440来说,CPU是不给nand-flash分配地址空间的,nand-flash只相当于CPU的一个外设,S3C2440做了一个从nand-flash启动的机制。开发板一上电,CPU就自动复制 nand-flash里面的前4K-Bytes内容到S3C2440内部集成的SDRAM,然后把4K内容所在 的RAM映射到S3C2440的0地址,从0地址开始执行。这4K的内容主要负责下面这些工 作:初始化中断矢量、设定CPU的工作模式为SVC32模式、屏蔽看门狗、屏蔽中断、 初始化时钟、把整个u-boot重定向到外部SDRAM、跳到主要的C函数入口。nor: 早期的时候利用nor-flash启动的方式比较多,就是把u-boot烧写到nor-flash里面, 直接把nor-flash映射到S3C2440的0地址,上电从0地址开始执行。ram: 直接把u-boot放到外部SDRAM上跑,这一般debug时候用到。
4. u-boot程序的入口地址问题
要理解程序的入口地址,自然想到的是连接文件,首先看看开发板相对于某个开发板的连接
文
件"/board/你的开发板/u-boot.lds",看一个2410的例子:
ENTRY(_start)SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text : { cpu/arm920t/start.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); __bss_start = .; .bss : { *(.bss) } _end = .;}(1) 从ENTRY(_start)可以看出u-boot的入口函数是_start,这个没错(2) 从. = 0x00000000也许可以看出_start的地址是0x00000000,事实并不是这样的,这里的0x00000000没效,在连接的时候最终会被TETX_BASE所代替的,具体请参考u-boot根目录下的config.mk.(3) 网上很多说法是 _start=TEXT_BASE,我想这种说法也是正确的,但没有说具体原因。本人的理解是这样的,TEXT_BASE表示text段的起始地址,而从.text :{ cpu/arm920t/start.o (.text) *(.text)}看,放在text段的第一个文件就是start.c编译后的内容,而start.c中的第一个函数就是_start,所以 _start应该是放在text段的起始位置,因此说_start=TEXT_BASE也不为过。
5. 一直不明白的U-BOOT是怎样从4Ksteppingstone跳到RAM中执行的,现在终于明白了。关键在于:
ldr pc, _start_armboot_start_armboot: .word start_armboot这两条语句,ldr pc, _start_armboot指令把_start_armboot这个标签的地方存放的内容(也即是start_armboot)移到PC寄存器里面,start_armboot是一个函数地址,在编译的时候给分配了一个绝对地址,所以上面语句实际上是完成了一个绝对地址的跳转。而我一直不明白的为什么在start.S里面有很多BL,B跳转语句都没有跳出4Ksteppingstone,原因是他们都是相对于PC的便宜的跳转,而不是绝对地址的跳转。还有要补充一下LDR,MOV,LDR伪指令的区别。LDR R0,0x12345678 //把地址0x12345678存放的内容放到R0里面MOV R0,#x //把立即数x放到R0里面,x必须是一个8 bits的数移到偶数次得到的数。LDR R0,=0x12345678 //把立即数0x12345678放到R0里面
6. 在移植u-boot-1.3.3以上版本的时候要注意:
在u-boot1.3.3及以上版本Makefile有一定的变化,使得对于24x0处理器从nand启动的遇到问题。也就是网上有人说的:无法运行过lowlevel_init。其实这个问题是由于编译器将我们自己添加的用于nandboot的子函数nand_read_ll放到了4K之后造成的(到这不理解的话,请仔细看看24x0处理器nandboot原理)。我是在运行失败后,利用mini2440的4个LED调试发现u-boot根本没有完成自我拷贝,然后看了uboot根目录下的System.map文件就可知道原因。解决办法其实很简单:
将__LIBS := $(subst $(obj),,$(LIBS)) $(subst $(obj),,$(LIBBOARD))
改为__LIBS := $(subst $(obj),,$(LIBBOARD)) $(subst $(obj),,$(LIBS))
7. 然后说一下跳转指令。ARM有两种跳转方式。
(1)mov pc <跳转地址〉 这种向程序计数器PC直接写跳转地址,能在4GB连续空间内任意跳转。(2)通过B BL BLX BX可以完成在当前指令向前或者向后32MB的地址空间的跳转(为什么是32MB呢?寄存器是32位的,此时的值是24位有符号数,所以32MB)。B是最简单的跳转指令。要注意的是,跳转指令的实际值不是绝对地址,而是相对地址——是相对当前PC值的一个偏移量,它的值由汇编器计算得出。BL非常常用。它在跳转之前会在寄存器LR(R14)中保存PC的当前内容。BL的经典用法如下: bl NEXT ; 跳转到NEXT …… NEXT …… mov pc, lr ; 从子程序返回。
预备知识:
1. 首先,U-Boot1.3.4还没有支持s3c2440,移植仍是用2410的文件稍作修改而成的。
2. 2440和2410的区别:
2440和2410的区别主要是2440的主频更高,增加了摄像头接口和AC‘97音频接口;寄存器方面,除了新增模 块的寄存器外,移植所要注意的是NAND FlASH控制器的寄存器有较大的变化、芯片的时钟频率控制寄存器(芯片PLL的寄存器)有一定的变化。其他寄存器基本是兼容的。
3. 你开发板的boot方式是什么,开发板上电以后是怎么执行的。
一般来说三星的开发板有三种启动方式:nand、nor、ram。具体用那一种方式来启动决定于CPU的0M[0:1]这两个引脚,具体请参考S3C2440的datasheet nand:对于2440来说,CPU是不给nand-flash分配地址空间的,nand-flash只相当于CPU的一个外设,S3C2440做了一个从nand-flash启动的机制。开发板一上电,CPU就自动复制 nand-flash里面的前4K-Bytes内容到S3C2440内部集成的SDRAM,然后把4K内容所在 的RAM映射到S3C2440的0地址,从0地址开始执行。这4K的内容主要负责下面这些工 作:初始化中断矢量、设定CPU的工作模式为SVC32模式、屏蔽看门狗、屏蔽中断、 初始化时钟、把整个u-boot重定向到外部SDRAM、跳到主要的C函数入口。nor: 早期的时候利用nor-flash启动的方式比较多,就是把u-boot烧写到nor-flash里面, 直接把nor-flash映射到S3C2440的0地址,上电从0地址开始执行。ram: 直接把u-boot放到外部SDRAM上跑,这一般debug时候用到。
4. u-boot程序的入口地址问题
要理解程序的入口地址,自然想到的是连接文件,首先看看开发板相对于某个开发板的连接
文
件"/board/你的开发板/u-boot.lds",看一个2410的例子:
ENTRY(_start)SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text : { cpu/arm920t/start.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); __bss_start = .; .bss : { *(.bss) } _end = .;}(1) 从ENTRY(_start)可以看出u-boot的入口函数是_start,这个没错(2) 从. = 0x00000000也许可以看出_start的地址是0x00000000,事实并不是这样的,这里的0x00000000没效,在连接的时候最终会被TETX_BASE所代替的,具体请参考u-boot根目录下的config.mk.(3) 网上很多说法是 _start=TEXT_BASE,我想这种说法也是正确的,但没有说具体原因。本人的理解是这样的,TEXT_BASE表示text段的起始地址,而从.text :{ cpu/arm920t/start.o (.text) *(.text)}看,放在text段的第一个文件就是start.c编译后的内容,而start.c中的第一个函数就是_start,所以 _start应该是放在text段的起始位置,因此说_start=TEXT_BASE也不为过。
5. 一直不明白的U-BOOT是怎样从4Ksteppingstone跳到RAM中执行的,现在终于明白了。关键在于:
ldr pc, _start_armboot_start_armboot: .word start_armboot这两条语句,ldr pc, _start_armboot指令把_start_armboot这个标签的地方存放的内容(也即是start_armboot)移到PC寄存器里面,start_armboot是一个函数地址,在编译的时候给分配了一个绝对地址,所以上面语句实际上是完成了一个绝对地址的跳转。而我一直不明白的为什么在start.S里面有很多BL,B跳转语句都没有跳出4Ksteppingstone,原因是他们都是相对于PC的便宜的跳转,而不是绝对地址的跳转。还有要补充一下LDR,MOV,LDR伪指令的区别。LDR R0,0x12345678 //把地址0x12345678存放的内容放到R0里面MOV R0,#x //把立即数x放到R0里面,x必须是一个8 bits的数移到偶数次得到的数。LDR R0,=0x12345678 //把立即数0x12345678放到R0里面
6. 在移植u-boot-1.3.3以上版本的时候要注意:
在u-boot1.3.3及以上版本Makefile有一定的变化,使得对于24x0处理器从nand启动的遇到问题。也就是网上有人说的:无法运行过lowlevel_init。其实这个问题是由于编译器将我们自己添加的用于nandboot的子函数nand_read_ll放到了4K之后造成的(到这不理解的话,请仔细看看24x0处理器nandboot原理)。我是在运行失败后,利用mini2440的4个LED调试发现u-boot根本没有完成自我拷贝,然后看了uboot根目录下的System.map文件就可知道原因。解决办法其实很简单:
将__LIBS := $(subst $(obj),,$(LIBS)) $(subst $(obj),,$(LIBBOARD))
改为__LIBS := $(subst $(obj),,$(LIBBOARD)) $(subst $(obj),,$(LIBS))
7. 然后说一下跳转指令。ARM有两种跳转方式。
(1)mov pc <跳转地址〉 这种向程序计数器PC直接写跳转地址,能在4GB连续空间内任意跳转。(2)通过B BL BLX BX可以完成在当前指令向前或者向后32MB的地址空间的跳转(为什么是32MB呢?寄存器是32位的,此时的值是24位有符号数,所以32MB)。B是最简单的跳转指令。要注意的是,跳转指令的实际值不是绝对地址,而是相对地址——是相对当前PC值的一个偏移量,它的值由汇编器计算得出。BL非常常用。它在跳转之前会在寄存器LR(R14)中保存PC的当前内容。BL的经典用法如下: bl NEXT ; 跳转到NEXT …… NEXT …… mov pc, lr ; 从子程序返回。
