JZ2440移植uboot

开发板:JZ2440V3

U-Boot版本:u-boot-2012.04.01

1.首先下载源码,上传到服务器,解压缩。

tar -jxvf u-boot-2012.04.01.tar.bz2

2.新建一个项目,这个版本的uboot自带的有smdk2410项目的,通过阅读源码根目录下的README文件发现,新建一个项目主需要以下几步:
(1)在根目录下的boards.cfg文件中,仿照smdk2410项目,添加下面这段话:
jz2440                         arm         arm920t     jz2440                  samsung        s3c24x0
(2)在board/samsung/目录先新建文件夹jz2440;
cp -fr smdk2410 jz2440
(3)在include/configs/配置文件目录下新建项目的配置文件jz2440.h;

cp smdk2410.h jz2440.h

3.编译之前的配置
make jz2440_config
4.进行编译

make

注意:这个版本的uboot使用3.4.5的编译工具会发生段错误,需要使用4.3.2版本的arm-linux-gcc工具。

将生产的u-boot.bin文件烧写进Nor Flash中,发现串口没有任何的输出。我们现在来分析源码是什么原因导致的?

我们先来看编译链接的过程:

arm-linux-ld  -pie -T u-boot.lds -Bstatic -Ttext 0x0 $UNDEF_SYM arch/arm/cpu/arm920t/start.o \
--start-group api/libapi.o arch/arm/cpu/arm920t/libarm920t.o arch/arm/cpu/arm920t/s3c24x0/libs3c24x0.o 
arch/arm/lib/libarm.o common/libcommon.o disk/libdisk.o drivers/bios_emulator/libatibiosemu.o 
drivers/block/libblock.o drivers/dma/libdma.o drivers/fpga/libfpga.o drivers/gpio/libgpio.o 
drivers/hwmon/libhwmon.o drivers/i2c/libi2c.o drivers/input/libinput.o drivers/misc/libmisc.o 
drivers/mmc/libmmc.o drivers/mtd/libmtd.o drivers/mtd/nand/libnand.o drivers/mtd/onenand/libonenand.o 
drivers/mtd/spi/libspi_flash.o drivers/mtd/ubi/libubi.o drivers/net/libnet.o drivers/net/phy/libphy.o 
drivers/pci/libpci.o drivers/pcmcia/libpcmcia.o drivers/power/libpower.o drivers/rtc/librtc.o 
drivers/serial/libserial.o drivers/spi/libspi.o drivers/twserial/libtws.o drivers/usb/eth/libusb_eth.o 
drivers/usb/gadget/libusb_gadget.o drivers/usb/host/libusb_host.o drivers/usb/musb/libusb_musb.o 
drivers/usb/phy/libusb_phy.o drivers/usb/ulpi/libusb_ulpi.o drivers/video/libvideo.o drivers/watchdog/libwatchdog.o 
fs/cramfs/libcramfs.o fs/ext2/libext2fs.o fs/fat/libfat.o fs/fdos/libfdos.o fs/jffs2/libjffs2.o 
fs/reiserfs/libreiserfs.o fs/ubifs/libubifs.o fs/yaffs2/libyaffs2.o lib/libfdt/libfdt.o lib/libgeneric.o 
lib/lzma/liblzma.o lib/lzo/liblzo.o lib/zlib/libz.o net/libnet.o post/libpost.o 
board/samsung/jz2440/libjz2440.o 
--end-group 

