全志A10 Bootload加载过程分析
生活随笔
收集整理的這篇文章主要介紹了
全志A10 Bootload加载过程分析
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
A10的啟動(dòng)過程大概可分為5步:BootRom,SPL,Uboot,Kernel,RootFileSystem。本文只關(guān)注鏡像的加載過程,分析RootRom->SPL->Uboot的啟動(dòng)流程。
系統(tǒng)上電后,ARM處理器在復(fù)位時(shí)從地址0x000000開始執(zhí)行指令,把板上ROM或Flash映射到這一地址。A10將啟動(dòng)設(shè)備選擇程序固化在CPU內(nèi)部的一個(gè)32KB ROM中,默認(rèn)的啟動(dòng)時(shí)序?yàn)镾D Card0,NAND FLASH,SD Card2,SPI NOR FLASH。另外通過外部的一個(gè)啟動(dòng)選擇引腳可以使其跳轉(zhuǎn)到USB啟動(dòng)模式。通常情況下,啟動(dòng)選擇引腳狀態(tài)連接50K內(nèi)部上拉電阻。在上電后,執(zhí)行存儲(chǔ)在ROM中的啟動(dòng)代碼,將自動(dòng)檢測(cè)啟動(dòng)選擇引腳狀態(tài)。只有當(dāng)該引腳狀態(tài)為低電平時(shí)選擇USB啟動(dòng)模式。
啟動(dòng)設(shè)備選擇程序的流程圖:
在選擇啟動(dòng)設(shè)備后將加載并執(zhí)行bootload程序,CPU通過拷貝或映射bootload程序到內(nèi)存,然后執(zhí)行bootload的第一條指令。通過閱讀官方的uboot燒寫方法,發(fā)現(xiàn)A10通過uboot引導(dǎo)系統(tǒng),但卻沒有加載整個(gè)uboot,而是在此之前先載入了uboot SPL。什么是SPL?通過查閱uboot的官網(wǎng)資料得知,SPL是一個(gè)迷你版的uboot,全拼為Second Program Loader。適用于SOC的內(nèi)部SROM<64K的情況,用它來加載完整的uboot程序到SDROM,并通過完整uboot加載內(nèi)核來啟動(dòng)系統(tǒng)。
SPL程序流程如下:
1.初始化ARM處理器
2.初始化串口控制臺(tái)
3.配置時(shí)鐘和最基礎(chǔ)的分頻
4.初始化SDRAM
5.配置引腳多路復(fù)用功能
6.啟動(dòng)設(shè)備初始化(即上面選擇的啟動(dòng)設(shè)備)
7.加載完整的uboot程序并轉(zhuǎn)交控制權(quán)
搞清楚了上面的概念,可以知道Cubieboard出廠已經(jīng)燒寫了NandFlash中的程序,即在啟動(dòng)選擇時(shí)使用的是NandFlash。現(xiàn)在根據(jù)全志A10上的步驟,我們嘗試用SDC1(即Cubieboard上卡槽中的TF卡)來啟動(dòng)系統(tǒng)。
下載并編譯uboot
#git clone https://github.com/linux-sunxi/u-boot-sunxi.git
#cd u-boot-sunxi
#export CROSS_COMPILE=arm-linux-gnueabihf-
#make cubieboard
為TF卡燒寫引導(dǎo)程序
#dd if=/dev/zero of=/dev/sdb bs=1M count=1 # 清空SD卡(包括分區(qū)表)
嘗試不建立分區(qū)表,直接燒寫引導(dǎo)程序,無法啟動(dòng)系統(tǒng)。
因此按需求給TF卡分區(qū),我只創(chuàng)建了唯一一個(gè)200M主分區(qū),此處不詳述分區(qū)過程,下面是我使用的TF卡的分區(qū)表信息。
$ sudo fdisk -l /dev/sdb Disk /dev/sdb: 1977 MB, 1977614336 bytes 52 heads, 30 sectors/track, 2475 cylinders, total 3862528 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x00000000 Device Boot Start End Blocks Id System /dev/sdb1 2048 411647 204800 83 Linux
通過A10相關(guān)資料,通過以下2條命令燒寫spl和uboot到指定位置,暫時(shí)不清楚如何確定這2個(gè)讀取位置。
#dd if=spl/sunxi-spl.bin of=/dev/sdb bs=1024 seek=8
#dd if=u-boot.bin of=/dev/sdb bs=1024 seek=32
燒寫完成后插入TF卡到CB的卡槽中,連接USB轉(zhuǎn)TTL串口線,打開串口終端,上電。
串口打印信息如下:
U-Boot SPL?2012.10-04277-g7aa9f04 (Mar10?2013?-?00:36:40)
DRAM:?1024MB
SUNXI SD/MMC:0
U-Boot?2012.10-04277-g7aa9f04 (Mar10?2013?-?00:36:40) Allwinner Technology
CPU:?SUNXI Family
Board:?Cubieboard
I2C:?ready
DRAM:?1?GiB
MMC:?SUNXI SD/MMC:0
***?Warning-?bad CRC, using default environment
In:?serial
Out:?serial
Err:?serial
Hit any key to stop autoboot:?0?
**?Unable to use mmc0:1for?fatload?**
Loading file?"uEnv.txt"?from mmc device?0:1
Failed to mount ext2 filesystem...
**?Bad ext2 partitionor?disk?-?mmc0:1**
ext2load?-?load binary file from a Ext2 filesystem
Usage:
ext2load?<interface><dev[:part]>?[addr] [filename] [bytes]
-?load binary file?'filename'?from?'dev'?on?'interface'
to address?'addr'?from ext2 filesystem
Loading file?"boot/uEnv.txt"?from mmc device?0:1
Failed to mount ext2 filesystem...
**?Bad ext2 partitionor?disk?-?mmc0:1**
ext2load?-?load binary file from a Ext2 filesystem
Usage:
ext2load?<interface><dev[:part]>?[addr] [filename] [bytes]
-?load binary file?'filename'?from?'dev'?on?'interface'
to address?'addr'?from ext2 filesystem
**?Unable to use mmc0:1for?fatload?**
Loading file?"boot.scr"?from mmc device?0:1
Failed to mount ext2 filesystem...
**?Bad ext2 partitionor?disk?-?mmc0:1**
ext2load?-?load binary file from a Ext2 filesystem
Usage:
ext2load?<interface><dev[:part]>?[addr] [filename] [bytes]
-?load binary file?'filename'?from?'dev'?on?'interface'
to address?'addr'?from ext2 filesystem
Loading file?"boot/boot.scr"?from mmc device?0:1
Failed to mount ext2 filesystem...
**?Bad ext2 partitionor?disk?-?mmc0:1**
ext2load?-?load binary file from a Ext2 filesystem
Usage:
ext2load?<interface><dev[:part]>?[addr] [filename] [bytes]
-?load binary file?'filename'?from?'dev'?on?'interface'
to address?'addr'?from ext2 filesystem
**?Unable to use mmc0:1for?fatload?**
sun4i# 通過串口信息可以看到SPL和Uboot已經(jīng)成功加載,uboot最后通過ext2load命令讀取uEnv.txt和boot.scr文件失敗后退回控制臺(tái)。 下面通過源碼分析SPL載入完整Uboot的過程。 /u-boot-sunxi/common/spl/spl.c - board_init_r void?board_init_r(gd_t?*dummy1, ulong dummy2)
{
u32 boot_device;
debug(">>spl:board_init_r()\n");
puts(">>spl:board_init_r()\n");
#ifdef?CONFIG_SYS_SPL_MALLOC_START
mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,
CONFIG_SYS_SPL_MALLOC_SIZE);
#endif
timer_init();
#ifdef?CONFIG_SPL_BOARD_INIT
spl_board_init();
#endif
boot_device?=?spl_boot_device();?//檢測(cè)啟動(dòng)設(shè)備,此處返回BOOT_DEVICE_MMC1
debug("boot device - %d\n", boot_device);
switch?(boot_device) {
#ifdef?CONFIG_SPL_RAM_DEVICE
case?BOOT_DEVICE_RAM:
spl_ram_load_image();
break;
#endif
#ifdef?CONFIG_SPL_MMC_SUPPORT
case?BOOT_DEVICE_MMC1:
case?BOOT_DEVICE_MMC2:
case?BOOT_DEVICE_MMC2_2:
spl_mmc_load_image();?//通過mmc讀取image
break;
#endif
#ifdef?CONFIG_SPL_NAND_SUPPORT
case?BOOT_DEVICE_NAND:
spl_nand_load_image();
break;
#endif
#ifdef?CONFIG_SPL_NOR_SUPPORT
case?BOOT_DEVICE_NOR:
spl_nor_load_image();
break;
#endif
#ifdef?CONFIG_SPL_YMODEM_SUPPORT
case?BOOT_DEVICE_UART:
spl_ymodem_load_image();
break;
#endif
#ifdef?CONFIG_SPL_SPI_SUPPORT
case?BOOT_DEVICE_SPI:
spl_spi_load_image();
break;
#endif
#ifdef?CONFIG_SPL_ETH_SUPPORT
case?BOOT_DEVICE_CPGMAC:
#ifdef?CONFIG_SPL_ETH_DEVICE
spl_net_load_image(CONFIG_SPL_ETH_DEVICE);
#else
spl_net_load_image(NULL);
#endif
break;
#endif
default:
debug("SPL: Un-supported Boot Device\n");
hang();
}
switch?(spl_image.os) {
case?IH_OS_U_BOOT:
debug("Jumping to U-Boot\n");
break;
#ifdef?CONFIG_SPL_OS_BOOT
case?IH_OS_LINUX:
debug("Jumping to Linux\n");
spl_board_prepare_for_linux();
jump_to_image_linux((void?*)CONFIG_SYS_SPL_ARGS_ADDR);
#endif
default:
debug("Unsupported OS image.. Jumping nevertheless..\n");
}
jump_to_image_no_args();
} u-boot-sunxi/arch/arm/cpu/armv7/sunxi/board.c - spl_boot_device u32 spl_boot_device(void) {
u32 cfg;
#ifdef?CONFIG_SPL_NOR_SUPPORT
/* TODO */
#endif
#ifdef?CONFIG_SPL_MMC_SUPPORT
cfg?=?sunxi_gpio_get_cfgpin(SUNXI_GPC(7));
if( cfg?==?SUNXI_GPC7_SDC2_CLK )
return?BOOT_DEVICE_MMC2;
#endif
#ifdef?CONFIG_SPL_NAND_SUPPORT
cfg?=?sunxi_gpio_get_cfgpin(SUNXI_GPC(2));
if( cfg?==?SUNXI_GPC2_NCLE )
return?BOOT_DEVICE_NAND;
#endif
#ifdef?CONFIG_SPL_MMC_SUPPORT
cfg?=?sunxi_gpio_get_cfgpin(SUNXI_GPF(2));
if( cfg?==?SUNXI_GPF2_SDC0_CLK )
return?BOOT_DEVICE_MMC1;
#endif
/* if we are here, something goes wrong. Fall back on MMC */
return?BOOT_DEVICE_MMC1;
} 啟動(dòng)設(shè)備是通過讀取連接相應(yīng)設(shè)備的GPIO狀態(tài)來判斷的,但在上述條件下執(zhí)行該段代碼時(shí)并沒有成功檢測(cè)到設(shè)備,直到最后返回BOOT_DEVICE_MMC1。 u-boot-sunxi/drivers/mmc/spl_mmc.c - spl_mmc_load_image void?spl_mmc_load_image(void)
{
struct?mmc?*mmc;
int?err;
u32 boot_mode;
mmc_initialize(gd->bd);
/* We register only one device. So, the dev id is always 0 */
mmc?=?find_mmc_device(0);
if?(!mmc) {
puts("spl: mmc device not found!!\n");
hang();
}?
err?=?mmc_init(mmc);
if?(err) {
printf("spl: mmc init failed: err - %d\n", err);
hang();
}?
boot_mode?=?spl_boot_mode();?// sunxi的代碼在此處直接返回了MMCSD_MODE_RAW
if?(boot_mode?==?MMCSD_MODE_RAW) {
debug("boot mode - RAW\n");
mmc_load_image_raw(mmc);
#ifdef?CONFIG_SPL_FAT_SUPPORT
}?else?if?(boot_mode?==?MMCSD_MODE_FAT) {
debug("boot mode - FAT\n");
mmc_load_image_fat(mmc);
#endif
}?else?{
puts("spl: wrong MMC boot mode\n");
hang();
}?
} u-boot-sunxi/drivers/mmc/spl_mmc.c - mmc_load_image_raw static?void?mmc_load_image_raw(struct?mmc*mmc)
{
u32 image_size_sectors, err;
const?struct?image_header?*header;
header?=?(struct?image_header*)(CONFIG_SYS_TEXT_BASE?-
sizeof(struct?image_header));
/* read image header to find the image size & load address */
err?=?mmc->block_dev.block_read(0,
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR,?1,
(void?*)header);
if?(err?<=?0)
goto?end;
spl_parse_image_header(header);
/* convert size to sectors - round up */
image_size_sectors?=?(spl_image.size?+?mmc->read_bl_len-?1)?/
mmc->read_bl_len;
/* Read the header too to avoid extra memcpy */
err?=?mmc->block_dev.block_read(0,
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR,
image_size_sectors, (void?*)spl_image.load_addr);?//此處確定了Uboot讀取位置
end:
if?(err?<=?0) {
printf("spl: mmc blk read err - %d\n", err);
hang();
}
} u-boot-sunxi/include/configs/sunxi-common.h #define?CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR (64)/* 32KB offset */
#define?CONFIG_SYS_U_BOOT_MAX_SIZE_SECTORS (400)/* 200KB, enough for a full u-boot.bin */ 通過CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR確定了我們把完整的uboot寫入到TF卡從32K位置開始。
DRAM:?1024MB
SUNXI SD/MMC:0
U-Boot?2012.10-04277-g7aa9f04 (Mar10?2013?-?00:36:40) Allwinner Technology
CPU:?SUNXI Family
Board:?Cubieboard
I2C:?ready
DRAM:?1?GiB
MMC:?SUNXI SD/MMC:0
***?Warning-?bad CRC, using default environment
In:?serial
Out:?serial
Err:?serial
Hit any key to stop autoboot:?0?
**?Unable to use mmc0:1for?fatload?**
Loading file?"uEnv.txt"?from mmc device?0:1
Failed to mount ext2 filesystem...
**?Bad ext2 partitionor?disk?-?mmc0:1**
ext2load?-?load binary file from a Ext2 filesystem
Usage:
ext2load?<interface><dev[:part]>?[addr] [filename] [bytes]
-?load binary file?'filename'?from?'dev'?on?'interface'
to address?'addr'?from ext2 filesystem
Loading file?"boot/uEnv.txt"?from mmc device?0:1
Failed to mount ext2 filesystem...
**?Bad ext2 partitionor?disk?-?mmc0:1**
ext2load?-?load binary file from a Ext2 filesystem
Usage:
ext2load?<interface><dev[:part]>?[addr] [filename] [bytes]
-?load binary file?'filename'?from?'dev'?on?'interface'
to address?'addr'?from ext2 filesystem
**?Unable to use mmc0:1for?fatload?**
Loading file?"boot.scr"?from mmc device?0:1
Failed to mount ext2 filesystem...
**?Bad ext2 partitionor?disk?-?mmc0:1**
ext2load?-?load binary file from a Ext2 filesystem
Usage:
ext2load?<interface><dev[:part]>?[addr] [filename] [bytes]
-?load binary file?'filename'?from?'dev'?on?'interface'
to address?'addr'?from ext2 filesystem
Loading file?"boot/boot.scr"?from mmc device?0:1
Failed to mount ext2 filesystem...
**?Bad ext2 partitionor?disk?-?mmc0:1**
ext2load?-?load binary file from a Ext2 filesystem
Usage:
ext2load?<interface><dev[:part]>?[addr] [filename] [bytes]
-?load binary file?'filename'?from?'dev'?on?'interface'
to address?'addr'?from ext2 filesystem
**?Unable to use mmc0:1for?fatload?**
sun4i# 通過串口信息可以看到SPL和Uboot已經(jīng)成功加載,uboot最后通過ext2load命令讀取uEnv.txt和boot.scr文件失敗后退回控制臺(tái)。 下面通過源碼分析SPL載入完整Uboot的過程。 /u-boot-sunxi/common/spl/spl.c - board_init_r void?board_init_r(gd_t?*dummy1, ulong dummy2)
{
u32 boot_device;
debug(">>spl:board_init_r()\n");
puts(">>spl:board_init_r()\n");
#ifdef?CONFIG_SYS_SPL_MALLOC_START
mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,
CONFIG_SYS_SPL_MALLOC_SIZE);
#endif
timer_init();
#ifdef?CONFIG_SPL_BOARD_INIT
spl_board_init();
#endif
boot_device?=?spl_boot_device();?//檢測(cè)啟動(dòng)設(shè)備,此處返回BOOT_DEVICE_MMC1
debug("boot device - %d\n", boot_device);
switch?(boot_device) {
#ifdef?CONFIG_SPL_RAM_DEVICE
case?BOOT_DEVICE_RAM:
spl_ram_load_image();
break;
#endif
#ifdef?CONFIG_SPL_MMC_SUPPORT
case?BOOT_DEVICE_MMC1:
case?BOOT_DEVICE_MMC2:
case?BOOT_DEVICE_MMC2_2:
spl_mmc_load_image();?//通過mmc讀取image
break;
#endif
#ifdef?CONFIG_SPL_NAND_SUPPORT
case?BOOT_DEVICE_NAND:
spl_nand_load_image();
break;
#endif
#ifdef?CONFIG_SPL_NOR_SUPPORT
case?BOOT_DEVICE_NOR:
spl_nor_load_image();
break;
#endif
#ifdef?CONFIG_SPL_YMODEM_SUPPORT
case?BOOT_DEVICE_UART:
spl_ymodem_load_image();
break;
#endif
#ifdef?CONFIG_SPL_SPI_SUPPORT
case?BOOT_DEVICE_SPI:
spl_spi_load_image();
break;
#endif
#ifdef?CONFIG_SPL_ETH_SUPPORT
case?BOOT_DEVICE_CPGMAC:
#ifdef?CONFIG_SPL_ETH_DEVICE
spl_net_load_image(CONFIG_SPL_ETH_DEVICE);
#else
spl_net_load_image(NULL);
#endif
break;
#endif
default:
debug("SPL: Un-supported Boot Device\n");
hang();
}
switch?(spl_image.os) {
case?IH_OS_U_BOOT:
debug("Jumping to U-Boot\n");
break;
#ifdef?CONFIG_SPL_OS_BOOT
case?IH_OS_LINUX:
debug("Jumping to Linux\n");
spl_board_prepare_for_linux();
jump_to_image_linux((void?*)CONFIG_SYS_SPL_ARGS_ADDR);
#endif
default:
debug("Unsupported OS image.. Jumping nevertheless..\n");
}
jump_to_image_no_args();
} u-boot-sunxi/arch/arm/cpu/armv7/sunxi/board.c - spl_boot_device u32 spl_boot_device(void) {
u32 cfg;
#ifdef?CONFIG_SPL_NOR_SUPPORT
/* TODO */
#endif
#ifdef?CONFIG_SPL_MMC_SUPPORT
cfg?=?sunxi_gpio_get_cfgpin(SUNXI_GPC(7));
if( cfg?==?SUNXI_GPC7_SDC2_CLK )
return?BOOT_DEVICE_MMC2;
#endif
#ifdef?CONFIG_SPL_NAND_SUPPORT
cfg?=?sunxi_gpio_get_cfgpin(SUNXI_GPC(2));
if( cfg?==?SUNXI_GPC2_NCLE )
return?BOOT_DEVICE_NAND;
#endif
#ifdef?CONFIG_SPL_MMC_SUPPORT
cfg?=?sunxi_gpio_get_cfgpin(SUNXI_GPF(2));
if( cfg?==?SUNXI_GPF2_SDC0_CLK )
return?BOOT_DEVICE_MMC1;
#endif
/* if we are here, something goes wrong. Fall back on MMC */
return?BOOT_DEVICE_MMC1;
} 啟動(dòng)設(shè)備是通過讀取連接相應(yīng)設(shè)備的GPIO狀態(tài)來判斷的,但在上述條件下執(zhí)行該段代碼時(shí)并沒有成功檢測(cè)到設(shè)備,直到最后返回BOOT_DEVICE_MMC1。 u-boot-sunxi/drivers/mmc/spl_mmc.c - spl_mmc_load_image void?spl_mmc_load_image(void)
{
struct?mmc?*mmc;
int?err;
u32 boot_mode;
mmc_initialize(gd->bd);
/* We register only one device. So, the dev id is always 0 */
mmc?=?find_mmc_device(0);
if?(!mmc) {
puts("spl: mmc device not found!!\n");
hang();
}?
err?=?mmc_init(mmc);
if?(err) {
printf("spl: mmc init failed: err - %d\n", err);
hang();
}?
boot_mode?=?spl_boot_mode();?// sunxi的代碼在此處直接返回了MMCSD_MODE_RAW
if?(boot_mode?==?MMCSD_MODE_RAW) {
debug("boot mode - RAW\n");
mmc_load_image_raw(mmc);
#ifdef?CONFIG_SPL_FAT_SUPPORT
}?else?if?(boot_mode?==?MMCSD_MODE_FAT) {
debug("boot mode - FAT\n");
mmc_load_image_fat(mmc);
#endif
}?else?{
puts("spl: wrong MMC boot mode\n");
hang();
}?
} u-boot-sunxi/drivers/mmc/spl_mmc.c - mmc_load_image_raw static?void?mmc_load_image_raw(struct?mmc*mmc)
{
u32 image_size_sectors, err;
const?struct?image_header?*header;
header?=?(struct?image_header*)(CONFIG_SYS_TEXT_BASE?-
sizeof(struct?image_header));
/* read image header to find the image size & load address */
err?=?mmc->block_dev.block_read(0,
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR,?1,
(void?*)header);
if?(err?<=?0)
goto?end;
spl_parse_image_header(header);
/* convert size to sectors - round up */
image_size_sectors?=?(spl_image.size?+?mmc->read_bl_len-?1)?/
mmc->read_bl_len;
/* Read the header too to avoid extra memcpy */
err?=?mmc->block_dev.block_read(0,
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR,
image_size_sectors, (void?*)spl_image.load_addr);?//此處確定了Uboot讀取位置
end:
if?(err?<=?0) {
printf("spl: mmc blk read err - %d\n", err);
hang();
}
} u-boot-sunxi/include/configs/sunxi-common.h #define?CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR (64)/* 32KB offset */
#define?CONFIG_SYS_U_BOOT_MAX_SIZE_SECTORS (400)/* 200KB, enough for a full u-boot.bin */ 通過CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR確定了我們把完整的uboot寫入到TF卡從32K位置開始。
?
總結(jié)
以上是生活随笔為你收集整理的全志A10 Bootload加载过程分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NVIDIA刀法有点狠:GTX 1630
- 下一篇: android 4.2以上版本永不休眠