Android 4.0启动流程分析

来源:互联网 发布:算法第四版答案 王晓东 编辑:程序博客网 时间:2024/06/05 07:06

在分析SPRD启动流程之前,第一步:先来分析一下嵌入式系统一般的启动流程,也就是从uboot开始在到启动kernel模块。第二部:再来分析一下SPRD android系统的启动与一般启动有和不同,启动过程分析道android init进程起来为止。至于init后的启动过程应该是地球人都知道的。

 

第一部分:关于uboot分析有些摘自网络,

http://blog.chinaunix.net/uid-24951403-id-2212589.html

bootloader 除了依赖CPU,还依赖板级设备的配置,例如板卡的硬件地址分配,外设硬件芯片的类型。不同的板子需修改bootloader。阶段1:硬件初始化,为加载bootloader的二阶段准备RAM空间,拷贝2阶段代码到内存,设置好堆栈,跳到2阶段,初始化本阶段要的设备,将内核和根文件从flash中拷贝到RAM中,最后调用内核。





1、Stage1 start.S代码结构 u-boot的stage1代码通常放在start.S文件中,他用汇编语言写成,其主要代码部分如下

(1)定义入口。:

该工作通过修改连接器脚本来完成。

(2)设置异常向量(Exception Vector)。

(3)设置CPU的速度、时钟频率及终端控制寄存器。

(4)初始化内存控制器。

(5)将ROM中的程序复制到RAM中。

(6)初始化堆栈。

(7)转到RAM中执行,该工作可使用指令ldr pc来完成。

2、Stage2

 C语言代码部分lib_arm/board.c中的start arm boot是C语言开始的函数也是整个启动代码中C语言的主函数,同时还是整个u-boot(armboot)的主函数,该函数只要完成如下操作:

(1)调用一系列的初始化函数。

(2)初始化Flash设备。

(3)初始化系统内存分配函数。

(4)如果目标系统拥有NAND设备,则初始化NAND设备。

(5)如果目标系统有显示设备,则初始化该类设备。

(6)初始化相关网络设备,填写IP、MAC地址等。

(7)进去命令循环(即整个boot的工作循环),接受用户从串口输入的命令,然后进行相应的工作。


3、U-Boot的启动顺序

发板上电后,执行U-Boot的第一条指令,然后顺序执行U-Boot启动函数。看一下u-boot\board\spreadtrum\sp6825ga/u-boot.lds这个链接脚本,可以知道目标程序的各部分链接顺序。第一个要链接的是arch/arm/cpu/arm926ejs/start.o,那么U-Boot的入口指令一定位于这个程序中。下面分两阶段介绍启动流程:

如下:u-boot\board\spreadtrum\sp6825ga\start.sOUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")OUTPUT_ARCH(arm)ENTRY(_start)SECTIONS{. = 0x00000000;. = ALIGN(4);.text :{arch/arm/cpu/arm926ejs/start.o(.text)*(.text)}. = ALIGN(4);.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }. = ALIGN(4);.data : { *(.data) }. = ALIGN(4);.got : { *(.got) }. = .;__u_boot_cmd_start = .;.u_boot_cmd : { *(.u_boot_cmd) }__u_boot_cmd_end = .;. = ALIGN(4);__bss_start = .;.bss (NOLOAD) : { *(.bss) . = ALIGN(4); }_end = .;}

第一阶段

1.  start.S  这个汇编程序是U-Boot的入口程序,开头就是复位向量的代码。

.globl _start_start: breset //复位向量… …ldrpc, _undefined_instructionldrpc, _software_interruptldrpc, _prefetch_abortldrpc, _data_abortldrpc, _not_usedldrpc, _irq   //中断向量ldrpc, _fiq   //… …/* * the actual reset code */reset://复位启动子程序/* * set the cpu to SVC32 mode */#ifndef CONFIG_SKIP_LOWLEVEL_INIT#ifdef SPRD_EVM_TAG_ONldr r0,=SPRD_EVM_ADDR_STARTldr r1,=0x87003004ldr r2,[r1]str r2,[r0]#endif   /*?设置CPU为SVC32模式?*/mrsr0, cpsrbicr0, r0, #0x1forrr0, r0, #0xd3msrcpsr,r0#endif… …#ifndef CONFIG_SKIP_LOWLEVEL_INITblcpu_init_critmov    r10, #0/*set up temp stack*///设置堆栈LDR    sp, =SVC_STACK_TEMPSTMDB sp!,{lr} bl lowlevel_init//初始化CPU@bl MMU_Init     //初始化MMU内存管理单元/*Re-set up stack  The sp here must be in the reserved region  *///重新设置堆栈  sp必须指向此区域LDMIA sp!, {lr}LDR     sp, =SPL_STACK #endif/* Set stackpointer in internal RAM to call board_init_f *///设置堆栈指针 指向 RAM 调用board_init_fcall_board_init_f:ldrsp, =(CONFIG_SYS_INIT_SP_ADDR)bicsp, sp, #7 /* 8-byte alignment for ABI compliance */#ifndef CONFIG_NAND_SPLldrr0,=0x00000000blboard_init_f#elseldr r0, =(CONFIG_SYS_INIT_SP_ADDR)ldr r1, =0x00000000ldr r2, =(CONFIG_SYS_TEXT_BASE)bl relocate_code#endif… …/* * We are done. Do not return, instead branch to second part of board * initialization, now running from RAM. */jump_2_ram:#ifdef CONFIG_NAND_SPLldr     r0, _nand_boot_ofsmovpc, r0_nand_boot_ofs:.word nand_boot#elseldrr0, _board_init_r_ofsadrr1, _startaddlr, r0, r1addlr, lr, r9/* setup parameters for board_init_r */movr0, r5/* gd_t */movr1, r6/* dest_addr *//* jump to it ... */movpc, lr_board_init_r_ofs:.word board_init_r - _start#endif

