Chinaunix首页 | 论坛 | 博客
  • 博客访问: 831201
  • 博文数量: 281
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2770
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-02 19:45
个人简介

邮箱:zhuimengcanyang@163.com 痴爱嵌入式技术的蜗牛

文章分类
文章存档

2020年(1)

2018年(1)

2017年(56)

2016年(72)

2015年(151)

分类: 嵌入式

2015-07-13 15:35:55

注意:本文有些是我自己的理解,可能有误,请选择性阅读,可以共同探讨。谢谢。

1. 总结新uboot

分析原版的uboot可以知道:
重定位的做法是:
把程序从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. 修改uboot之支持nand启动

    原来的代码在链接时加了"-pie"选项,使得u-boot.bin里多了"*(.rel*)","*(.dynsym)"
    使得程序非常大,不利于从NAND启动(重定位之前的启动代码应该少于4K,nand启动时,前4k的代码拷贝到2440内部的RAM中运行)。

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

  1. /*
  2.  * Copyright (c) 2004-2008 Texas Instruments
  3.  *
  4.  * (C) Copyright 2002
  5.  * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
  6.  *
  7.  * See file CREDITS for list of people who contributed to this
  8.  * project.
  9.  *
  10.  * This program is free software; you can redistribute it and/or
  11.  * modify it under the terms of the GNU General Public License as
  12.  * published by the Free Software Foundation; either version 2 of
  13.  * the License, or (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  23.  * MA 02111-1307 USA
  24.  */

  25. OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
  26. OUTPUT_ARCH(arm)
  27. ENTRY(_start)
  28. SECTIONS
  29. {
  30.         . = 0x00000000;

  31.         . = ALIGN(4);
  32.         .text :
  33.         {
  34.                 __image_copy_start = .;

  35.                 CPUDIR/start.o (.text)   // 也就是文件:arch/arm/cpu/arm920t/start.S

  36.                // 添加下面的这句话。 init.c lowlevel_init.S smdk2410.c -> 这几个文件编译链接成一个库文件
  37.                // 为什么要添加这句话?思考一下。(重定位之前的程序必须放在前4K代码处,并且是位置无关码)
  38.                board/samsung/smdk2440/libsmdk2440.o (.text
  39.                 *(.text)
  40.         }

  41.         . = ALIGN(4);
  42.         .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }

  43.         . = ALIGN(4);
  44.         .data : {
  45.                 *(.data)
  46.         }

  47.         . = ALIGN(4);

  48.         . = .;
  49.         __u_boot_cmd_start = .;
  50.         .u_boot_cmd : { *(.u_boot_cmd) }
  51.         __u_boot_cmd_end = .;

  52.         . = ALIGN(4);

  53.         __image_copy_end = .;

  54.         .rel.dyn : {
  55.                 __rel_dyn_start = .;
  56.                 *(.rel*)
  57.                 __rel_dyn_end = .;
  58.         }

  59.         .dynsym : {
  60.                 __dynsym_start = .;
  61.                 *(.dynsym)
  62.         }

  63.         _end = .;

  64.         /*
  65.          * Deprecated: this MMU section is used by pxa at present but
  66.          * should not be used by new boards/CPUs.
  67.          */
  68.         . = ALIGN(4096);
  69.         .mmutable : {
  70.                 *(.mmutable)
  71.         }

  72.         .bss __rel_dyn_start (OVERLAY) : {
  73.                 __bss_start = .;
  74.                 *(.bss)
  75.                  . = ALIGN(4);
  76.                 __bss_end__ = .;
  77.         }

  78.         /DISCARD/ : { *(.dynstr*) }
  79.         /DISCARD/ : { *(.dynamic*) }
  80.         /DISCARD/ : { *(.plt*) }
  81.         /DISCARD/ : { *(.interp*) }
  82.         /DISCARD/ : { *(.gnu*) }
  83. }

2.3 参考"毕业班第1课"的start.S, init.c来修改代码

    把init.c放入board/samsung/smdk2440目录,修改init.c以及Makefile
