邮箱:zhuimengcanyang@163.com 痴爱嵌入式技术的蜗牛
分类: 嵌入式
2015-07-13 15:35:55
把程序从flash上拷贝到SDRAM的任何位置,然后修改变量的地址(在flash中定位的地址)到新的地址(在SDRAM中的地址)
在链接的时候,就要加上 “-pie” 选项,使得u-boot.bin里多了"*(.rel*)","*(.dynsym)",这些东西都需要在start.S等源程序里面调用。
这样将会使得重定位之前的代码可能大于4K,导致4k之外的地址运行错误(需要读写nand flash)。
nand flash 启动时:
(1)前4k的代码自动复制到2440内部RAM中,然后开始从RAM的零地址处取指令执行,在4k代码执行完前,将nand flash中的代码复制到SDRAM中,完成代码重定位;
(2)跳转到SDRAM中执行之前的代码必须是位置无关码。
2.1 去掉 "-pie"选项
(注意: 不是修改Makefile了)
在uboot源码主目录下,搜索“-pie”相关的引用: grep "\-pie" * -nR
book@book-desktop:/work/system/u-boot-2012.04.01$ grep "\-pie" * -nR
arch/x86/config.mk:43:LDFLAGS_FINAL += --gc-sections -pie
arch/arm/config.mk:75:LDFLAGS_u-boot += -pie
doc/README.arm-relocation:3:At arch level: add linker flag -pie
arch/arm/config.mk:75:LDFLAGS_u-boot += -pie 去掉这行
# needed for relocation
ifndef CONFIG_NAND_SPL
#LDFLAGS_u-boot += -pie
endif
2.2 修改链接脚本: /arch/arm/cpu/u-boot.lds: 链接脚本是make时候自动生成的。
可以利用命令搜索: book@book-desktop:/work/system/u-boot-2012.04.01$ find -name "u-boot.lds"
把start.S, init.c, lowlevel_init.S等文件放在最前面 (为什么要放在最前面???想想看前面说的nand启动过程,前4k的代码要定死在前面的位置。否则重定位后,可能无法运行。)
将上面的.S和.c文件编译成一个库文件:libsmdk2440.o,所以只要加一个库文件就可以了。
board/samsung/smdk2440/libsmdk2440.o
/arch/arm/cpu/u-boot.lds
- /*
- * Copyright (c) 2004-2008 Texas Instruments
- *
- * (C) Copyright 2002
- * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
- OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
- OUTPUT_ARCH(arm)
- ENTRY(_start)
- SECTIONS
- {
- . = 0x00000000;
- . = ALIGN(4);
- .text :
- {
- __image_copy_start = .;
- CPUDIR/start.o (.text) // 也就是文件:arch/arm/cpu/arm920t/start.S
- // 添加下面的这句话。 init.c lowlevel_init.S smdk2410.c -> 这几个文件编译链接成一个库文件
- // 为什么要添加这句话?思考一下。(重定位之前的程序必须放在前4K代码处,并且是位置无关码)
- board/samsung/smdk2440/libsmdk2440.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 = .;
- /*
- * Deprecated: this MMU section is used by pxa at present but
- * should not be used by new boards/CPUs.
- */
- . = 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*) }
- }
2.3 参考"毕业班第1课"的start.S, init.c来修改代码
把init.c放入board/samsung/smdk2440目录,修改init.c以及Makefile
修改:init.c
makefile 修改:
- /* NAND FLASH控制器 */
- #define NFCONF (*((volatile unsigned long *)0x4E000000))
- #define NFCONT (*((volatile unsigned long *)0x4E000004))
- #define NFCMMD (*((volatile unsigned char *)0x4E000008))
- #define NFADDR (*((volatile unsigned char *)0x4E00000C))
- #define NFDATA (*((volatile unsigned char *)0x4E000010))
- #define NFSTAT (*((volatile unsigned char *)0x4E000020))
- void nand_read_ll(unsigned int addr, unsigned char *buf, unsigned int len);
- static int isBootFromNorFlash(void)
- {
- volatile int *p = (volatile int *)0;
- int val;
- val = *p;
- *p = 0x12345678;
- if (*p == 0x12345678)
- {
- /* 写成功, 是nand启动 */
- *p = val;
- return 0;
- }
- else
- {
- /* NOR不能像内存一样写 */
- return 1;
- }
- }
- void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len)
- {
- int i = 0;
- /* 如果是NOR启动 */
- if (isBootFromNorFlash())
- {
- while (i < len)
- {
- dest[i] = src[i];
- i++;
- }
- }
- else
- {
- //nand_init();
- nand_read_ll((unsigned int)src, dest, len);
- }
- }
- void clear_bss(void) // 这个函数需要注意
- {
- /*
- .bss __rel_dyn_start (OVERLAY) : {
- __bss_start = .;
- *(.bss)
- . = ALIGN(4);
- __bss_end__ = .;
- }
- */
- extern int __bss_start, __bss_end__; // 从u-boot.lds中找到地址,将原来的"__bss_end"修改为"__bss_end__"
- int *p = &__bss_start;
- for (; p < &__bss_end__; p++)
- *p = 0;
- }
- void nand_init_ll(void)
- {
- #define TACLS 0
- #define TWRPH0 1
- #define TWRPH1 0
- /* 设置时序 */
- NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
- /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
- NFCONT = (1<<4)|(1<<1)|(1<<0);
- }
- static void nand_select(void)
- {
- NFCONT &= ~(1<<1);
- }
- static void nand_deselect(void)
- {
- NFCONT |= (1<<1);
- }
- static void nand_cmd(unsigned char cmd)
- {
- volatile int i;
- NFCMMD = cmd;
- for (i = 0; i < 10; i++);
- }
- static void nand_addr(unsigned int addr)
- {
- unsigned int col = addr % 2048;
- unsigned int page = addr / 2048;
- volatile int i;
- NFADDR = col & 0xff;
- for (i = 0; i < 10; i++);
- NFADDR = (col >> 8) & 0xff;
- for (i = 0; i < 10; i++);
- NFADDR = page & 0xff;
- for (i = 0; i < 10; i++);
- NFADDR = (page >> 8) & 0xff;
- for (i = 0; i < 10; i++);
- NFADDR = (page >> 16) & 0xff;
- for (i = 0; i < 10; i++);
- }
- static void nand_wait_ready(void)
- {
- while (!(NFSTAT & 1));
- }
- static unsigned char nand_data(void)
- {
- return NFDATA;
- }
- void nand_read_ll(unsigned int addr, unsigned char *buf, unsigned int len)
- {
- int col = addr % 2048;
- int i = 0;
- /* 1. 选中 */
- nand_select();
- while (i < len)
- {
- /* 2. 发出读命令00h */
- nand_cmd(0x00);
- /* 3. 发出地址(分5步发出) */
- nand_addr(addr);
- /* 4. 发出读命令30h */
- nand_cmd(0x30);
- /* 5. 判断状态 */
- nand_wait_ready();
- /* 6. 读数据 */
- for (; (col < 2048) && (i < len); col++)
- {
- buf[i] = nand_data();
- i++;
- addr++;
- }
- col = 0;
- }
- /* 7. 取消选中 */
- nand_deselect();
- }
(2)修改CONFIG_SYS_TEXT_BASE为0x33f80000board/samsung/smdk2440/Makefile
- include $(TOPDIR)/config.mk
- LIB = $(obj)lib$(BOARD).o
- COBJS := smdk2410.o init.o
- SOBJS := lowlevel_init.o
- SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
- OBJS := $(addprefix $(obj),$(COBJS))
- SOBJS := $(addprefix $(obj),$(SOBJS))
- $(LIB): $(obj).depend $(OBJS) $(SOBJS)
- $(call cmd_link_o_target, $(OBJS) $(SOBJS))
- #########################################################################
- # defines $(obj).depend target
- include $(SRCTREE)/rules.mk
- sinclude $(obj).depend
- #########################################################################
在目录文件: \include\configs\Smdk2440.h
- #if 0
- #define CONFIG_SYS_TEXT_BASE 0x0
- #else
- // 0x34000000 - 0x33f8000000 = 512K, 这里假定u-boot的大小不超过512K
- #define CONFIG_SYS_TEXT_BASE 0x33f80000
- #endif
(3)修改start.S
- #if 0
- /* Set stackpointer in internal RAM to call board_init_f */
- call_board_init_f:
- ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
- bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
- ldr r0,=0x00000000
- bl board_init_f
- #else
- // 1. 调用C函数之前,先设置好堆栈
- ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
- bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
- // 2. 初始化nand flash,因为nand读写需要专门的时序,所以需要初始化
- bl nand_init_ll
- // 3. 拷贝代码,先设置参数
- mov r0, #0 // r0 =0, 表示源地址
- /*不要用这条伪指令,如果_start的值比较复杂,它会将它存在某个内存地址,但是存在哪里,根本没法知道,由编译器决定,有可能把它存到到4k 之外了。*/
- // ldr r1, =_start
- /* 用这种方法,可以定死存放的地址,该指令的意思是取标号处地址的内容, _TEXT_BASE = 0x33f80000*/
- ldr r1, _TEXT_BASE // r1 = _TEXT_BASE,表示目的地址
- // 注意: 不是 ldr r2, =_bss_start_ofs
ldr r2, _bss_start_ofs // _bss_start_ofs = __bss_start - _start,表示u-boot代码的大小。 这里为什么bss段不拷贝过去呢??
- bl copy_code_to_sdram
- bl clear_bss
- ldr pc, =call_board_init_f // 这句话的意思是:从RAM当中直接跳转到SDRAM中执行
- /* Set stackpointer in internal RAM to call board_init_f */
- call_board_init_f:
- ldr r0,=0x00000000
- bl board_init_f // 在这个函数里,做了重定位,要去掉。
/* unsigned int的值存在r0里,正好给第二阶段的函数board_init_r 用。 */
// 接下来执行第二阶段的代码:
ldr r1, _TEXT_BASE
bl board_init_r /* 调用第二阶段的代码*/
// 这个函数,第一个参数是gd_t 结构体指针, 第二个参数是目标地址,也就是 链接地址 _TEXT_BASE
// 第一个参数 gd_t 结构体,可以由第一阶段的函数 board_init_f 进行返回, 见下面1.4的修改。
// void board_init_r(gd_t *id, ulong dest_addr)
#endif
删掉与重定位的相关代码:
/*
* void relocate_code (addr_sp, gd, addr_moni)
*
* This "function" does not return, instead it continues in RAM
* after relocating the monitor code.
*
*/
.globl relocate_code
relocate_code:
mov r4, r0 /* save addr_sp */
mov r5, r1 /* save addr of gd */
mov r6, r2 /* save addr of destination */
/* Set up the stack */
stack_setup:
mov sp, r4
adr r0, _start
cmp r0, r6 /* 比较链接地址和目的地址,如果相等,则表示不需要拷贝代码 */
beq clear_bss /* skip relocation ,如果相等,不需要重定位,直接清BSS段*/
mov r1, r6 /* r1 <- scratch for copy_loop */
ldr r3, _bss_start_ofs /* r3 = __bss_start - _start: 表示除bss段以外代码的大小 */
add r2, r0, r3 /* r2 <- source end address */
copy_loop:
ldmia r0!, {r9-r10} /* copy from source address [r0] */
stmia r1!, {r9-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end address [r2] */
blo copy_loop
#ifndef CONFIG_SPL_BUILD
/*
* fix .rel.dyn relocations
*/
ldr r0, _TEXT_BASE /* r0 <- Text base */
sub r9, r6, r0 /* r9 <- relocation offset */
ldr r10, _dynsym_start_ofs /* r10 <- sym table ofs */
add r10, r10, r0 /* r10 <- sym table in FLASH */
ldr r2, _rel_dyn_start_ofs /* r2 <- rel dyn start ofs */
add r2, r2, r0 /* r2 <- rel dyn start in FLASH */
ldr r3, _rel_dyn_end_ofs /* r3 <- rel dyn end ofs */
add r3, r3, r0 /* r3 <- rel dyn end in FLASH */
fixloop:
ldr r0, [r2] /* r0 <- location to fix up, IN FLASH! */
add r0, r0, r9 /* r0 <- location to fix up in RAM */
ldr r1, [r2, #4]
and r7, r1, #0xff
cmp r7, #23 /* relative fixup? */
beq fixrel
cmp r7, #2 /* absolute fixup? */
beq fixabs
/* ignore unknown type of fixup */
b fixnext
fixabs:
/* absolute fix: set location to (offset) symbol value */
mov r1, r1, LSR #4 /* r1 <- symbol index in .dynsym */
add r1, r10, r1 /* r1 <- address of symbol in table */
ldr r1, [r1, #4] /* r1 <- symbol value */
add r1, r1, r9 /* r1 <- relocated sym addr */
b fixnext
fixrel:
/* relative fix: increase location by offset */
ldr r1, [r0]
add r1, r1, r9
fixnext:
str r1, [r0]
add r2, r2, #8 /* each rel.dyn entry is 8 bytes */
cmp r2, r3
blo fixloop
#endif
clear_bss:
#ifndef CONFIG_SPL_BUILD
ldr r0, _bss_start_ofs
ldr r1, _bss_end_ofs
mov r4, r6 /* reloc addr */
add r0, r0, r4
add r1, r1, r4
mov r2, #0x00000000 /* clear */
clbss_l:str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
bne clbss_l
bl coloured_LED_init
bl red_led_on
#endif2.4 修改board_init_f, 把relocate_code去掉
\arch\arm\lib\Board.c
- unsigned int board_init_f(ulong bootflag)
- {
- bd_t *bd;
- init_fnc_t **init_fnc_ptr;
- gd_t *id;
- ulong addr, addr_sp;
- #ifdef CONFIG_PRAM
- ulong reg;
- #endif
- bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_F, "board_init_f");
- /* Pointer is writable since we allocated a register for it */
- gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);
- /* compiler optimization barrier needed for GCC >= 3.4 */
- __asm__ __volatile__("": : :"memory");
- memset((void *)gd, 0, sizeof(gd_t));
- gd->mon_len = _bss_end_ofs;
- #ifdef CONFIG_OF_EMBED
- /* Get a pointer to the FDT */
- gd->fdt_blob = _binary_dt_dtb_start;
- #elif defined CONFIG_OF_SEPARATE
- /* FDT is at end of image */
- gd->fdt_blob = (void *)(_end_ofs + _TEXT_BASE);
- #endif
- /* Allow the early environment to override the fdt address */
- gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16,
- (uintptr_t)gd->fdt_blob);
- for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
- if ((*init_fnc_ptr)() != 0) {
- hang ();
- }
- }
- #ifdef CONFIG_OF_CONTROL
- /* For now, put this check after the console is ready */
- if (fdtdec_prepare_fdt()) {
- panic("** CONFIG_OF_CONTROL defined but no FDT - please see "
- "doc/README.fdt-control");
- }
- #endif
- debug("monitor len: %08lX\n", gd->mon_len);
- /*
- * Ram is setup, size stored in gd !!
- */
- debug("ramsize: %08lX\n", gd->ram_size);
- #if defined(CONFIG_SYS_MEM_TOP_HIDE)
- /*
- * Subtract specified amount of memory to hide so that it won't
- * get "touched" at all by U-Boot. By fixing up gd->ram_size
- * the Linux kernel should now get passed the now "corrected"
- * memory size and won't touch it either. This should work
- * for arch/ppc and arch/powerpc. Only Linux board ports in
- * arch/powerpc with bootwrapper support, that recalculate the
- * memory size from the SDRAM controller setup will have to
- * get fixed.
- */
- gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE;
- #endif
- addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size; /* gd->ram_size = PHYS_SDRAM_1_SIZE = 64Mb*/
- /* 将addr指向SDRAM的最顶端*/
- #ifdef CONFIG_LOGBUFFER
- #ifndef CONFIG_ALT_LB_ADDR
- /* reserve kernel log buffer */
- addr -= (LOGBUFF_RESERVE);
- debug("Reserving %dk for kernel logbuffer at %08lx\n", LOGBUFF_LEN,
- addr);
- #endif
- #endif
- #ifdef CONFIG_PRAM
- /*
- * reserve protected RAM
- */
- reg = getenv_ulong("pram", 10, CONFIG_PRAM);
- addr -= (reg << 10); /* size is in kB */
- debug("Reserving %ldk for protected RAM at %08lx\n", reg, addr);
- #endif /* CONFIG_PRAM */
- #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
- /* reserve TLB table */
- addr -= (4096 * 4);
- /* round down to next 64 kB limit */
- addr &= ~(0x10000 - 1);
- gd->tlb_addr = addr;
- debug("TLB table at: %08lx\n", addr);
- #endif
- /* round down to next 4 kB limit */
- addr &= ~(4096 - 1);
- debug("Top of RAM usable for U-Boot at: %08lx\n", addr);
- #ifdef CONFIG_LCD
- #ifdef CONFIG_FB_ADDR
- gd->fb_base = CONFIG_FB_ADDR;
- #else
- /* reserve memory for LCD display (always full pages) */
- addr = lcd_setmem(addr);
- gd->fb_base = addr;
- #endif /* CONFIG_FB_ADDR */
- #endif /* CONFIG_LCD */
- /*
- * reserve memory for U-Boot code, data & bss
- * round down to next 4 kB limit
- */
- addr -= gd->mon_len; /*gd->mon_len = __bss_end__ - _start 为整个u-boot 代码的长度*/
- addr &= ~(4096 - 1);
- debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr);
- #ifndef CONFIG_SPL_BUILD
- /*
- * reserve memory for malloc() arena
- */
- addr_sp = addr - TOTAL_MALLOC_LEN;
- debug("Reserving %dk for malloc() at: %08lx\n",
- TOTAL_MALLOC_LEN >> 10, addr_sp);
- /*
- * (permanently) allocate a Board Info struct
- * and a permanent copy of the "global" data
- */
- addr_sp -= sizeof (bd_t);
- bd = (bd_t *) addr_sp;
- gd->bd = bd;
- debug("Reserving %zu Bytes for Board Info at: %08lx\n",
- sizeof (bd_t), addr_sp);
- #ifdef CONFIG_MACH_TYPE
- gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */
- #endif
- addr_sp -= sizeof (gd_t);
- id = (gd_t *) addr_sp;
- debug("Reserving %zu Bytes for Global Data at: %08lx\n",
- sizeof (gd_t), addr_sp);
- /* setup stackpointer for exeptions */
- gd->irq_sp = addr_sp;
- #ifdef CONFIG_USE_IRQ
- addr_sp -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);
- debug("Reserving %zu Bytes for IRQ stack at: %08lx\n",
- CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ, addr_sp);
- #endif
- /* leave 3 words for abort-stack */
- addr_sp -= 12;
- /* 8-byte alignment for ABI compliance */
- addr_sp &= ~0x07;
- #else
- addr_sp += 128; /* leave 32 words for abort-stack */
- gd->irq_sp = addr_sp;
- #endif
- debug("New Stack Pointer is: %08lx\n", addr_sp);
- #ifdef CONFIG_POST
- post_bootmode_init();
- post_run(NULL, POST_ROM | post_bootmode_get(0));
- #endif
- gd->bd->bi_baudrate = gd->baudrate;
- /* Ram ist board specific, so move it to board code ... */
- dram_init_banksize();
- display_dram_config(); /* and display it */
- gd->relocaddr = addr;
- gd->start_addr_sp = addr_sp;
- gd->reloc_off = addr - _TEXT_BASE;
- debug("relocation Offset is: %08lx\n", gd->reloc_off);
- memcpy(id, (void *)gd, sizeof(gd_t));
- // relocate_code(addr_sp, id, addr); // 去掉这句话,因为我们在之前加入了 重定位 代码
return id;
- /* NOTREACHED - relocate_code() does not return */
- }
2.5 内存参数的修改
在原来的代码中,是算出u-boot代码的大小,放在sdram中的。
而在我们修改的代码中,是直接拷贝u-boot的代码到SDRAM中固定的地址处: 0x33f80000,这样更加直观。
arch/arm/lib/board.c
在函数 void board_init_f(ulong bootflag) 中修改
void board_init_f(ulong bootflag)
- /*
- * reserve memory for U-Boot code, data & bss
- * round down to next 4 kB limit
- */
- #if 0
- addr -= gd->mon_len; /*gd->mon_len = __bss_end__ - _start 为整个u-boot 代码的长度*/
- addr &= ~(4096 - 1);
- #else
- addr = CONFIG_SYS_TEXT_BASE; /* addr = _TEXT_BASE 直接把地址固定在某个位置 */
- #endif
(1) 查看u-boot.bin 文件大小
book@book-desktop:/work/system/u-boot-2012.04.01$ ls -l u-boot.bin(2)所以程序本身最终的大小应该是包括 bss段
-rwxr-xr-x 1 book book 432796 2015-07-13 09:21 u-boot.bin
这里u-boot.bin 有432796 字节的大小,注意:这个大小不包括bss段的大小
这可以利用反汇编文件,进行查看:
start.S中有一个变量: _bss_end_ofs
.globl _bss_end_ofs
_bss_end_ofs:
.word __bss_end__ - _start // 这个就是程序本身的大小,包括代码段,数据段,BSS段, 但是bss段不是没有拷贝过来吗???
当代码放置的地址为:0x33f80000,预置的u-boot最大空间大小为:0x34000000 - 0x33f80000 = 512K,如果bin文件大于这个数,则设置肯定是有问题的。
在反汇编里,搜索_bss_end_ofs,找到这个值的大小,这个数据包括代码段,数据段,BSS段,这个值 = 0x00094b40 = 594K,超过512Kb的大小,所以放置u-boot代码的起始地址:0x33f80000 是不够的。
可以设置为:0x33f00000,预留1Mbyte的空间来存放u-boot.bin的大小。
/* 预留1M 的空间*/
#define CONFIG_SYS_TEXT_BASE 0x33f00000
3.1 编译可能出现的错误
在include/configs/smdk2440.h中将CONFIG_S3C2410改为CONFIG_S3C2440
我们可以编译下,可以看到串口正常输出!编译出现错误:忘记是什么了,反正是说s3c2440_nand.c文件有什么没有定义解决方法:将#define CONFIG_CMD_NAND注释掉
再次编译,出现错误:fs/yaffs2/libyaffs2.o: In function `yaffs_StartUp':u-boot/u-boot-2012.04.01/fs/yaffs2/yaffscfg.c:210: undefined reference to `nand_info'解决方法:将#define CONFIG_YAFFS2注释掉
3.2 打印结果
将拔码开关打到nand flash启动,查看打印信息:
U-Boot 2012.04.01 (Jul 13 2015 - 20:33:34)
CPUID: 32440001
FCLK: 400 MHz
HCLK: 100 MHz
PCLK: 50 MHz
DRAM: 64 MiB
WARNING: Caches not enabled
Flash: *** failed ***
### ERROR ### Please RESET the board ###
(1)为什么重定位的时候BSS段不拷贝过去?如果在SDRAM中调用这些BSS段定义的变量或者地址,不是需要在SDRAM进行地址的转换吗?就跟新的u-boot的做法一样,需要地址转换啊。
比如,在bss段中有个变量的地址是0x100, 那如果在SDRAM中引用这个变量不是需要地址转换吗?这样不是必须得拷贝这个变量过去吗??
回答:没必要拷贝过去,因为在链接文件中有它确定的地址信息,在重定位代码中,只需要将对应的BSS的转换地址上的数据清零就可以了。
(2)既然bss段没有拷贝过去,为什么存储在SDRAM上u-boot代码总的大小是:__bss_end__ - _start 呢?
代码重定向拷贝代码不是只拷贝了除BSS段以外代码段和数据段的大小么? ldr r2, =_bss_start_ofs // _bss_start_ofs = __bss_start - _start,表示u-boot代码的大小。
回答:问题1已经知道,没有拷贝过去并不代表不需要BSS段,其实是已经有了BSS段的信息了,就没必要拷贝过去,在进入第二阶段启动代码之前,把BSS段全部清零就好了。
1. 总结移植新的U-BOOT的编译过程,如何启动,链接地址在哪里?
新的uboot的链接地址设置在0x0,只支持nor启动,还有在重定位到SDRAM中后,相应的在链接地址为0下编译的地址信息要重新转换到SDRAM中的地址。而且新的uboot拷贝的地址是根据uboot编译后的bin文件大小自动固定的。
2. 修改支持NAND启动,需要:
2.1 NAND控制器需要初始化
2.2 因为从NAND启动的时候,是CPU自动将NAND前4K的内存拷贝到内部的SRAM中,然后从SRAM启动,也就是说启动的代码必须在4K就得完成这就必须缩小启动代码的量,所以可以去掉新的uboot启动方法,改成老的启动方法,将链接地址定死在SDRAM中的某个地址。这样就不会在重定位之后还需要转换地址。
2.3 重新规划内存的布局,比如u-boot编译处的大小最后是多少,存在那个位置。SP存在哪里等。