第二阶段:跳转到u-boot\arch\arm\lib

start_armboot是U-Boot执行的第一个C语言函数,完成系统初始化工作,进入主循环,处理用户输入的命令。

在board_init_f函数中有init_sequence[]

init_sequence[]数组保存着基本的初始化函数指针。

 

init_fnc_t *init_sequence[] = {

cpu_init,  /* 基本的处理器相关配置 -- arch\arm\cpu\armv7 */

board_init,/* 基本的板级相关配置 -- board\spreadtrum\sp6825ga*/

interrupt_init,  /* 初始化中断处理 -- arch\arm\lib/interrupt.c */

env_init,      /* 初始化环境变量 --common/cmd_flash.c */

init_baudrate,  /* 初始化波特率设置 --lib_arm/board.c */

serial_init,  /* 串口通讯设置 -- common /serial.c*/

console_init_f,       /* 控制台初始化阶段1 --common/console.c */

display_banner,       /* 打印u-boot信息 --lib_arm/board.c */

dram_init,     /* 配置可用的RAM -- board/ spreadtrum/ openphone.c */

display_dram_config,  /* 显示RAM的配置大小 --lib_arm/board.c */

NULL,

};


void board_init_f (ulong bootflag){bd_t *bd;init_fnc_t **init_fnc_ptr;gd_t *id;ulong addr, addr_sp;/* Pointer is writable since we allocated a register for it */gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);/* compiler optimization barrier needed for GCC >= 3.4 */__asm__ __volatile__("": : :"memory");memset ((void*)gd, 0, sizeof (gd_t));gd->mon_len = _bss_end_ofs;  /* 顺序执行init_sequence数组中的初始化函数 */ for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {if ((*init_fnc_ptr)() != 0) {hang ();}}debug ("monitor len: %08lX\n", gd->mon_len);/* * Ram is setup, size stored in gd !! */debug ("ramsize: %08lX\n", gd->ram_size);#if defined(CONFIG_SYS_MEM_TOP_HIDE)/* * Subtract specified amount of memory to hide so that it won't * get "touched" at all by U-Boot. By fixing up gd->ram_size * the Linux kernel should now get passed the now "corrected" * memory size and won't touch it either. This should work * for arch/ppc and arch/powerpc. Only Linux board ports in * arch/powerpc with bootwrapper support, that recalculate the * memory size from the SDRAM controller setup will have to * get fixed. */gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE;#endifaddr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;#ifdef CONFIG_LOGBUFFER#ifndef CONFIG_ALT_LB_ADDR/* reserve kernel log buffer */addr -= (LOGBUFF_RESERVE);debug ("Reserving %dk for kernel logbuffer at %08lx\n", LOGBUFF_LEN, addr);#endif#endif#ifdef CONFIG_PRAM/* * reserve protected RAM */i = getenv_r ("pram", (char *)tmp, sizeof (tmp));reg = (i > 0) ? simple_strtoul ((const char *)tmp, NULL, 10) : CONFIG_PRAM;addr -= (reg << 10);/* size is in kB */debug ("Reserving %ldk for protected RAM at %08lx\n", reg, addr);#endif /* CONFIG_PRAM */#if !(defined(CONFIG_SYS_NO_ICACHE) && defined(CONFIG_SYS_NO_DCACHE))/* reserve TLB table */addr -= (4096 * 4);/* round down to next 64 kB limit */addr &= ~(0x10000 - 1);gd->tlb_addr = addr;debug ("TLB table at: %08lx\n", addr);#endif/* round down to next 4 kB limit */addr &= ~(4096 - 1);debug ("Top of RAM usable for U-Boot at: %08lx\n", addr);#ifdef CONFIG_VFD#ifndef PAGE_SIZE#  define PAGE_SIZE 4096#endif/* * reserve memory for VFD display (always full pages) */addr -= vfd_setmem (addr);gd->fb_base = addr;#endif /* CONFIG_VFD */#ifdef CONFIG_LCD/* reserve memory for LCD display (always full pages) */addr = lcd_setmem (addr);gd->fb_base = addr;#endif /* CONFIG_LCD *//* * reserve memory for U-Boot code, data & bss * round down to next 4 kB limit */addr -= gd->mon_len;addr &= ~(4096 - 1);debug ("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr);#ifndef CONFIG_PRELOADER/* * reserve memory for malloc() arena */addr_sp = addr - TOTAL_MALLOC_LEN;debug ("Reserving %dk for malloc() at: %08lx\n",TOTAL_MALLOC_LEN >> 10, addr_sp);/* * (permanently) allocate a Board Info struct * and a permanent copy of the "global" data */addr_sp -= sizeof (bd_t);bd = (bd_t *) addr_sp;gd->bd = bd;debug ("Reserving %zu Bytes for Board Info at: %08lx\n",sizeof (bd_t), addr_sp);addr_sp -= sizeof (gd_t);id = (gd_t *) addr_sp;debug ("Reserving %zu Bytes for Global Data at: %08lx\n",sizeof (gd_t), addr_sp);/* setup stackpointer for exeptions */gd->irq_sp = addr_sp;#ifdef CONFIG_USE_IRQaddr_sp -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);debug ("Reserving %zu Bytes for IRQ stack at: %08lx\n",CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ, addr_sp);#endif/* leave 3 words for abort-stack    */addr_sp -= 3;/* 8-byte alignment for ABI compliance */addr_sp &= ~0x07;#elseaddr_sp += 128;/* leave 32 words for abort-stack   */gd->irq_sp = addr_sp;#endifdebug ("New Stack Pointer is: %08lx\n", addr_sp);#ifdef CONFIG_POSTpost_bootmode_init();post_run (NULL, POST_ROM | post_bootmode_get(0));#endifgd->bd->bi_baudrate = gd->baudrate;/* Ram ist board specific, so move it to board code ... */dram_init_banksize();display_dram_config();/* and display it */gd->relocaddr = addr;gd->start_addr_sp = addr_sp;gd->reloc_off = addr - _TEXT_BASE;debug ("relocation Offset is: %08lx\n", gd->reloc_off);memcpy (id, (void *)gd, sizeof (gd_t));/* 配置环境变量*/relocate_code (addr_sp, id, addr);/* NOTREACHED - relocate_code() does not return */}