修改:init.c
  1. /* NAND FLASH控制器 */
  2. #define NFCONF (*((volatile unsigned long *)0x4E000000))
  3. #define NFCONT (*((volatile unsigned long *)0x4E000004))
  4. #define NFCMMD (*((volatile unsigned char *)0x4E000008))
  5. #define NFADDR (*((volatile unsigned char *)0x4E00000C))
  6. #define NFDATA (*((volatile unsigned char *)0x4E000010))
  7. #define NFSTAT (*((volatile unsigned char *)0x4E000020))


  8. void nand_read_ll(unsigned int addr, unsigned char *buf, unsigned int len);


  9. static int isBootFromNorFlash(void)
  10. {
  11.     volatile int *p = (volatile int *)0;
  12.     int val;

  13.     val = *p;
  14.     *p = 0x12345678;
  15.     if (*p == 0x12345678)
  16.     {
  17.         /* 写成功, 是nand启动 */
  18.         *p = val;
  19.         return 0;
  20.     }
  21.     else
  22.     {
  23.         /* NOR不能像内存一样写 */
  24.         return 1;
  25.     }
  26. }

  27. void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len)
  28. {    
  29.     int i = 0;
  30.     
  31.     /* 如果是NOR启动 */
  32.     if (isBootFromNorFlash())
  33.     {
  34.         while (i < len)
  35.         {
  36.             dest[i] = src[i];
  37.             i++;
  38.         }
  39.     }
  40.     else
  41.     {
  42.         //nand_init();
  43.         nand_read_ll((unsigned int)src, dest, len);
  44.     }
  45. }

  46. void clear_bss(void)    // 这个函数需要注意
  47. {

  48. /*
  49. .bss __rel_dyn_start (OVERLAY) : {
  50.         __bss_start = .;
  51.         *(.bss)
  52.          . = ALIGN(4);
  53.         __bss_end__ = .;
  54. }

  55. */
  56.     extern int __bss_start, __bss_end__;  // 从u-boot.lds中找到地址,将原来的"__bss_end"修改为"__bss_end__"
  57.     int *p = &__bss_start;
  58.     
  59.     for (; p < &__bss_end__; p++)
  60.         *p = 0;
  61. }

  62. void nand_init_ll(void)
  63. {
  64. #define TACLS 0
  65. #define TWRPH0 1
  66. #define TWRPH1 0
  67.     /* 设置时序 */
  68.     NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
  69.     /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
  70.     NFCONT = (1<<4)|(1<<1)|(1<<0);    
  71. }

  72. static void nand_select(void)
  73. {
  74.     NFCONT &= ~(1<<1);    
  75. }

  76. static void nand_deselect(void)
  77. {
  78.     NFCONT |= (1<<1);    
  79. }

  80. static void nand_cmd(unsigned char cmd)
  81. {
  82.     volatile int i;
  83.     NFCMMD = cmd;
  84.     for (i = 0; i < 10; i++);
  85. }

  86. static void nand_addr(unsigned int addr)
  87. {
  88.     unsigned int col = addr % 2048;
  89.     unsigned int page = addr / 2048;
  90.     volatile int i;

  91.     NFADDR = col & 0xff;
  92.     for (i = 0; i < 10; i++);
  93.     NFADDR = (col >> 8) & 0xff;
  94.     for (i = 0; i < 10; i++);
  95.     
  96.     NFADDR = page & 0xff;
  97.     for (i = 0; i < 10; i++);
  98.     NFADDR = (page >> 8) & 0xff;
  99.     for (i = 0; i < 10; i++);
  100.     NFADDR = (page >> 16) & 0xff;
  101.     for (i = 0; i < 10; i++);    
  102. }

  103. static void nand_wait_ready(void)
  104. {
  105.     while (!(NFSTAT & 1));
  106. }

  107. static unsigned char nand_data(void)
  108. {
  109.     return NFDATA;
  110. }

  111. void nand_read_ll(unsigned int addr, unsigned char *buf, unsigned int len)
  112. {
  113.     int col = addr % 2048;
  114.     int i = 0;
  115.         
  116.     /* 1. 选中 */
  117.     nand_select();

  118.     while (i < len)
  119.     {
  120.         /* 2. 发出读命令00h */
  121.         nand_cmd(0x00);

  122.         /* 3. 发出地址(分5步发出) */
  123.         nand_addr(addr);

  124.         /* 4. 发出读命令30h */
  125.         nand_cmd(0x30);

  126.         /* 5. 判断状态 */
  127.         nand_wait_ready();

  128.         /* 6. 读数据 */
  129.         for (; (col < 2048) && (i < len); col++)
  130.         {
  131.             buf[i] = nand_data();
  132.             i++;
  133.             addr++;
  134.         }
  135.         
  136.         col = 0;
  137.     }

  138.     /* 7. 取消选中 */        
  139.     nand_deselect();
  140. }
    makefile 修改:

