全志A10 Bootload加载过程分析

A10的启动过程大概可分为5步:BootRom,SPL,Uboot,Kernel,RootFileSystem。本文只关注镜像的加载过程,分析RootRom->SPL->Uboot的启动流程。
系统上电后,ARM处理器在复位时从地址0x000000开始执行指令,把板上ROM或Flash映射到这一地址。A10将启动设备选择程序固化在CPU内部的一个32KB ROM中,默认的启动时序为SD Card0,NAND FLASH,SD Card2,SPI NOR FLASH。另外通过外部的一个启动选择引脚可以使其跳转到USB启动模式。通常情况下,启动选择引脚状态连接50K内部上拉电阻。在上电后,执行存储在ROM中的启动代码,将自动检测启动选择引脚状态。只有当该引脚状态为低电平时选择USB启动模式。
启动设备选择程序的流程图:
全志A10 Bootload加载过程分析_第1张图片
 
在选择启动设备后将加载并执行bootload程序,CPU通过拷贝或映射bootload程序到内存,然后执行bootload的第一条指令。通过阅读官方的uboot烧写方法,发现A10通过uboot引导系统,但却没有加载整个uboot,而是在此之前先载入了uboot SPL。什么是SPL?通过查阅uboot的官网资料得知,SPL是一个迷你版的uboot,全拼为Second Program Loader。适用于SOC的内部SROM<64K的情况,用它来加载完整的uboot程序到SDROM,并通过完整uboot加载内核来启动系统。
 
SPL程序流程如下:
1.初始化ARM处理器
2.初始化串口控制台
3.配置时钟和最基础的分频
4.初始化SDRAM
5.配置引脚多路复用功能
6.启动设备初始化(即上面选择的启动设备)
7.加载完整的uboot程序并转交控制权
 
 
搞清楚了上面的概念,可以知道Cubieboard出厂已经烧写了NandFlash中的程序,即在启动选择时使用的是NandFlash。现在根据全志A10上的步骤,我们尝试用SDC1(即Cubieboard上卡槽中的TF卡)来启动系统。
 
下载并编译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卡烧写引导程序
#dd if=/dev/zero of=/dev/sdb bs=1M count=1 # 清空SD卡(包括分区表)
尝试不建立分区表,直接烧写引导程序,无法启动系统。
因此按需求给TF卡分区,我只创建了唯一一个200M主分区,此处不详述分区过程,下面是我使用的TF卡的分区表信息。
$ 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相关资料,通过以下2条命令烧写spl和uboot到指定位置,暂时不清楚如何确定这2个读取位置。
#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转TTL串口线,打开串口终端,上电。
串口打印信息如下:
U -Boot SPL 2012. 10 - 04277 -g7aa9f04 (Mar 10 2013 - 00 : 36 : 40)
DRAM : 1024MB
SUNXI SD /MMC : 0


U -Boot 2012. 10 - 04277 -g7aa9f04 (Mar 10 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 mmc 0 : 1 for fatload * *
Loading file "uEnv.txt" from mmc device 0 : 1
Failed to mount ext2 filesystem...
* * Bad ext2 partition or disk - mmc 0 : 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 partition or disk - mmc 0 : 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 mmc 0 : 1 for fatload * *
Loading file "boot.scr" from mmc device 0 : 1
Failed to mount ext2 filesystem...
* * Bad ext2 partition or disk - mmc 0 : 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 partition or disk - mmc 0 : 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 mmc 0 : 1 for fatload * *
sun4i #
通过串口信息可以看到SPL和Uboot已经成功加载,uboot最后通过ext2load命令读取uEnv.txt和boot.scr文件失败后退回控制台。
 
下面通过源码分析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(); //检测启动设备,此处返回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;
}
启动设备是通过读取连接相应设备的GPIO状态来判断的,但在上述条件下执行该段代码时并没有成功检测到设备,直到最后返回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位置开始。

 

你可能感兴趣的:(A10,cubieboard)