从编译链接过程可以得知,链接脚本时u-boot.lds;我们来看这个文件的内容,看看链接地址定的是多少?

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
 . = 0x00000000;            #链接地址
 . = ALIGN(4);
 .text :
 {
  __image_copy_start = .;
  arch/arm/cpu/arm920t/start.o (.text)
  *(.text)
 }
 . = ALIGN(4);
 .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 . = ALIGN(4);
 .data : {
  *(.data)
 }
 . = ALIGN(4);
 . = .;
 __u_boot_cmd_start = .;
 .u_boot_cmd : { *(.u_boot_cmd) }
 __u_boot_cmd_end = .;
 . = ALIGN(4);
 __image_copy_end = .;
 .rel.dyn : {
  __rel_dyn_start = .;
  *(.rel*)
  __rel_dyn_end = .;
 }
 .dynsym : {
  __dynsym_start = .;
  *(.dynsym)
 }
 _end = .;
 . = ALIGN(4096);
 .mmutable : {
  *(.mmutable)
 }
 .bss __rel_dyn_start (OVERLAY) : {
  __bss_start = .;
  *(.bss)
   . = ALIGN(4);
  __bss_end__ = .;
 }
 /DISCARD/ : { *(.dynstr*) }
 /DISCARD/ : { *(.dynamic*) }
 /DISCARD/ : { *(.plt*) }
 /DISCARD/ : { *(.interp*) }
 /DISCARD/ : { *(.gnu*) }
}

从链接脚本可以知道,默认的链接地址是0x00000000;所以,默认只支持Nor Flash启动。从编译链接过程可以得知开发板一上电首先执行的是"arch/arm/cpu/arm920t/start.S"文件。我们现在来分析这个文件,查找为什么在Nor Flash启动时串口没有任何的输出。

记录start.S文件做了哪些事情:

1.set the cpu to SVC32 mode
2.turn off the watchdog
3.mask all IRQs by setting all bits in the INTMR
4.设置时钟比例;FCLK:HCLK:PCLK = 1:2:4
5.flush v4 I/D caches和disable MMU stuff and caches,跳转到lowlevel_init处,设置内存控制器;
6.设置栈,并调用board_init_f函数;
6.1.设置R8寄存器指向的指针gd,并将其指向的内存空间清零;
6.2.调用init_sequence数组中的函数指针指向的各个函数;
6.3.设置系统时钟,设置过GPIO端口;
6.4.最后是重定位代码;relocate_code(addr_sp, id, addr);
分析到这里发现有问题了,默认的是先设置时钟预分频系数,然后初始化内存,然后再C代码中初始化时钟。

而我们设置SDRAM控制器是有严格时序要求的,并不清楚时钟那个HCLK下设置的,所有极有可能出错。

为什么在最后才开始重定位代码呢?

是由于uboot的代码很大,后面的C代码有可能使用全局或静态变量,而全局或静态遍历在链接时的地址是其链接脚本中的地址规定的;在运行时就会去链接地址处寻找这些变量,而开发板的内存地址是从0X30000000地址开始的,所以需要进行重定位。而Nand启动时内部SRAM只有4K的大小,uboot.bin文件要远大于4K;所以要将uboot.bin文件重定位SDRAM中去执行。

这个版本的uboot默认支持Nor启动,为什么将代码重定位之后,还能执行呢?
可以将uboot复制到内存中的任意位置,复制之后为什么还能够执行,程序会自动修改代码;修改变量和函数的地址。假如原来变量的地址是0x100,将代码复制到0x32000000地址处,在访问这个变量的时候就要使用新地址0x32000100了。那么是修改的时候怎么知道原来的地址呢?这就需要在链接的时候添加"-pie"选项。pie选项的含义是:Create a position independent executable。创建位置无关的可执行程序。
当加上pie选项之后,就会在uboot中生成:
.rel.dyn : {
__rel_dyn_start = .;
*(.rel*)
__rel_dyn_end = .;
}
.dynsym : {
__dynsym_start = .;
*(.dynsym)
}
这两个段。程序在运行时可以根据这个两个段来修改变量和函数的地址。注意,有这两个段之后编译出来的bin文件会大很多。

我们首先来分析内存分布情况,再来分析重定位的代码:




    

猜你喜欢

转载自blog.csdn.net/caihaitao2000/article/details/80151620
今日推荐