board/samsung/smdk2440/Makefile

  1. include $(TOPDIR)/config.mk

  2. LIB = $(obj)lib$(BOARD).o

  3. COBJS := smdk2410.o init.o
  4. SOBJS := lowlevel_init.o

  5. SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
  6. OBJS := $(addprefix $(obj),$(COBJS))
  7. SOBJS := $(addprefix $(obj),$(SOBJS))

  8. $(LIB): $(obj).depend $(OBJS) $(SOBJS)
  9.         $(call cmd_link_o_target, $(OBJS) $(SOBJS))

  10. #########################################################################

  11. # defines $(obj).depend target
  12. include $(SRCTREE)/rules.mk

  13. sinclude $(obj).depend

  14. #########################################################################
      (2)修改CONFIG_SYS_TEXT_BASE为0x33f80000
              在目录文件: \include\configs\Smdk2440.h
  1. #if 0

  2.     #define CONFIG_SYS_TEXT_BASE    0x0

  3. #else

  4.     // 0x34000000 - 0x33f8000000 = 512K, 这里假定u-boot的大小不超过512K
  5.     #define CONFIG_SYS_TEXT_BASE    0x33f80000

  6. #endif

      (3)修改start.S
  1. #if 0

  2. /* Set stackpointer in internal RAM to call board_init_f */
  3. call_board_init_f:
  4.     ldr    sp, =(CONFIG_SYS_INIT_SP_ADDR)
  5.     bic    sp, sp, #7 /* 8-byte alignment for ABI compliance */
  6.     ldr    r0,=0x00000000
  7.     bl    board_init_f

  8. #else

  9.     // 1. 调用C函数之前,先设置好堆栈
  10.     ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
  11.     bic sp, sp, #7 /* 8-byte alignment for ABI compliance */


  12.     // 2. 初始化nand flash,因为nand读写需要专门的时序,所以需要初始化
  13.     bl nand_init_ll

  14.     // 3. 拷贝代码,先设置参数
  15.     mov r0, #0                               // r0 =0, 表示源地址
  16.     
  17. /*不要用这条伪指令,如果_start的值比较复杂,它会将它存在某个内存地址,但是存在哪里,根本没法知道,由编译器决定,有可能把它存到到4k 之外了。*/
  18.     // ldr r1, =_start                     

  19.     /* 用这种方法,可以定死存放的地址,该指令的意思是取标号处地址的内容, _TEXT_BASE = 0x33f80000*/
  20.     ldr r1, _TEXT_BASE                      // r1 = _TEXT_BASE,表示目的地址


  21.      // 注意: 不是 ldr r2, =_bss_start_ofs
        ldr r2, _bss_start_ofs   // _bss_start_ofs = __bss_start - _start,表示u-boot代码的大小。   这里为什么bss段不拷贝过去呢??

  22.     bl copy_code_to_sdram
  23.     bl clear_bss
  24.         
  25.    ldr pc, =call_board_init_f             // 这句话的意思是:从RAM当中直接跳转到SDRAM中执行

  26. /* Set stackpointer in internal RAM to call board_init_f */
  27. call_board_init_f:
  28.     ldr    r0,=0x00000000
  29.     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
#endif

2.4 修改board_init_f, 把relocate_code去掉

