[1],先看一下整个系统的结构(软件是灵魂,硬件是驱体,再强大的灵魂力若没有躯体终将是游魂野鬼,再强壮的驱体若没有灵魂终将是植物人)
结构 | 作用 | 备注 |
硬件 | 一切软件的载体 | |
xloader | 引导uboot | |
uboot | 启动加载或下载linux kernel | |
linux kernel | OS,承载android | |
android | OS,承载APP |
[2],为什么需要xloader?
cpu上电后会自动加载一小段程序到内部ram中运行,内部的ram资源很小,一般只有几十k的空间,比如我现在用的cpu就只有32k的空间。uboot功能很强,具有初始化,交互操作,下载和引导linux的作用,因此体积上会超过cpu内部的ram大小,所以我们需要更小的xloader来为我们加载引导uboot。xloader一般只作一些最最核心的硬件初始化,比如cpu时钟,外部内存,flash和usb/SD/uart的初始化工作,然后就加载uboot,把更深入的初始就交给uboot来执行。
[3],xloader执行流程
[首先],看x-loader.lds文件,通过以下命令得到lds文件的路径
1 $ find -name "*.lds"
打开x-loader.lds如下:
1 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 2 //指定输出可执行文件是elf格式,32位ARM指令,小端 3 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") 4 //指定输出可执行文件的平台为ARM 5 OUTPUT_ARCH(arm) 6 //指定输出可执行文件的起始代码段为_start 7 ENTRY(_start) 8 SECTIONS 9 { 10 //从0x0位置开始,但会在vim board/copener_pad_ref/config.mk 文件里面定义为TEXT_BASE = 0x07041000 11 . = 0x00000000; 12 13 //代码以4字节对齐 14 . = ALIGN(4); 15 //指定代码段 16 .text : 17 { 18 cpu/copener/start.o (.text) //代码的第一个代码部分 19 *(.text) //其它代码部分 20 } 21 22 . = ALIGN(4); 23 24 //指定只读数据段 25 .rodata : { *(.rodata) } 26 27 . = ALIGN(4); 28 29 //指定可读写数据段 30 .data : { *(.data) } 31 32 . = ALIGN(4); 33 34 //指定got段, got段式是uboot自定义的一个段, 非标准段 35 .got : { *(.got) } 36 37 . = ALIGN(4); 38 39 //把__bss_start赋值为当前位置,即bss段的开始位置 40 __bss_start = .; 41 42 //指定bss段 43 .bss : { *(.bss) } 44 45 //把_end赋值为当前位置,即bss段的结束位置 46 _end = .; 47 }
由上面可知程序的入口为“cpu/copener/start.S”文件,且入口函数为“_start”,开头已经有了,接下来就是怎么跟踪代码了。
[然后],跟踪start.S文件:
start.S是汇编写的文件,主要是执行了下面的操作
1 // set the cpu to SVC32 mode 2 // disable MMU 3 // Enable all domains to client mode 4 // Invalidate instruction cache 5 // Invalidate data cache 6 // Invalidate entire Unified main TLB 7 8 ldr pc, _start_armboot /* jump to C code */ 9 _start_armboot: .word start_armboot
start.S的最后通过“ldr pc, _start_armboot”跳入C代码中运行了。通过下面的命令把start_armboot函数所在文件lib/board.c找出。
1 $ grep -rnws start_armboot
打开board.c,该函数简化后的操作如下
1 void start_armboot (void) 2 { 3 board_init(); //pad_ref.c 空函数 4 uart_init(CFG_UART_BAUD_RATE); //uart.c 初始化串口 5 cpu_init(); //cpu.c 设置一下cpu的频率 6 ddr_init(); //ddr_init.c 初始化ddr 7 mem_test(); //board.c 内存测试 8 9 for(idx = 0;idx < 892;) { 10 sram_dat = readl(SRAM_BASE_ADDR + idx); 11 writel(sram_dat,DDR_DATA_BASE + idx); 12 idx = idx + 4; 13 } 14 15 16 if (check_romloader_fastboot()) { //检测引导设置,若符合usb引导则fastboot USB 17 TRACE(KERN_INFO, "enter fastboot USB boot\n"); 18 usb_boot(0x02); //进入USB引导操作 19 } 20 21 22 switch(readl(CFG_BOOT_MODE) & 0x3){ //检测其它引导模式进入相应操作 23 case 0x00: 24 TRACE(KERN_INFO,"SDIO\n"); 25 sdmmc_continue_boot(0x0); 26 27 case 0x02: 28 TRACE(KERN_INFO,"USB\n"); 29 usb_boot(0x02); 30 break; 31 32 case 0x03: 33 TRACE(KERN_UART,"UART\n"); 34 uart_boot(0x03); 35 break; 36 default: 37 TRACE(KERN_ERROR,"No Boot Source\n"); 38 break; 39 } 40 TRACE(KERN_ERROR,"No U-boot found\n"); 41 while(1); 42 }
而后面的usb_boot(0x02)又会调用handle_fastboot(rxdata, rxsize, boot_mode),进而调用enter_entry(head.entry, boot_mode),最后调用(*(void(*)())buf)(boot_mode),然后就跳进uboot里面去运行了。
(*(void(*)())buf)(boot_mode)是一个函数指针,类型为void(*)(),指向的是buf地址,即head.entry,涉及到的结构体如下:
1 typedef struct { 2 char tag[4]; //NUFX 3 unsigned int offset; // 4 unsigned int entry; //where to place 5 unsigned int size; //size of binary 6 unsigned int loader_cksum; //chsum of binary 7 unsigned int header_cksum; //cksum of first 16 bytes of header 8 }xl_header; 9 extern xl_header head;
由config.mk文件指定TEXT_BASE = 0x07041000,然后通过偏移算出Head.entry = 0x7041008。即xloader最后要跳转的地址为0x7041008。
[4]xloader的编译
1 //清除上一次编译 2 $ make distclean 3 4 //配置当前编译 5 $ make copener_pad_ref_config 6 7 //编译 8 $ make 9 10 11 //////////////////////////////////////生成文件时打印的信息////////////////////////////////////// 12 Generate x-load.img from x-load 13 ELF Entry = 0x7041008 14 ELF Program number = 2 15 ELF Program Header Offset = 52 16 Program[0]: offset=0x200, Size=0x74f8 17 Program[1]: offset=0x61656100, Size=0x412d3705 18 Head.tag = NUFX 19 Head.offset = 0x200 20 Head.entry = 0x7041008 21 Head.size = 0x74fc 22 Head.loader_cksum = 0x55157080 23 Head.header_cksum = 0xb4604cd2
生成的文件为:
1 oee@copener:/opt/ns115_jb/bsp/xloader$ ls -lh 2 -rwxrwxr-x 1 oee oee 30K 5月 26 12:40 x-load.bin 3 -rw-rw-r-- 1 oee oee 30K 5月 26 12:40 x-load.img