編輯:關於Android編程
前邊4篇文章,成功將 u-boot2012 移植到了 2440 開發板上,但是它僅僅支持 norflash 啟動並不夠完善,下面我們設法讓它支持兩種啟動方式。
首先,我們得先分析一下目前的啟動流程:
鏈接地址為 0
第一階段:start.S中的匯編部分,包括時鐘、sdram 等初始化
第二階段:board_init_f 先是調用了大量C函數進行串口什麼的初始化,然後進行內存劃分
第三階段:根據第二階段的內存劃分 start.S 中進行代碼重定位,清BSS,修正位置有關碼,跳到sdram裡去執行board_init_r
那麼,如果我們想 nandflash 啟動,那麼我們必須在前4K代碼中就進行 nandflash 的初始化,用nandflash的讀函數將代碼進行重定位到sdram裡,現在有一個矛盾擺在我們面前。首先是,原來的重定位的地方在第三階段,而且第二階段調用了大量的C函數,重定位的時候早就在 4K 之外了。如果我們把重定位放在第一階段和第二階段之間,那麼那時內存還沒有進行劃分,我們不知道重定位到哪裡去。
解決辦法:采用 uboot1.1.6 那種老的方式,在第一階段和第二階段之間進行重定位,重定位到固定地址 0x33f00000 中去,第二階段進行內存劃分時,將u-boot的起始地址也固定為 0x33f0000 ,在鏈接時,指定鏈接地址為0x33f00000,這樣,我們也可以去掉 *.rel 段,實際上是去掉編譯時的 -pie 選項。
還有一個問題,我們nandflash啟動時,norflash對cpu是不可見的,因此我們根本無法對Norflash進行初始化,更無法將環境變量保存在Norflash上了。
解決辦法:判斷如果是nandflash啟動,不進行Norflash的初始化。無論那種方式啟動,均將環境變量保存在nandflash上。
1、去掉 -pie 選項
grep "\-pie" * -nRw
arch/arm/config.mk:75:LDFLAGS_u-boot += -pie
直接注釋掉即可。
2、指定鏈接地址
grep "Ttext" * -nRw
找到一個宏CONFIG_SYS_TEXT_BASE 搜索這個宏,發現是在 smdk2440.h 中定義,修改為
#defineCONFIG_SYS_TEXT_BASE 0x33f00000
3、在第二階段內存劃分時,固定u-boot的起始地址
在 arch/aem/lib/board.c 中的
addr -= gd->mon_len;
addr &= ~(4096 - 1); 這兩行後邊,新增一行
addr = 0x33f00000;//增加
4、實現判斷 nor 啟動還是 nand 啟動的 C 函數
nor啟動時,片內ram位於0x40000000處,可以直接讀寫,0-2M的空間可以直接讀,但是沒法直接寫入。
nand啟動時,片內ram位於0x0處,0-4k,可以直接讀寫。
我一開始嘗試在 0x40000000 處寫值,然後讀取回來看是否成功,發現 nand 啟動時訪問0x40000000會觸發異常直接死掉。那麼只好嘗試讀寫0地址了。
int isNandBoot(){
#define RAMSTART (*(volatile unsigned long *)0x00000000)
unsigned long temp = RAMSTART;
RAMSTART = 0xbadc0de;
if(RAMSTART == 0xbadc0de){
RAMSTART = temp;
return 1;
}else{
RAMSTART = temp;
return 0;
}
}
nand啟動返回1,Nor啟動返回0
5、將nandflash的初始化函數、讀函數和上邊的判斷函數統一放入 smdk2440.c 中,同時,我們需要改變鏈接順序,將 smdk2440.o 盡量靠前放,索性放在 start.o 的後邊好了。但是經過我的嘗試,smdk2440.c 和lowlevel_init.S 會被鏈接成libsmdk2440.o ,只把smdk2440.o放到前面的話,會造成函數的重定義,解決辦法就是把libsmdk2440.o 放到前邊。
更改鏈接腳本:/arc/arm/cpu/u-boot.lds
在CPUDIR/start.o (.text) 後邊添加一行
board/samsung/smdk2440/libsmdk2440.o (.text)
嘗試編譯一下,正常應該沒問題。
6、在第一階段和第二階段之間增加代碼重定位等相關操作
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
/******************此行之前的代碼保持不變,增加*************************/
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
/* 判斷是 nand 還是 nor 啟動 */
bl isNandBoot
mov r1,#0x01
cmp r0,r1
bne copy_nor /* 不相等nor 相等nand*/
copy_nand:
bl my_nand_init
ldr r0, =0x33f00000
mov r1, #0x00
ldr r2, =_bss_start_ofs
bl my_nand_read
bl clear_bss
copy_nor:
mov r0, #0x00
ldr r1, =0x33f00000 /* r1 <- scratch for copy_loop */
ldr r3, _bss_start_ofs
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
bl clear_bss
/*****************call_board_init_f 中去掉sp的設置***********************/
call_board_init_f:
ldr r0,=0x00000000
bl board_init_f
/*************** 將 clear_bss 提升至 relocate_code 的前面****************/
clear_bss:
#ifndef CONFIG_SPL_BUILD
ldr r0, _bss_start_ofs
ldr r1, _bss_end_ofs
ldr r4, =0x33f00000 /* 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
ldr pc, =call_board_init_f // 增加跳轉到sdram的指令
#endif
/*************** 去掉原有的代碼重定位操作****************/
.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 */
mov sp, r0 /* 設置棧 */
/* setup parameters for board_init_r */
mov r0, r5 /* gd_t */
mov r1, r6 /* dest_addr */
/* jump to it ... */
bl board_init_r
/*
***********************之後代碼保持不變**********************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/
7、在norflash初始化代碼前,增加判斷#if !defined(CONFIG_SYS_NO_FLASH) 作用域之內的代碼放入 if(!isNandBoot()) 條件語句。
8、將環境變量存儲到 nandflash
首先,我查看了一下 common 目錄下,env_flash.c 是被編譯進u-boot了,但是 env_nand.c 並沒有,看下makefile 它依賴於哪個宏。
COBJS-$(CONFIG_ENV_IS_IN_FLASH) += env_flash.o
COBJS-$(CONFIG_ENV_IS_IN_NAND) += env_nand.o
搜索一下,發現CONFIG_ENV_IS_IN_FLASH 在 smdk2440.h 中定義
去掉#define CONFIG_ENV_IS_IN_FLASH
增加#defineCONFIG_ENV_IS_IN_NAND
實際在編譯測試的過程中,只定義CONFIG_ENV_IS_IN_NAND 是不夠的,會打印出錯誤信息
Need to define CONFIG_ENV_OFFSET when using CONFIG_ENV_IS_IN_NAND
意思很明確,我們需要定義環境變量在 nandflash 中的偏移地址,如果對 u-boot 進行分區的話,環境變量應該是存在於 params 區域,為了和內核保持一致,我們干脆分區得了。
9、查看內核啟動打印信息
0x00000000-0x00040000 : "bootloader"
0x00040000-0x00060000 : "params"
0x00060000-0x00260000 : "kernel"
0x00260000-0x10000000 : "root"
這是內核的分區劃分,我們按照內核的分區,也給 u-boot 進行分區。
添加分區,smdk2440.h 中要有一下宏定義:
#define CONFIG_CMD_MTDPARTS
#define CONFIG_MTD_DEVICE
#define CONFIG_MTD_PARTITIONS
加入MTD分區信息:
#define MTDIDS_DEFAULT "nand0=2440_nand"
#define MTDPARTS_DEFAULT "mtdparts=2440_nand:256k@0(bootloader)," \
"128k(params)," \
"2M(kernel)," \
"-(root)"
這個內核比較小,因此內核分區只有2M,如果內核比較大的話,在修改就是了。
環境變量的位置確定了,我們需要在smdk2440.h中定義偏移地址
#define CONFIG_ENV_OFFSET0x40000
同時,在smdk2440.h 中定義的CONFIG_ENV_SIZE 默認為0x10000 修改為 0x20000
10、剪裁u-boot
我嘗試nand啟動時,發現啟動不了,是因為我們的u-boot有400多K,而我們的 bootloader 只有256k,要麼修改分區,要麼剪裁u-boot,是它小於256k,如何剪裁,就是修改smdk2440.h宏咯。
在 smdk2440.h 中去掉
#define CONFIG_CMD_FAT
#define CONFIG_CMD_EXT2
#define CONFIG_CMD_UBI
#define CONFIG_CMD_UBIFS
#define CONFIG_YAFFS2
#define CONFIG_RBTREE
#define CONFIG_USB_OHCI
#define CONFIG_USB_KEYBOARD
#define CONFIG_USB_STORAGE
#define CONFIG_DOS_PARTITION
#define CONFIG_BOOTP_BOOTFILESIZE
#define CONFIG_BOOTP_BOOTPATH
#define CONFIG_BOOTP_GATEWAY
#define CONFIG_BOOTP_HOSTNAME
#define CONFIG_CMD_USB
#define CONFIG_CMD_BSP
make clean
make
編譯完你會發現體積大大減小,不到200K
11、燒寫測試,不出意外,我們的 nor nand 都能啟動了
可以看到,我們的環境變量已經保存在 nandflash 中了,需要注意的是,我們需要使用 mtdparts default 命令將分區信息保存在環境變量中,才可以在命令中像使用變量一樣引用分區名字。如果是第一次劃分分區,或者擦出了 params 區,記得 mtdparts default 然後 save 一下。
12、修改機器ID
u-boot 在引導內核時,會向內核傳遞機器ID,機器ID不對,直接無法啟動或者導致內核使用了其他單板的初始化函數,那麼 u-boot2012 的機器ID 在哪裡設置的呢?
board\samsung\smdk2410\smdk2410.c ->board_init
gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
gd->bd->bi_boot_params = 0x30000100;
13、個性化修改
如果你想像上邊那幅圖一樣,控制台每一樣默認出現“MINI2440 #”該如何設置?
在 smdk2440.h 中,修改宏定義
#define CONFIG_SYS_PROMPT"MIMI2440 # "
14、制作補丁文件
將修改好的u-boot2012文件夾重命名為 u-boot2012.04.1_OK 然後再解壓一份源碼
制作補丁前先清理生成的文件:
make clean
rm u-boot u-boot.bin u-boot.map u-boot.srec System.map
find -name "*.depend*"|rm -rf
diff -urNu-boot2012.04.1u-boot2012.04.1_OK u-boot2012.04.1.patch
OK ,整個 u-boot2012 的移植工作至此告一段落~,移植耗時2天,整理博客用了一天半~~醉醉的。
Andoid的Button+Intent(適合初學者)
自己剛學Android的時候在這上面花了不少時間,資料沒少找。學習別人的“關鍵代碼”,自己寫起來不是缺這就是缺那的。希望後來的同學在這上面少浪費些時間。 其實很簡單,就是
Dex文件格式詳解
什麼是dex文件他是Android系統的可執行文件,包含應用程序的全部操作指令以及運行時數據。由於dalvik是一種針對嵌入式設備而特殊設計的java虛擬機,所以dex文
詳解Android圖表 MPAndroidChart折線圖
1.介紹MPAndroidChart GitHub地址 MPAndroidChart的強大之處就不在多說了,目前最新的版本是3.0.1,在新版本中很多方法都被
一起學android之如何設置TextView中不同字段的字體顏色
在這裡先看看效果圖: OK,有時候,在我們的項目中會要求TextView中文本有一部分的字體顏色不一樣,這時我們應該使用 SpannableStrin