\arch\arm\lib\Board.c

  1. unsigned int board_init_f(ulong bootflag)
  2. {
  3.     bd_t *bd;
  4.     init_fnc_t **init_fnc_ptr;
  5.     gd_t *id;
  6.     ulong addr, addr_sp;
  7. #ifdef CONFIG_PRAM
  8.     ulong reg;
  9. #endif

  10.     bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_F, "board_init_f");

  11.     /* Pointer is writable since we allocated a register for it */
  12.     gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);
  13.     /* compiler optimization barrier needed for GCC >= 3.4 */
  14.     __asm__ __volatile__("": : :"memory");

  15.     memset((void *)gd, 0, sizeof(gd_t));

  16.     gd->mon_len = _bss_end_ofs;
  17. #ifdef CONFIG_OF_EMBED
  18.     /* Get a pointer to the FDT */
  19.     gd->fdt_blob = _binary_dt_dtb_start;
  20. #elif defined CONFIG_OF_SEPARATE
  21.     /* FDT is at end of image */
  22.     gd->fdt_blob = (void *)(_end_ofs + _TEXT_BASE);
  23. #endif
  24.     /* Allow the early environment to override the fdt address */
  25.     gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16,
  26.                         (uintptr_t)gd->fdt_blob);

  27.     for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
  28.         if ((*init_fnc_ptr)() != 0) {
  29.             hang ();
  30.         }
  31.     }

  32. #ifdef CONFIG_OF_CONTROL
  33.     /* For now, put this check after the console is ready */
  34.     if (fdtdec_prepare_fdt()) {
  35.         panic("** CONFIG_OF_CONTROL defined but no FDT - please see "
  36.             "doc/README.fdt-control");
  37.     }
  38. #endif

  39.     debug("monitor len: %08lX\n", gd->mon_len);
  40.     /*
  41.      * Ram is setup, size stored in gd !!
  42.      */
  43.     debug("ramsize: %08lX\n", gd->ram_size);
  44. #if defined(CONFIG_SYS_MEM_TOP_HIDE)
  45.     /*
  46.      * Subtract specified amount of memory to hide so that it won't
  47.      * get "touched" at all by U-Boot. By fixing up gd->ram_size
  48.      * the Linux kernel should now get passed the now "corrected"
  49.      * memory size and won't touch it either. This should work
  50.      * for arch/ppc and arch/powerpc. Only Linux board ports in
  51.      * arch/powerpc with bootwrapper support, that recalculate the
  52.      * memory size from the SDRAM controller setup will have to
  53.      * get fixed.
  54.      */
  55.     gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE;
  56. #endif

  57.     addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size; /* gd->ram_size = PHYS_SDRAM_1_SIZE = 64Mb*/
  58.                                                  /* 将addr指向SDRAM的最顶端*/
  59. #ifdef CONFIG_LOGBUFFER
  60. #ifndef CONFIG_ALT_LB_ADDR
  61.     /* reserve kernel log buffer */
  62.     addr -= (LOGBUFF_RESERVE);
  63.     debug("Reserving %dk for kernel logbuffer at %08lx\n", LOGBUFF_LEN,
  64.         addr);
  65. #endif
  66. #endif

  67. #ifdef CONFIG_PRAM
  68.     /*
  69.      * reserve protected RAM
  70.      */
  71.     reg = getenv_ulong("pram", 10, CONFIG_PRAM);
  72.     addr -= (reg << 10);        /* size is in kB */
  73.     debug("Reserving %ldk for protected RAM at %08lx\n", reg, addr);
  74. #endif /* CONFIG_PRAM */

  75. #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
  76.     /* reserve TLB table */
  77.     addr -= (4096 * 4);

  78.     /* round down to next 64 kB limit */
  79.     addr &= ~(0x10000 - 1);

  80.     gd->tlb_addr = addr;
  81.     debug("TLB table at: %08lx\n", addr);
  82. #endif

  83.     /* round down to next 4 kB limit */
  84.     addr &= ~(4096 - 1);
  85.     debug("Top of RAM usable for U-Boot at: %08lx\n", addr);

  86. #ifdef CONFIG_LCD
  87. #ifdef CONFIG_FB_ADDR
  88.     gd->fb_base = CONFIG_FB_ADDR;
  89. #else
  90.     /* reserve memory for LCD display (always full pages) */
  91.     addr = lcd_setmem(addr);
  92.     gd->fb_base = addr;
  93. #endif /* CONFIG_FB_ADDR */
  94. #endif /* CONFIG_LCD */

  95.     /*
  96.      * reserve memory for U-Boot code, data & bss
  97.      * round down to next 4 kB limit
  98.      */
  99.     addr -= gd->mon_len; /*gd->mon_len = __bss_end__ - _start 为整个u-boot 代码的长度*/
  100.     addr &= ~(4096 - 1);

  101.     debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr);

  102. #ifndef CONFIG_SPL_BUILD
  103.     /*
  104.      * reserve memory for malloc() arena
  105.      */
  106.     addr_sp = addr - TOTAL_MALLOC_LEN;
  107.     debug("Reserving %dk for malloc() at: %08lx\n",
  108.             TOTAL_MALLOC_LEN >> 10, addr_sp);
  109.     /*
  110.      * (permanently) allocate a Board Info struct
  111.      * and a permanent copy of the "global" data
  112.      */
  113.     addr_sp -= sizeof (bd_t);
  114.     bd = (bd_t *) addr_sp;
  115.     gd->bd = bd;
  116.     debug("Reserving %zu Bytes for Board Info at: %08lx\n",
  117.             sizeof (bd_t), addr_sp);

  118. #ifdef CONFIG_MACH_TYPE
  119.     gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */
  120. #endif

  121.     addr_sp -= sizeof (gd_t);
  122.     id = (gd_t *) addr_sp;
  123.     debug("Reserving %zu Bytes for Global Data at: %08lx\n",
  124.             sizeof (gd_t), addr_sp);

  125.     /* setup stackpointer for exeptions */
  126.     gd->irq_sp = addr_sp;
  127. #ifdef CONFIG_USE_IRQ
  128.     addr_sp -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);
  129.     debug("Reserving %zu Bytes for IRQ stack at: %08lx\n",
  130.         CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ, addr_sp);
  131. #endif
  132.     /* leave 3 words for abort-stack */
  133.     addr_sp -= 12;

  134.     /* 8-byte alignment for ABI compliance */
  135.     addr_sp &= ~0x07;
  136. #else
  137.     addr_sp += 128;    /* leave 32 words for abort-stack */
  138.     gd->irq_sp = addr_sp;
  139. #endif

  140.     debug("New Stack Pointer is: %08lx\n", addr_sp);

  141. #ifdef CONFIG_POST
  142.     post_bootmode_init();
  143.     post_run(NULL, POST_ROM | post_bootmode_get(0));
  144. #endif

  145.     gd->bd->bi_baudrate = gd->baudrate;
  146.     /* Ram ist board specific, so move it to board code ... */
  147.     dram_init_banksize();
  148.     display_dram_config();    /* and display it */

  149.     gd->relocaddr = addr;
  150.     gd->start_addr_sp = addr_sp;
  151.     gd->reloc_off = addr - _TEXT_BASE;
  152.     debug("relocation Offset is: %08lx\n", gd->reloc_off);
  153.     memcpy(id, (void *)gd, sizeof(gd_t));

  154.     // relocate_code(addr_sp, id, addr);   // 去掉这句话,因为我们在之前加入了 重定位 代码


            return id;

  1.     /* NOTREACHED - relocate_code() does not return */
  2. }

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)

  1. /*
  2.      * reserve memory for U-Boot code, data & bss
  3.      * round down to next 4 kB limit
  4.      */
  5. #if 0
  6.     addr -= gd->mon_len; /*gd->mon_len = __bss_end__ - _start 为整个u-boot 代码的长度*/
  7.     addr &= ~(4096 - 1);
  8. #else
  9.     addr = CONFIG_SYS_TEXT_BASE; /* addr = _TEXT_BASE 直接把地址固定在某个位置 */
  10. #endif




2. 一切步骤做好,编译出新的 u-boot.bin 文件之后,要看看u-boot.bin文件的大小

(1) 查看u-boot.bin 文件大小
book@book-desktop:/work/system/u-boot-2012.04.01$ ls -l u-boot.bin
-rwxr-xr-x 1 book book 432796 2015-07-13 09:21 u-boot.bin

这里u-boot.bin 有432796 字节的大小,注意:这个大小不包括bss段的大小

(2)所以程序本身最终的大小应该是包括 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. 重新编译烧写,看打印结果

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 ###


4. 问题

(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存在哪里等。

      
阅读(1159) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~