一、 支持NAND FLASH啟動 新版u-boot在鏈接時加了“-pie”選項 -pie Produce a position independent executable on targets which support it. For predictable results, you must also specify the same set of options that were used to generate code (-fpie, -fPIE, or model suboptions) when you specify this option. 產(chǎn)生的代碼中,沒有絕對地址,全部使用相對地址,故而代碼可以被加載器加載到內(nèi)存的任意 位置,都可以正確的執(zhí)行。 最終u-boot.bin中多了這些段 .rel.dyn : { __rel_dyn_start = .; *(.rel*) __rel_dyn_end = .; } .dynsym : { __dynsym_start = .; *(.dynsym) } 從NOR FLASH把代碼復(fù)制到SDRAM,程序的鏈接地址是0,訪問全局變量、靜態(tài)變量、調(diào)用函數(shù)時是使用基于0地址編譯得到的地址,現(xiàn)在把程序復(fù)制到了SDRAM(0x3000000),需要修改代碼,把原來的地址改為新地址。這樣太復(fù)雜了,還是使用老版本的方法。 去掉“-pie”選項,在u-boot源碼搜索“-pie” pengdl@debian:~/work/tq2440/u-boot-2014.04$ grep "\-pie" . -nR ...... ./arch/arm/config.mk:83:LDFLAGS_u-boot += -pie ...... 去除arch/arm/config.mk:83:LDFLAGS_u-boot += -pie中的“-pie” 82 # needed for relocation 83 #LDFLAGS_u-boot += -pie 修改配置文件include/configs/tq2440.h,給u-boot分配512KB #define CONFIG_SYS_TEXT_BASE 0x33f80000 增加文件board/tq2440/nand_read_ll.c并修改相應(yīng)的Makefile obj-y := tq2440.o obj-y += nand_read_ll.o obj-y += lowlevel_init.o nand_read_ll.c文件內(nèi)容如下: /* NAND FLASH控制器 */ #define NFCONF (*((volatile unsigned long *)0x4E000000)) #define NFCONT (*((volatile unsigned long *)0x4E000004)) #define NFCMMD (*((volatile unsigned char *)0x4E00000  ) #define NFADDR (*((volatile unsigned char *)0x4E00000C)) #define NFDATA (*((volatile unsigned char *)0x4E000010)) #define NFSTAT (*((volatile unsigned char *)0x4E000020)) static 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 == 0x1234567  { /* 寫成功, 是nand啟動 */ *p = val; return 0; } else { /* NOR不能像內(nèi)存一樣寫 */ return 1; } } void nand_init_ll(void) { #define TACLS 0 #define TWRPH0 1 #define TWRPH1 0 /* 設(shè)置時序 */ NFCONF = (TACLS<<12)|(TWRPH0<<  |(TWRPH1<<4); /* 使能NAND Flash控制器, 初始化ECC, 禁止片選 */ NFCONT = (1<<4)|(1<<1)|(1<<0); } void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len) { int i = 0; /* 如果是NOR啟動 */ if (isBootFromNorFlash()) { while (i < len) { dest = src; i++; } } else { nand_init_ll(); nand_read_ll((unsigned int)src, dest, len); } } void clear_bss(void) { extern int __bss_start, __bss_end; int *p = &__bss_start; for (; p < &__bss_end; p++) *p = 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 >>  & 0xff; for (i = 0; i < 10; i++); NFADDR = page & 0xff; for (i = 0; i < 10; i++); NFADDR = (page >>  & 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; } static 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. 發(fā)出讀命令00h */ nand_cmd(0x00); /* 3. 發(fā)出地址(分5步發(fā)出) */ nand_addr(addr); /* 4. 發(fā)出讀命令30h */ nand_cmd(0x30); /* 5. 判斷狀態(tài) */ nand_wait_ready(); /* 6. 讀數(shù)據(jù) */ for (; (col < 204  && (i < len); col++) { buf = nand_data(); i++; addr++; } col = 0; } /* 7. 取消選中 */ nand_deselect(); } 通過閱讀u-boot源碼arch/arm/cpu/arm920t/start.S #ifndef CONFIG_SKIP_LOWLEVEL_INIT bl cpu_init_crit #endif bl _main 跳轉(zhuǎn)到arch/arm/lib/crt0.S:_main 修改arch/arm/lib/crt0.S為: ENTRY(_main) /* * Set up initial C runtime environment and call board_init_f(0). */ #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK) ldr sp, =(CONFIG_SPL_STACK) #else ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) #endif bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ sub sp, sp, #GD_SIZE /* allocate one GD above SP */ bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ mov r9, sp /* GD is above SP */ #if 1 __TEXT_BASE: .word CONFIG_SYS_TEXT_BASE mov r0, #0 ldr r1, __TEXT_BASE ldr r2, __TEXT_BASE ldr r3, =__bss_end sub r2, r3, r2 bl copy_code_to_sdram bl clear_bss ldr pc, =call_board_init_f call_board_init_f: mov r0, #0 bl board_init_f ldr sp, [r9, #GD_START_ADDR_SP] /* sp = gd->start_addr_sp */ bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ ldr r9, [r9, #GD_BD] /* r9 = gd->bd */ sub r9, r9, #GD_SIZE /* new GD is below bd */ ldr r1, __TEXT_BASE bl board_init_r #else mov r0, #0 bl board_init_f #if ! defined(CONFIG_SPL_BUILD) /* * Set up intermediate environment (new sp and gd) and call * relocate_code(addr_moni). Trick here is that we'll return * 'here' but relocated. */ ldr sp, [r9, #GD_START_ADDR_SP] /* sp = gd->start_addr_sp */ bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ ldr r9, [r9, #GD_BD] /* r9 = gd->bd */ sub r9, r9, #GD_SIZE /* new GD is below bd */ adr lr, here ldr r0, [r9, #GD_RELOC_OFF] /* r0 = gd->reloc_off */ add lr, lr, r0 ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */ b relocate_code here: /* Set up final (full) environment */ bl c_runtime_cpu_setup /* we still call old routine here */ ldr r0, =__bss_start /* this is auto-relocated! */ ldr r1, =__bss_end /* this is auto-relocated! */ mov r2, #0x00000000 /* prepare zero to clear BSS */ clbss_l:cmp r0, r1 /* while not at end of BSS */ strlo r2, [r0] /* clear 32-bit BSS word */ addlo r0, r0, #4 /* move to next */ blo clbss_l bl coloured_LED_init bl red_led_on /* call board_init_r(gd_t *id, ulong dest_addr) */ mov r0, r9 /* gd_t */ ldr r1, [r9, #GD_RELOCADDR] /* dest_addr */ /* call board_init_r */ ldr pc, =board_init_r /* this is auto-relocated! */ /* we should not return here. */ #endif #endif ENDPROC(_main) 修改arch/arm/lib/board.c中的函數(shù)board_init_f為:
圖片1.png (8.53 KB, 下載次數(shù): 90)
下載附件
2014-06-30 09:20 上傳
然后再board_init_f的結(jié)尾添加:
圖片2.png (7.85 KB, 下載次數(shù): 96)
下載附件
2014-06-30 09:20 上傳
即將board_init_r要用的第一個參數(shù)返回,也就是重定向后gd結(jié)構(gòu)體的起始地址。 修改include/common.h:
圖片3.png (6.51 KB, 下載次數(shù): 81)
下載附件
2014-06-30 09:20 上傳
修改arch/arm/lib/board.c中的函數(shù)board_init_f //addr -= gd->mon_len; //addr &= ~(4096 - 1); addr = CONFIG_SYS_TEXT_BASE; 然后編譯,編譯完成后,執(zhí)行make u-boot.dis,生成u-boot的反匯編文件,看一下start.o、nand_read_ll.o、lowlevel_init.o是否被連接到了u-boot的前面4KB范圍內(nèi):
圖片4.png (8.48 KB, 下載次數(shù): 82)
下載附件
2014-06-30 09:20 上傳
從上面的圖中可以看到,copy_code_to_sdram和clear_bss的地址已經(jīng)超過4KB了,前面我們把CONFIG_SYS_TEXT_BASE設(shè)置為了0x33f80000,但是copy_code_to_sdram的地址已經(jīng)到了0x33f81464,0x33f81464-0x33f80000=0x1464>0x1000,顯然超多了4KB(十六進(jìn)制就是0x1000),所以需要修改鏈接腳本和Makefile,將nand_read_ll和lowlevel_init.S 鏈接到uboot的前4KB內(nèi),具體做法如下: 修改鏈接腳本arch/arm/cpu/u-boot.lds把start.o、nand_read_ll.o、lowlevel_init.o編譯到前面4KB 修改board/tq2440/Makefile: obj-y := tq2440.o extra-y := nand_read_ll.o extra-y += lowlevel_init.o 修改arch/arm/cpu/u-boot.lds: . = ALIGN(4); .text : { *(.__image_copy_start) CPUDIR/start.o (.text*) board/tq2440/lowlevel_init.o (.text*) board/tq2440/nand_read_ll.o (.text*) *(.text*) } 重新編譯: ...... HOSTLD tools/dumpimage HOSTLD tools/mkimage CC arch/arm/lib/board.o LD arch/arm/lib/built-in.o AS board/tq2440/lowlevel_init.o CC common/main.o CC common/cmd_version.o LD common/built-in.o CC lib/display_options.o LD lib/built-in.o LDS u-boot.lds LD u-boot u-boot contains unexpected relocations: make: *** [checkarmreloc] Error 1 搜索 “u-boot contains unexpected relocations” pengdl@debian:~/work/tq2440/u-boot-2014.04$ grep "u-boot contains unexpected relocations" * -nR 沒有搜索到任何內(nèi)容,那么我們搜索checkarmreloc: pengdl@debian:~/work/tq2440/u-boot-2014.04$ grep "checkarmreloc" * -nR arch/arm/config.mk:105:ALL-y += checkarmreloc Makefile:1123:checkarmreloc: u-boot 在頂層Makefile中有如下語句: 1121 # ARM relocations should all be R_ARM_RELATIVE (32-bit) or 1122 # R_AARCH64_RELATIVE (64-bit). 1123 checkarmreloc: u-boot 1124 @RELOC="`$(CROSS_COMPILE)readelf -r -W $< | cut -d ' ' -f 4 | \ 1125 grep R_A | sort -u`"; \ 1126 if test "$$RELOC" != "R_ARM_RELATIVE" -a \ 1127 "$$RELOC" != "R_AARCH64_RELATIVE"; then \ 1128 echo "$< contains unexpected relocations: $$RELOC"; \ 1129 false; \ 1130 fi 那么我們就別編譯checkarmreloc了,所以我們修改arch/arm/config.mk的第105行: 105 #ALL-y += checkarmreloc 重新編譯,從NOR FLASH啟動開發(fā)板,將u-boot.bin燒到NAND FLASH TQ2440 # nand erase 0 40000;tftp 32000000 u-boot.bin;nand write 32000000 0 40000 NAND erase: device 0 offset 0x0, size 0x40000 Erasing at 0x20000 -- 100% complete. OK dm9000 i/o: 0x20000000, id: 0x90000a46 DM9000: running in 16 bit mode MAC: 00:0c:29:2a:5c:a5 operating at 100M full duplex mode Using dm9000 device TFTP from server 192.168.1.8; our IP address is 192.168.1.6 Filename 'u-boot.bin'. Load address: 0x32000000 Loading: T ############### 39.1 KiB/s done Bytes transferred = 209400 (331f8 hex) NAND write: device 0 offset 0x0, size 0x40000 262144 bytes written: OK TQ2440 # 從NAND FLASh啟動開發(fā)板 TQ2440 # reset resetting ... U-Boot 2014.04 (Jun 29 2014 - 07:58:40) 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 ### 卡在這里不動了,由于從NAND啟動,CPU檢測不到NOR FLASH,具體代碼如下arch/arm/lib/board.c flash_size = flash_init(); if (flash_size > 0) { # ifdef CONFIG_SYS_FLASH_CHECKSUM print_size(flash_size, ""  ; /* * Compute and print flash CRC if flashchecksum is set to 'y' * * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX */ if (getenv_yesno("flashchecksum"  == 1) { printf(" CRC: %08X", crc32(0, (const unsigned char *) CONFIG_SYS_FLASH_BASE, flash_size)); } putc('\n'); # else /* !CONFIG_SYS_FLASH_CHECKSUM */ print_size(flash_size, "\n"  ; # endif /* CONFIG_SYS_FLASH_CHECKSUM */ } else { puts(failed); hang(); } 其中failed定義為 #if !defined(CONFIG_SYS_NO_FLASH) static char *failed = "*** failed ***\n"; #endif 函數(shù)hang()定義為 void hang(void) { puts("### ERROR ### Please RESET the board ###\n"  ; for (;  ; } 我們直接注釋掉上面的hang(); # endif /* CONFIG_SYS_FLASH_CHECKSUM */ } else { puts(failed); //hang(); } #endif 重新編譯,從NOR FLASH啟動開發(fā)板,將u-boot.bin燒到NAND FLASH,從NAND啟動 CPUID: 32440001 FCLK: 400 MHz HCLK: 100 MHz PCLK: 50 MHz DRAM: 64 MiB WARNING: Caches not enabled Flash: *** failed *** NAND: 256 MiB In: serial Out: serial Err: serial Net: dm9000 Hit any key to stop autoboot: 0 TQ2440 #
|