然后还会调用此函数

在start.s中

/* * We are done. Do not return, instead branch to second part of board * initialization, now running from RAM. */jump_2_ram:#ifdef CONFIG_NAND_SPLldr     r0, _nand_boot_ofsmovpc, r0_nand_boot_ofs:.word nand_boot#elseldrr0, _board_init_r_ofsadrr1, _startaddlr, r0, r1addlr, lr, r9/* setup parameters for board_init_r */movr0, r5/* gd_t */movr1, r6/* dest_addr *//* jump to it ... */movpc, lr_board_init_r_ofs:.word board_init_r - _start#endif

将调用board.c中的board_init_r 

/************************************************************************ * * This is the next part if the initialization sequence: we are now * running from RAM and have a "normal" C environment, i. e. global * data can be written, BSS has been cleared, the stack size in not * that critical any more, etc. * ************************************************************************ */void board_init_r (gd_t *id, ulong dest_addr){char *s;bd_t *bd;ulong malloc_start;#if !defined(CONFIG_SYS_NO_FLASH)ulong flash_size;#endifgd = id;bd = gd->bd;gd->flags |= GD_FLG_RELOC;/* tell others: relocation done */monitor_flash_len = _bss_start_ofs;debug ("monitor flash len: %08lX\n", monitor_flash_len);board_init();/* Setup chipselects */    boot_pwr_check();#ifdef CONFIG_SERIAL_MULTIserial_initialize();#endifdebug ("Now running in RAM - U-Boot at: %08lx\n", dest_addr);#ifdef CONFIG_LOGBUFFERlogbuff_init_ptrs ();#endif#ifdef CONFIG_POSTpost_output_backlog ();#endif/* The Malloc area is immediately below the monitor copy in DRAM */malloc_start = dest_addr - TOTAL_MALLOC_LEN;#ifdef SPRD_EVM_TAG_ONSPRD_EVM_TAG(4);#endif    /* _armboot_start在u-boot.lds链接脚本中定义*/mem_malloc_init (malloc_start, TOTAL_MALLOC_LEN);#ifdef SPRD_EVM_TAG_ONSPRD_EVM_TAG(5);#endif    boot_pwr_check();#if !defined(CONFIG_SYS_NO_FLASH)puts ("FLASH: ");    /*配置可用的Flash */ if ((flash_size = flash_init ()) > 0) {# ifdef CONFIG_SYS_FLASH_CHECKSUMprint_size (flash_size, "");/* * Compute and print flash CRC if flashchecksum is set to 'y' * * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX */s = getenv ("flashchecksum");if (s && (*s == 'y')) {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 ();}#endif    boot_pwr_check();#if !defined(CONFIG_EMMC_BOOT)#if defined(CONFIG_CMD_NAND)puts ("NAND:  ");nand_init();/* go init the NAND */#endif#endif    boot_pwr_check();#ifdef SPRD_EVM_TAG_ONSPRD_EVM_TAG(6);#endif#if defined(CONFIG_CMD_ONENAND)#if !(defined CONFIG_TIGER && defined CONFIG_EMMC_BOOT)onenand_init();#endif#endif#ifdef CONFIG_GENERIC_MMC       puts("MMC:   ");       mmc_initialize(bd);#endif#ifdef CONFIG_HAS_DATAFLASHAT91F_DataflashInit();dataflash_print_info();#endif#ifdef CONFIG_EMMC_BOOTmmc_legacy_init(1);#endif/* initialize environment */env_relocate ();    boot_pwr_check();#ifdef CONFIG_VFD/* must do this after the framebuffer is allocated */drv_vfd_init();#endif /* CONFIG_VFD *//*tempaily use for tiger to avoid died as refreshing LCD*//* IP Address */ /* 从环境变量中获取IP地址 */gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");  stdio_init ();/* get the devices list going. */    boot_pwr_check();jumptable_init ();    boot_pwr_check();#if defined(CONFIG_API)/* Initialize API */api_init ();#endif    char fake[4]="fak";    setenv("splashimage", fake);    /* 完整地初始化控制台设备 */console_init_r ();/* fully init console as a device */    boot_pwr_check();#if defined(CONFIG_ARCH_MISC_INIT)/* miscellaneous arch dependent initialisations */arch_misc_init ();#endif#if defined(CONFIG_MISC_INIT_R)/* miscellaneous platform dependent initialisations */misc_init_r ();#endif /* set up exceptions */interrupt_init ();/* enable exceptions */enable_interrupts ();/* 使能中断处理 */    boot_pwr_check();/* Perform network card initialisation if necessary */#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)/* XXX: this needs to be moved to board init */if (getenv ("ethaddr")) {uchar enetaddr[6];eth_getenv_enetaddr("ethaddr", enetaddr);smc_set_mac_addr(enetaddr);}#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 *//* Initialize from environment */ /* 通过环境变量初始化 */if ((s = getenv ("loadaddr")) != NULL) {load_addr = simple_strtoul (s, NULL, 16);}#if defined(CONFIG_CMD_NET)if ((s = getenv ("bootfile")) != NULL) {copy_filename (BootFile, s, sizeof (BootFile));}#endif    boot_pwr_check();//usb_eth_initialize(NULL);#ifdef BOARD_LATE_INITboard_late_init ();#endif#ifdef CONFIG_BITBANGMIIbb_miiphy_init();#endif#if defined(CONFIG_CMD_NET)#if defined(CONFIG_NET_MULTI)puts ("Net:   ");#endif//eth_initialize(gd->bd);#if defined(CONFIG_RESET_PHY_R)debug ("Reset Ethernet PHY\n");reset_phy();#endif#endif#ifdef CONFIG_POSTpost_run (NULL, POST_RAM | post_bootmode_get(0));#endif    boot_pwr_check();#if defined(CONFIG_PRAM) || defined(CONFIG_LOGBUFFER)/* * Export available size of memory for Linux, * taking into account the protected RAM at top of memory */{ulong pram;uchar memsz[32];#ifdef CONFIG_PRAMchar *s;if ((s = getenv ("pram")) != NULL) {pram = simple_strtoul (s, NULL, 10);} else {pram = CONFIG_PRAM;}#elsepram=0;#endif#ifdef CONFIG_LOGBUFFER#ifndef CONFIG_ALT_LB_ADDR/* Also take the logbuffer into account (pram is in kB) */pram += (LOGBUFF_LEN+LOGBUFF_OVERHEAD)/1024;#endif#endifsprintf ((char *)memsz, "%ldk", (bd->bi_memsize / 1024) - pram);setenv ("mem", (char *)memsz);}#endif#ifdef SPRD_EVM_TAG_ONSPRD_EVM_TAG(11);#endif    extern int do_cboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);    boot_pwr_check();    do_cboot(NULL, 0, 1, NULL);/* main_loop() can return to retry autoboot, if so just run it again. */for (;;) {main_loop ();/* 主循环函数处理执行用户命令 -- common/main.c */}/* NOTREACHED - no way out of command loop except booting */}

命令实现

U-Boot作为Bootloader,具备多种引导内核启动的方式。常用的do命令可以直接引导内核映像启动。U-Boot与内核的关系主要是内核启动过程中参数的传递。

1.  do命令的实现:

查看参数:do_cboot(NULL, 0, 1, NULL); 

u-boot\propertyU_BOOT_CMD(            cboot, CONFIG_SYS_MAXARGS, 1, do_cboot,            "choose boot mode",            "mode: \nrecovery, fastboot, dloader, charge, normal, vlx, caliberation.\n"            "cboot could enter a mode specified by the mode descriptor.\n"            "it also could enter a proper mode automatically depending on "            "the environment\n"          );int do_cboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]){  …  …boot_pwr_check();//检查是否有power按键… …CHG_Init();//充电模块初始化… …    boot_pwr_check();//再次检查是否有power按键    board_keypad_init();//初始化按键选项    boot_pwr_check();//再次检查是否有power按键    int recovery_init(void);//恢复出厂设置初始化    int ret =0;    ret = recovery_init();    if(ret == 1){        DBG("func: %s line: %d\n", __func__, __LINE__);        recovery_mode_without_update();    }else if(ret == 2){    try_update_modem(); //update img from mmc    normal_mode();    } … …    //检查重启模式    unsigned check_reboot_mode(void);    unsigned rst_mode= check_reboot_mode();    if(rst_mode == RECOVERY_MODE){        DBG("func: %s line: %d\n", __func__, __LINE__);        recovery_mode();    }    else if(rst_mode == FASTBOOT_MODE){        DBG("func: %s line: %d\n", __func__, __LINE__);        fastboot_mode();    }else if(rst_mode == NORMAL_MODE){        normal_mode();    }else if(rst_mode == WATCHDOG_REBOOT){        watchdog_mode();    }else if(rst_mode == UNKNOW_REBOOT_MODE){        unknow_reboot_mode();    }else if(rst_mode == PANIC_REBOOT){        panic_reboot_mode();    }else if(rst_mode == ALARM_MODE){              int flag =alarm_flag_check();              if(flag == 1)alarm_mode();              else if(flag == 2)normal_mode();    }else if(rst_mode == SLEEP_MODE){sleep_mode();    }else if(rst_mode == SPECIAL_MODE){special_mode();} … …    //充电连接,充电模式   if(charger_connected()){        DBG("%s: charger connected\n", __FUNCTION__);        charge_mode();}    //find the power up trigger //检查是否有power按键,是否是组合按键    else if(boot_pwr_check() >= get_pwr_key_cnt()){        DBG("%s: power button press\n", __FUNCTION__);DBG("boot_pwr_check=%d,get_pwr_key_cnt=%d\n",boot_pwr_check(),get_pwr_key_cnt());        //go on to check other keys        mdelay(50);        for(i=0; i<10;i++){            key_code = board_key_scan();            if(key_code != KEY_RESERVED)              break;        }DBG("key_code %d\n", key_code);        key_mode = check_key_boot(key_code);        switch(key_mode){            case BOOT_FASTBOOT:                fastboot_mode();                break;            case BOOT_RECOVERY:                recovery_mode();                break;            case BOOT_CALIBRATE:                engtest_mode();                return 0; //back to normal boot                break;            case BOOT_DLOADER:                dloader_mode();                break;            default:                break;        }    }    else if(alarm_triggered() && alarm_flag_check()){//alarm模式        DBG("%s: alarm triggered\n", __FUNCTION__);        int flag =alarm_flag_check();        if(flag == 1)alarm_mode();        else if(flag == 2)              normal_mode();    }else{#if BOOT_NATIVE_LINUX_MODEM        *(volatile u32*)CALIBRATION_FLAG = 0xca;#endif        calibration_detect(0);        //if calibrate success, it will here        DBG("%s: power done again\n", __FUNCTION__);        power_down_devices();        while(1)          ;    }//主要为1个参数,正常模式启动    if(argc == 1){DBG("func: %s line: %d\n", __func__, __LINE__);        normal_mode();        return 1;    }… …}

将会进入此函数normal_mode(normal_mode.c) 

void normal_mode(void){#if defined (CONFIG_SC8810) || defined (CONFIG_SC8825)    //MMU_Init(CONFIG_MMU_TABLE_ADDR);vibrator_hw_init();#endif    set_vibrator(1);//按开机按键震动设置#if BOOT_NATIVE_LINUX    vlx_nand_boot(BOOT_PART, CONFIG_BOOTARGS, BACKLIGHT_ON);#else    vlx_nand_boot(BOOT_PART, NULL, BACKLIGHT_ON);//从这里启动#endif}

将进入vlx_nand_boot(normal_nand_mode.c)

void vlx_nand_boot(char * kernel_pname, char * cmdline, int backlight_set){    boot_img_hdr *hdr = (void *)raw_header;struct mtd_info *nand;struct mtd_device *dev;struct part_info *part;u8 pnum;int ret;size_t size;loff_t off = 0;char *fixnvpoint = "/fixnv";char *fixnvfilename = "/fixnv/fixnv.bin";char *fixnvfilename2 = "/fixnv/fixnvchange.bin";char *backupfixnvpoint = "/backupfixnv";char *backupfixnvfilename = "/backupfixnv/fixnv.bin";char *runtimenvpoint = "/runtimenv";char *runtimenvfilename = "/runtimenv/runtimenv.bin";char *runtimenvfilename2 = "/runtimenv/runtimenvbkup.bin";char *productinfopoint = "/productinfo";char *productinfofilename = "/productinfo/productinfo.bin";char *productinfofilename2 = "/productinfo/productinfobkup.bin";int orginal_right, backupfile_right;unsigned long orginal_index, backupfile_index;nand_erase_options_t opts;char * mtdpart_def = NULL;#if (defined CONFIG_SC8810) || (defined CONFIG_SC8825)MMU_Init(CONFIG_MMU_TABLE_ADDR);//初始化MMU内存管理单元#endifret = mtdparts_init();//flash 区域初始化if (ret != 0){printf("mtdparts init error %d\n", ret);return;}#ifdef CONFIG_SPLASH_SCREEN#define SPLASH_PART "boot_logo"ret = find_dev_and_part(SPLASH_PART, &dev, &pnum, &part);//查找开机logoif(ret){printf("No partition named %s\n", SPLASH_PART);return;}else if(dev->id->type != MTD_DEV_TYPE_NAND){printf("Partition %s not a NAND device\n", SPLASH_PART);return;}off=part->offset;nand = &nand_info[dev->id->num];//read boot image headersize = 1<<19;//where the size come from????char * bmp_img = malloc(size);if(!bmp_img){    printf("not enough memory for splash image\n");    return;}ret = nand_read_offset_ret(nand, off, &size, (void *)bmp_img, &off);if(ret != 0){printf("function: %s nand read error %d\n", __FUNCTION__, ret);return;}//显示开机logo   lcd_display_logo(backlight_set,(ulong)bmp_img,size);#endif#if !(BOOT_NATIVE_LINUX)/*int good_blknum, bad_blknum;nand_block_info(nand, &good_blknum, &bad_blknum);printf("good is %d  bad is %d\n", good_blknum, bad_blknum);*/////////////////////////////////////////////////////////////////////////* recovery damaged fixnv or backupfixnv *//* FIXNV_PART */printf("Reading fixnv to 0x%08x\n", FIXNV_ADR);//try "/fixnv/fixnvchange.bin" first,if fail,//try /fixnv/fixnv.bin insteadret = load_sector_to_memory(fixnvpoint,fixnvfilename2,fixnvfilename,(unsigned char *)FIXNV_ADR,(unsigned char *)MODEM_ADR,FIXNV_SIZE + 4);if(ret == -1){//fixnvpoint's files are not correct//the "/backupfixnv/fixnv.bin" must be correct!ret = load_sector_to_memory(backupfixnvpoint,backupfixnvfilename,0,(unsigned char *)FIXNV_ADR,(unsigned char *)MODEM_ADR,//we just test if it's correct.FIXNV_SIZE + 4);if(ret ==1){//we got a right file in backupfixnvpoint,//use it to recovery fixnvpoint's files.recovery_sector(fixnvpoint,fixnvfilename,fixnvfilename2,(unsigned char *)FIXNV_ADR,FIXNV_SIZE + 4);}else{//backupfixnvpoint's files are still uncorrect.//then we can do nothing to get it right!!!!//there is an fatal error has occured.printf("\n\nfixnv and backupfixnv are all wrong!\n\n");return -1;//clear memory//memset(FIXNV_ADR, 0xff,FIXNV_SIZE + 4);}}else{//everything is right!!//we can chose to do it or not.ret = load_sector_to_memory(backupfixnvpoint,backupfixnvfilename,0,(unsigned char *)RUNTIMENV_ADR,//we just test if it's correct.(unsigned char *)MODEM_ADR,//we just test if it's correct.FIXNV_SIZE + 4);if(ret == -1){recovery_sector(backupfixnvpoint,backupfixnvfilename,0,(unsigned char *)FIXNV_ADR,FIXNV_SIZE + 4);}}//finally we check the fixnv structure,if fail,then u-boot will hung up!!!if(check_fixnv_struct(FIXNV_ADR,FIXNV_SIZE) == -1){printf("check fixnv structer error ............\r\n");return -1;}////////////////////////////////////////////////////////////////////////* PRODUCTINFO_PART */ret = load_sector_to_memory(productinfopoint,productinfofilename2,productinfofilename,(unsigned char *)PRODUCTINFO_ADR,(unsigned char *)MODEM_ADR,//we just test if it's correct.PRODUCTINFO_SIZE + 4);if(ret == -1){printf("don't need read productinfo  to 0x%08x!\n", PRODUCTINFO_ADR);}eng_phasechecktest((unsigned char *)PRODUCTINFO_ADR, SP09_MAX_PHASE_BUFF_SIZE);///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////* RUNTIMEVN_PART */ret = load_sector_to_memory(runtimenvpoint,runtimenvfilename2,runtimenvfilename,(unsigned char *)RUNTIMENV_ADR,(unsigned char *)MODEM_ADR,//we just test if it's correct.RUNTIMENV_SIZE + 4);if(ret == -1){//clear memorymemset(RUNTIMENV_ADR, 0xff,RUNTIMENV_SIZE + 4);}//array_value((unsigned char *)RUNTIMENV_ADR, RUNTIMENV_SIZE);/////////////////////////////////////////////////////////////////* DSP_PART */printf("Reading dsp to 0x%08x\n", DSP_ADR);ret = find_dev_and_part(DSP_PART, &dev, &pnum, &part);if (ret) {printf("No partition named %s\n", DSP_PART);return;} else if (dev->id->type != MTD_DEV_TYPE_NAND) {printf("Partition %s not a NAND device\n", DSP_PART);return;}off = part->offset;nand = &nand_info[dev->id->num];flash_page_size = nand->writesize;size = (DSP_SIZE + (flash_page_size - 1)) & (~(flash_page_size - 1));if(size <= 0) {printf("dsp image should not be zero\n");return;}ret = nand_read_offset_ret(nand, off, &size, (void*)DSP_ADR, &off);if(ret != 0) {printf("dsp nand read error %d\n", ret);return;}secure_check(DSP_ADR, 0, DSP_ADR + DSP_SIZE - VLR_INFO_OFF, CONFIG_SYS_NAND_U_BOOT_DST + CONFIG_SYS_NAND_U_BOOT_SIZE - KEY_INFO_SIZ - VLR_INFO_OFF);#elif defined(CONFIG_CALIBRATION_MODE_NEW)#if defined(CONFIG_SP7702) || defined(CONFIG_SP8810W)/*force dsp sleep in native 8810 verson to reduce power consumption*/ extern void DSP_ForceSleep(void);DSP_ForceSleep();printf("dsp nand read ok1 %d\n", ret);#endif    //开机校准if(poweron_by_calibration()){/* recovery damaged fixnv or backupfixnv */orginal_right = 0;memset((unsigned char *)FIXNV_ADR, 0xff, 0x20000);cmd_yaffs_mount(fixnvpoint);ret = cmd_yaffs_ls_chk(fixnvfilename);if (ret == (FIXNV_SIZE + 4)) {cmd_yaffs_mread_file(fixnvfilename, (unsigned char *)FIXNV_ADR);//should do something here}cmd_yaffs_umount(fixnvpoint);printf("Reading fixnv to 0x%08x \n", FIXNV_ADR);/* DSP_PART */printf("Reading dsp to 0x%08x\n", DSP_ADR);ret = find_dev_and_part(DSP_PART, &dev, &pnum, &part);if (ret) {        printf("No partition named %s\n", DSP_PART);        return;} else if (dev->id->type != MTD_DEV_TYPE_NAND) {        printf("Partition %s not a NAND device\n", DSP_PART);        return;}off = part->offset;nand = &nand_info[dev->id->num];flash_page_size = nand->writesize;size = (DSP_SIZE + (flash_page_size - 1)) & (~(flash_page_size - 1));if(size <= 0) {        printf("dsp image should not be zero\n");        return;}ret = nand_read_offset_ret(nand, off, &size, (void*)DSP_ADR, &off);if(ret != 0) {        printf("dsp nand read error %d\n", ret);        return;}printf("Reading firmware to 0x%08x\n", FIRMWARE_ADR);ret = find_dev_and_part(FIRMWARE_PART, &dev, &pnum, &part);if (ret) {        printf("No partition named %s\n", FIRMWARE_PART);        return;} else if (dev->id->type != MTD_DEV_TYPE_NAND) {        printf("Partition %s not a NAND device\n", FIRMWARE_PART);        return;}off = part->offset;nand = &nand_info[dev->id->num];size = (FIRMWARE_SIZE +(flash_page_size - 1)) & (~(flash_page_size - 1));if(size <= 0) {        printf("firmware image should not be zero\n");        return;}ret = nand_read_offset_ret(nand, off, &size, (void*)FIRMWARE_ADR, &off);if(ret != 0) {        printf("firmware nand read error %d\n", ret);        return;}printf("Reading vmjaluna to 0x%08x\n", VMJALUNA_ADR);ret = find_dev_and_part(VMJALUNA_PART, &dev, &pnum, &part);if (ret) {        printf("No partition named %s\n", VMJALUNA_PART);        return;} else if (dev->id->type != MTD_DEV_TYPE_NAND) {        printf("Partition %s not a NAND device\n", VMJALUNA_PART);        return;}off = part->offset;nand = &nand_info[dev->id->num];size = (VMJALUNA_SIZE +(flash_page_size - 1)) & (~(flash_page_size - 1));if(size <= 0) {        printf("modem image should not be zero\n");        return;}ret = nand_read_offset_ret(nand, off, &size, (void*)VMJALUNA_ADR, &off);if(ret != 0) {        printf("modem nand read error %d\n", ret);        return;}printf("call bootup modem in vlx_nand_boot,0x%x 0x%x\n",FIXNV_ADR, FIXNV_SIZE);bootup_modem((char *)VMJALUNA_ADR,0x3000);calibration_mode(cmdline, 10);memset(VMJALUNA_ADR,0,VMJALUNA_SIZE);memset(FIXNV_ADR,0,FIXNV_SIZE+4);memset(MODEM_ADR,0,MODEM_SIZE);memset(DSP_ADR,0,DSP_SIZE);memset(RUNTIMENV_ADR,0,RUNTIMENV_SIZE+4);}#endifset_vibrator(0);/////////////////////////////////////////////////////////////////* KERNEL_PART */printf("Reading kernel to 0x%08x\n", KERNEL_ADR);ret = find_dev_and_part(kernel_pname, &dev, &pnum, &part);if(ret){printf("No partition named %s\n", kernel_pname);        return;}else if(dev->id->type != MTD_DEV_TYPE_NAND){printf("Partition %s not a NAND device\n", kernel_pname);        return;}off=part->offset;nand = &nand_info[dev->id->num];//read boot image header    //加载内核ret = load_kernel_and_layout(nand,(unsigned int)off,(char *)raw_header,(char *) KERNEL_ADR,(char *) RAMDISK_ADR,2048,nand->writesize);if (ret != 0) {printf("ramdisk nand read error %d\n", ret);return;}#if !(BOOT_NATIVE_LINUX)/////////////////////////////////////////////////////////////////* MODEM_PART */printf("Reading modem to 0x%08x\n", MODEM_ADR);ret = find_dev_and_part(MODEM_PART, &dev, &pnum, &part);if (ret) {printf("No partition named %s\n", MODEM_PART);return;} else if (dev->id->type != MTD_DEV_TYPE_NAND) {printf("Partition %s not a NAND device\n", MODEM_PART);return;}off = part->offset;nand = &nand_info[dev->id->num];flash_page_size = nand->writesize;size = (MODEM_SIZE +(flash_page_size - 1)) & (~(flash_page_size - 1));if(size <= 0) {printf("modem image should not be zero\n");return;}ret = nand_read_offset_ret(nand, off, &size, (void*)MODEM_ADR, &off);if(ret != 0) {printf("modem nand read error %d\n", ret);return;}secure_check(MODEM_ADR, 0, MODEM_ADR + MODEM_SIZE - VLR_INFO_OFF, CONFIG_SYS_NAND_U_BOOT_DST + CONFIG_SYS_NAND_U_BOOT_SIZE - KEY_INFO_SIZ - VLR_INFO_OFF);//array_value((unsigned char *)MODEM_ADR, MODEM_SIZE);/////////////////////////////////////////////////////////////////* VMJALUNA_PART */printf("Reading vmjaluna to 0x%08x\n", VMJALUNA_ADR);ret = find_dev_and_part(VMJALUNA_PART, &dev, &pnum, &part);if (ret) {printf("No partition named %s\n", VMJALUNA_PART);return;} else if (dev->id->type != MTD_DEV_TYPE_NAND) {printf("Partition %s not a NAND device\n", VMJALUNA_PART);return;}off = part->offset;nand = &nand_info[dev->id->num];size = (VMJALUNA_SIZE +(flash_page_size - 1)) & (~(flash_page_size - 1));if(size <= 0) {printf("VMJALUNA image should not be zero\n");return;}ret = nand_read_offset_ret(nand, off, &size, (void*)VMJALUNA_ADR, &off);if(ret != 0) {printf("VMJALUNA nand read error %d\n", ret);return;}secure_check(VMJALUNA_ADR, 0, VMJALUNA_ADR + VMJALUNA_SIZE - VLR_INFO_OFF, CONFIG_SYS_NAND_U_BOOT_DST + CONFIG_SYS_NAND_U_BOOT_SIZE - KEY_INFO_SIZ - VLR_INFO_OFF);#endifcreat_cmdline(cmdline,hdr);//vlx_entry();//启动内核模块}

加载linux kernel函数

static int load_kernel_and_layout(struct mtd_info *nand,unsigned int phystart,char *header,char *kernel,char *ramdisk,unsigned int virtual_page_size,unsigned int real_page_size) {int ret = -1;boot_img_hdr *hdr = (boot_img_hdr*)header;unsigned int off = phystart;int size = real_page_size;printf("virtual_page_size : %x\n",virtual_page_size);printf("real_page_size : %x\n",real_page_size);//read boot image headerret = nand_read_offset_ret(nand, off, &size, (void *)hdr, &off);if(ret != 0){printf("function: %s nand read error %d\n", __FUNCTION__, ret);        return -1;}if(memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)){printf("bad boot image header, give up read!!!!\n");        return -1;}else{char* prev_page_addr = header;//we asume that the header takes only one page.//read kernel image prepareunsigned int used_size = 1*virtual_page_size;unsigned int spare_size = 0;unsigned int next_file_size = hdr->kernel_size;if(used_size > 0){spare_size = real_page_size - used_size;}else{spare_size = 0;}//read kernel imageprintf("file size: %x\n",hdr->kernel_size);printf("use size: %x\n",used_size);printf("spare size: %x\n",spare_size);if(spare_size) {memcpy(kernel,&prev_page_addr[used_size],spare_size);next_file_size -= spare_size;}size = (next_file_size+(real_page_size - 1)) & (~(real_page_size - 1));ret = nand_read_offset_ret(nand, off, &size, (void *)(kernel+spare_size), &off);if(ret != 0){printf("reading kernel error!\n");printf("try reading to %x\n",kernel+spare_size);}//read ramdisk image prepareprev_page_addr =  (char*)(kernel+spare_size+size-real_page_size);used_size = (next_file_size%real_page_size+virtual_page_size-1)&(~(virtual_page_size-1));if(used_size > 0){spare_size = real_page_size - used_size;}else{spare_size = 0;}next_file_size = hdr->ramdisk_size;printf("file size: %x\n",hdr->ramdisk_size);printf("use size: %x\n",used_size);printf("spare size: %x\n",spare_size);//read ramdisk imageif(spare_size){memcpy(ramdisk,&prev_page_addr[used_size],spare_size);next_file_size -= spare_size;}size = (next_file_size+(real_page_size - 1)) & (~(real_page_size - 1));ret = nand_read_offset_ret(nand, off, &size, (void *)(ramdisk+spare_size), &off);if(ret != 0){printf("reading ramdisk error!\n");printf("try reading to %x\n",ramdisk+spare_size);}}return ret;}

void vlx_entry(){void (*entry)(void) = (void*) VMJALUNA_ADR;#ifndef CONFIG_SC8810#ifndef CONFIG_TIGERMMU_InvalideICACHEALL();#endif#endif#if (defined CONFIG_SC8810) || (defined CONFIG_SC8825)MMU_DisableIDCM();#endif#ifdef REBOOT_FUNCTION_INUBOOTreboot_func();#endif#if BOOT_NATIVE_LINUXstart_linux();#elseentry();#endif}static int start_linux(){void (*theKernel)(int zero, int arch, u32 params);u32 exec_at = (u32)-1;u32 parm_at = (u32)-1;u32 machine_type;machine_type = machine_arch_type;         /* get machine type */theKernel = (void (*)(int, int, u32))KERNEL_ADR; /* set the kernel address */*(volatile u32*)0x84001000 = 'j';*(volatile u32*)0x84001000 = 'm';*(volatile u32*)0x84001000 = 'p';theKernel(0, machine_type, VLX_TAG_ADDR);    /* jump to kernel with register set */while(1);return 0;}

引导linux内核并启动。

遗留问题:

1、  传递参数到linux内核。

2、  Uboot到底做了什么?分别问那些部分?如:背光如何亮的,如何显示开机logo的。

3、  Nand flash如何启动并且初始化的?

4、  其他涉及到的模块初始化问题?

5、  Watchdog如何开始工作?

6、  总结回顾。



原创粉丝点击