记录自己学习android系统启动以及 recovery过程(1)----------uboot

来源:互联网 发布:体脂秤什么牌子好 知乎 编辑:程序博客网 时间:2024/06/05 18:32

记录自己学习android系统启动以及 recovery过程(1)----------uboot

欢迎指出其中错误。

启动uboot bootm文件作为uboot->kernel的最后一个步骤,负责引导内核,并配置需要传递进内核的相关参数

在uboot启动后,会检查是否需要recovery,一般通过两个途径, 1.挂载boot device,并查看/cache/recovery文件,2.按键检测,当需要进行recovery时,会重新设置启动的环境变量。

system image和recovery的环境变量主要区别在于:

system :   bootm (kernel_addr)  (ramdisk_addr)

recovery:   bootm或者bootm (kernel_addr)   root=/dev/mmcblk0px

uboot阶段通过对bootm代码的执行,来设置传递进内核的参数,通知内核是挂载recovery 还是运行system。

相关代码分析:

1. do_bootm函数

int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){    ulong        iflag;    ulong        load_end = 0;    int        ret;    boot_os_fn    *boot_fn;    /* relocate boot function table */       /*重定位 boot_os内部函数指针地址,启动包含do_bootm_linux。因为在uboot启动的最初阶段,会对uboot的text,data,bss..进行一次搬移*/    if (!relocated) {        int i;        for (i = 0; i < ARRAY_SIZE(boot_os); i++)            if (boot_os[i] != NULL)                boot_os[i] += gd->reloc_off;        relocated = 1;    }    /* determine if we have a sub command */    /* 当传进来参数多于一个时,判断参数类型,并执行。在android正常启动模式下,参数模式是 bootm kernel_addr rd_addr,多于3个,但是参数endp是0,不会return*/    if (argc > 1) {        char *endp;        simple_strtoul(argv[1], &endp, 16);        /* endp pointing to NULL means that argv[1] was just a         * valid number, pass it along to the normal bootm processing         *         * If endp is ':' or '#' assume a FIT identifier so pass         * along for normal processing.         *         * Right now we assume the first arg should never be '-'         */        if ((*endp != 0) && (*endp != ':') && (*endp != '#'))            return do_bootm_subcommand(cmdtp, flag, argc, argv);    }    /* do_bootm重要函数,主要用来查看,验证 uImage, ramdisk,并初始化一个结构体images,类型为bootm_headers_t,后续会详细解析*/    if (bootm_start(cmdtp, flag, argc, argv))        return 1;    /*     * We have reached the point of no return: we are going to     * overwrite all exception vector code, so we cannot easily     * recover from any failures any more...     */    iflag = disable_interrupts();#if defined(CONFIG_CMD_USB)    /*     * turn off USB to prevent the host controller from writing to the     * SDRAM while Linux is booting. This could happen (at least for OHCI     * controller), because the HCCA (Host Controller Communication Area)     * lies within the SDRAM and the host controller writes continously to     * this area (as busmaster!). The HccaFrameNumber is for example     * updated every 1 ms within the HCCA structure in SDRAM! For more     * details see the OpenHCI specification.     */    usb_stop();#endif#ifdef CONFIG_AMIGAONEG3SE    /*     * We've possible left the caches enabled during     * bios emulation, so turn them off again     */    icache_disable();    dcache_disable();#endif    /*下面函数,是用来将kernel的uImage 解压并拷贝到指定的运行地址*/    ret = bootm_load_os(images.os, &load_end, 1);    if (ret < 0) {        if (ret == BOOTM_ERR_RESET)            do_reset (cmdtp, flag, argc, argv);        if (ret == BOOTM_ERR_OVERLAP) {            if (images.legacy_hdr_valid) {                if (image_get_type (&images.legacy_hdr_os_copy) == IH_TYPE_MULTI)                    puts ("WARNING: legacy format multi component "                        "image overwritten\n");            } else {                puts ("ERROR: new format image overwritten - "                    "must RESET the board to recover\n");                show_boot_progress (-113);                do_reset (cmdtp, flag, argc, argv);            }        }        if (ret == BOOTM_ERR_UNIMPLEMENTED) {            if (iflag)                enable_interrupts();            show_boot_progress (-7);            return 1;        }    }    lmb_reserve(&images.lmb, images.os.load, (load_end - images.os.load));    if (images.os.type == IH_TYPE_STANDALONE) {        if (iflag)            enable_interrupts();        /* This may return when 'autostart' is 'no' */        bootm_start_standalone(iflag, argc, argv);        return 0;    }    show_boot_progress (8);#ifdef CONFIG_SILENT_CONSOLE    if (images.os.os == IH_OS_LINUX)        fixup_silent_linux();#endif    /*image.os.os在bootm_start函数中被初始化,此处,boot_fn就等于do_bootm_linux*/    boot_fn = boot_os[images.os.os];    if (boot_fn == NULL) {        if (iflag)            enable_interrupts();        printf ("ERROR: booting os '%s' (%d) is not supported\n",            genimg_get_os_name(images.os.os), images.os.os);        show_boot_progress (-8);        return 1;    }    /*调用do_bootm_linux引导内核并启动*/    boot_fn(0, argc, argv, &images);    show_boot_progress (-9);#ifdef DEBUG    puts ("\n## Control returned to monitor - resetting...\n");#endif    do_reset (cmdtp, flag, argc, argv);    return 1;}

各个大体部分的解释如上,在do_bootm函数中,需要详细看的函数有

       bootm_start-------相关结构体初始化

       bootm_load_os--------解压

       do_bootm_linux---------引导内核启动

2. bootm_start

首先看bootm_hearders_t结构体

/* * Legacy and FIT format headers used by do_bootm() and do_bootm_<os>() * routines. */typedef struct bootm_headers {/* * Legacy os image header, if it is a multi component image * then boot_get_ramdisk() and get_fdt() will attempt to get * data from second and third component accordingly. */image_header_t*legacy_hdr_os;/* image header pointer */image_header_tlegacy_hdr_os_copy;/* header copy */ulonglegacy_hdr_valid;#if defined(CONFIG_FIT)const char*fit_uname_cfg;/* configuration node unit name */void*fit_hdr_os;/* os FIT image header */const char*fit_uname_os;/* os subimage node unit name */intfit_noffset_os;/* os subimage node offset */void*fit_hdr_rd;/* init ramdisk FIT image header */const char*fit_uname_rd;/* init ramdisk subimage node unit name */intfit_noffset_rd;/* init ramdisk subimage node offset */#if defined(CONFIG_PPC)void*fit_hdr_fdt;/* FDT blob FIT image header */const char*fit_uname_fdt;/* FDT blob subimage node unit name */intfit_noffset_fdt;/* FDT blob subimage node offset */#endif#endif#ifndef USE_HOSTCC                      /*需要认真查看如何完成这个宏定义包含的部分*/image_info_tos;/* os image info */               /*linux image 相关*/ulongep;/* entry point of OS */           /* 解压后,指向image入口*/ulongrd_start, rd_end;/* ramdisk start/end */          /* ramdisk,用来引导systemimage,当为0时,引导recovery,kernel里有实现方法,会另写*/#ifdef CONFIG_OF_LIBFDTchar*ft_addr;/* flat dev tree address */#endifulongft_len;/* length of flat device tree */ulonginitrd_start;                      ulonginitrd_end;ulongcmdline_start;                     /*command line 相关*/ulongcmdline_end;bd_t*kbd;#endifintverify;/* getenv("verify")[0] != 'n' */#defineBOOTM_STATE_START(0x00000001)#defineBOOTM_STATE_LOADOS(0x00000002)#defineBOOTM_STATE_RAMDISK(0x00000004)#defineBOOTM_STATE_FDT(0x00000008)#defineBOOTM_STATE_OS_CMDLINE(0x00000010)#defineBOOTM_STATE_OS_BD_T(0x00000020)#defineBOOTM_STATE_OS_PREP(0x00000040)#defineBOOTM_STATE_OS_GO(0x00000080)intstate;#ifndef USE_HOSTCCstruct lmblmb;/* for memory mgmt */#endif} bootm_headers_t;
主要需要注意ifndef USE_HOSTCC宏内部结构体或变量的初始化过程,关系到内核的加载以及ramdisk的引导

image_header结构体

typedef struct image_header {uint32_tih_magic;/* Image Header Magic Number*/uint32_tih_hcrc;/* Image Header CRC Checksum*/uint32_tih_time;/* Image Creation Timestamp*/uint32_tih_size;/* Image Data Size*/uint32_tih_load;/* Data Load  Address*/uint32_tih_ep;/* Entry Point Address*/uint32_tih_dcrc;/* Image Data CRC Checksum*/uint8_tih_os;/* Operating System*/uint8_tih_arch;/* CPU architecture*/uint8_tih_type;/* Image Type*/uint8_tih_comp;/* Compression Type*/uint8_tih_name[IH_NMLEN];/* Image Name*/} image_header_t;

bootm_start函数如下:

static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){ulongmem_start;phys_size_tmem_size;void*os_hdr;intret;memset ((void *)&images, 0, sizeof (images));images.verify = getenv_yesno ("verify");        /*lmb相关代码,后续研究,暂时也搞不懂到底干啥以及用来干啥的*/lmb_init(&images.lmb);mem_start = getenv_bootm_low();mem_size = getenv_bootm_size();lmb_add(&images.lmb, (phys_addr_t)mem_start, mem_size);arch_lmb_reserve(&images.lmb);board_lmb_reserve(&images.lmb);        /* 重要函数,获取内核uImage信息,返回uImage头,并初始化image_start,image_len,以及images内部相关参数*//* get kernel image header, start address and length */os_hdr = boot_get_kernel (cmdtp, flag, argc, argv,&images, &images.os.image_start, &images.os.image_len);if (images.os.image_len == 0) {puts ("ERROR: can't get kernel image!\n");return 1;}/* get image parameters */switch (genimg_get_format (os_hdr)) {case IMAGE_FORMAT_LEGACY:images.os.type = image_get_type (os_hdr);               /*初始化bootm_headers_t结构体images.os内部参数,在打包image至uImage时,设置的*/images.os.comp = image_get_comp (os_hdr);images.os.os = image_get_os (os_hdr);images.os.end = image_get_image_end (os_hdr);images.os.load = image_get_load (os_hdr);break;#if defined(CONFIG_FIT)case IMAGE_FORMAT_FIT:if (fit_image_get_type (images.fit_hdr_os,images.fit_noffset_os, &images.os.type)) {puts ("Can't get image type!\n");show_boot_progress (-109);return 1;}if (fit_image_get_comp (images.fit_hdr_os,images.fit_noffset_os, &images.os.comp)) {puts ("Can't get image compression!\n");show_boot_progress (-110);return 1;}if (fit_image_get_os (images.fit_hdr_os,images.fit_noffset_os, &images.os.os)) {puts ("Can't get image OS!\n");show_boot_progress (-111);return 1;}images.os.end = fit_get_end (images.fit_hdr_os);if (fit_image_get_load (images.fit_hdr_os, images.fit_noffset_os,&images.os.load)) {puts ("Can't get image load address!\n");show_boot_progress (-112);return 1;}break;#endifdefault:puts ("ERROR: unknown image format type!\n");return 1;}/* find kernel entry point */                       /* 获取enter point*/if (images.legacy_hdr_valid) {images.ep = image_get_ep (&images.legacy_hdr_os_copy);#if defined(CONFIG_FIT)} else if (images.fit_uname_os) {ret = fit_image_get_entry (images.fit_hdr_os,images.fit_noffset_os, &images.ep);if (ret) {puts ("Can't get entry point property!\n");return 1;}#endif} else {puts ("Could not find kernel entry point!\n");return 1;}if (images.os.os == IH_OS_LINUX) {/* find ramdisk */                /*当是linux类型时,会查找ramdisk,当ramdisk存在时,rd_start,rd_end为实际值,否则为0,在kernel中,会判断这两个值,用来确认挂载root*/                ret = boot_get_ramdisk (argc, argv, &images, IH_INITRD_ARCH,&images.rd_start, &images.rd_end);if (ret) {puts ("Ramdisk image is corrupt or invalid\n");return 1;}#if defined(CONFIG_OF_LIBFDT)#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_SPARC)/* find flattened device tree */ret = boot_get_fdt (flag, argc, argv, &images,    &images.ft_addr, &images.ft_len);if (ret) {puts ("Could not find a valid device tree\n");return 1;}set_working_fdt_addr(images.ft_addr);#endif#endif}images.os.start = (ulong)os_hdr;images.state = BOOTM_STATE_START;return 0;}
在这个bootm_start函数中,主要是boot_get_kernel和boot_get_ramdisk两个函数,用来校验并完成image结构体的初始化。

boot_get_kernel

static void *boot_get_kernel (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],bootm_headers_t *images, ulong *os_data, ulong *os_len){image_header_t*hdr;ulongimg_addr;#if defined(CONFIG_FIT)void*fit_hdr;const char*fit_uname_config = NULL;const char*fit_uname_kernel = NULL;const void*data;size_tlen;intcfg_noffset;intos_noffset;#endif/* find out kernel image address */if (argc < 2) {                /*当小于2时,使用默认的addr配置*/                img_addr = load_addr;debug ("*  kernel: default image load address = 0x%08lx\n",load_addr);#if defined(CONFIG_FIT)} else if (fit_parse_conf (argv[1], load_addr, &img_addr,&fit_uname_config)) {debug ("*  kernel: config '%s' from image at 0x%08lx\n",fit_uname_config, img_addr);} else if (fit_parse_subimage (argv[1], load_addr, &img_addr,&fit_uname_kernel)) {debug ("*  kernel: subimage '%s' from image at 0x%08lx\n",fit_uname_kernel, img_addr);#endif} else {                /*使用传递进来的image_addr进行初始化*/                img_addr = simple_strtoul(argv[1], NULL, 16);debug ("*  kernel: cmdline image address = 0x%08lx\n", img_addr);}show_boot_progress (1);/* copy from dataflash if needed */        /*genimg_get_image是判断镜像是否存在于特殊的存储设备中,是否需要读取至指定内存位置,不管需不需要,在这步完成后,内存img_addr就存在了内核镜像,并在后面对其进行解压缩等*/        img_addr = genimg_get_image (img_addr);/* check image type, for FIT images get FIT kernel node */*os_data = *os_len = 0;switch (genimg_get_format ((void *)img_addr)) {case IMAGE_FORMAT_LEGACY:printf ("## Booting kernel from Legacy Image at %08lx ...\n",img_addr);                /*验证image的CRC校验,并返回image头部*/                hdr = image_get_kernel (img_addr, images->verify);if (!hdr)return NULL;show_boot_progress (5);/* get os_data and os_len */switch (image_get_type (hdr)) {case IH_TYPE_KERNEL:                        /*设置image中,除去头部分,真实kernel data的起始地址,以及长度*/                        *os_data = image_get_data (hdr);*os_len = image_get_data_size (hdr);break;case IH_TYPE_MULTI:image_multi_getimg (hdr, 0, os_data, os_len);break;case IH_TYPE_STANDALONE:if (argc >2) {hdr->ih_load = htonl(simple_strtoul(argv[2], NULL, 16));}*os_data = image_get_data (hdr);*os_len = image_get_data_size (hdr);break;default:printf ("Wrong Image Type for %s command\n", cmdtp->name);show_boot_progress (-5);return NULL;}/* * copy image header to allow for image overwrites during kernel * decompression. */memmove (&images->legacy_hdr_os_copy, hdr, sizeof(image_header_t));/* save pointer to image header */images->legacy_hdr_os = hdr;images->legacy_hdr_valid = 1;show_boot_progress (6);break;#if defined(CONFIG_FIT)case IMAGE_FORMAT_FIT:fit_hdr = (void *)img_addr;printf ("## Booting kernel from FIT Image at %08lx ...\n",img_addr);if (!fit_check_format (fit_hdr)) {puts ("Bad FIT kernel image format!\n");show_boot_progress (-100);return NULL;}show_boot_progress (100);if (!fit_uname_kernel) {/* * no kernel image node unit name, try to get config * node first. If config unit node name is NULL * fit_conf_get_node() will try to find default config node */show_boot_progress (101);cfg_noffset = fit_conf_get_node (fit_hdr, fit_uname_config);if (cfg_noffset < 0) {show_boot_progress (-101);return NULL;}/* save configuration uname provided in the first * bootm argument */images->fit_uname_cfg = fdt_get_name (fit_hdr, cfg_noffset, NULL);printf ("   Using '%s' configuration\n", images->fit_uname_cfg);show_boot_progress (103);os_noffset = fit_conf_get_kernel_node (fit_hdr, cfg_noffset);fit_uname_kernel = fit_get_name (fit_hdr, os_noffset, NULL);} else {/* get kernel component image node offset */show_boot_progress (102);os_noffset = fit_image_get_node (fit_hdr, fit_uname_kernel);}if (os_noffset < 0) {show_boot_progress (-103);return NULL;}printf ("   Trying '%s' kernel subimage\n", fit_uname_kernel);show_boot_progress (104);if (!fit_check_kernel (fit_hdr, os_noffset, images->verify))return NULL;/* get kernel image data address and length */if (fit_image_get_data (fit_hdr, os_noffset, &data, &len)) {puts ("Could not find kernel subimage data!\n");show_boot_progress (-107);return NULL;}show_boot_progress (108);*os_len = len;*os_data = (ulong)data;images->fit_hdr_os = fit_hdr;images->fit_uname_os = fit_uname_kernel;images->fit_noffset_os = os_noffset;break;#endifdefault:printf ("Wrong Image Format for %s command\n", cmdtp->name);show_boot_progress (-108);return NULL;}debug ("   kernel data at 0x%08lx, len = 0x%08lx (%ld)\n",*os_data, *os_len, *os_len);return (void *)img_addr;}
在boot_get_kernel函数中,会涉及kernel image的校验,并对os_data,os_len进行初始化,并返回image header,用作后续操作。

boot_get_ramdisk
此函数与boot_get_kernel类似,校验并初始化rd_start,rd_end,最终这两个参数会被传递到linux内核,挂载root目录用。

因为在正常启动模式下,传进的参数是bootm (kernel_addr) (rd_addr) 因此,boot_get_kernel可以通过addr得到kernel和rd的image,并对他们的文件头部分进行分析,初始化相关变量,初始化rd_start,rd_end后,kernel会对这两个参数进行分析,并挂载相应的root目录,并执行相应的init进程。

当在recovery模式下,传递进的参数是bootm (kernel_addr)或者是bootm,没有kernel_addr模式下,会使用环境变量默认的值,进行image配置。但ramdisk的没有默认值,image也是找不到的,所以被初始化为0。此时root的挂载就会走到另外一种模式,通过传递的commandline中加入 root=/dev/mmcblk0px时,kernel会对这个cmd进行分析,并挂载,后续kernel会继续讨论。

这两种初始化rd的模式,是kernel两种常规配置的模式

3.boot_load_os

static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress){uint8_t comp = os.comp;ulong load = os.load;ulong blob_start = os.start;ulong blob_end = os.end;ulong image_start = os.image_start;ulong image_len = os.image_len;uint unc_len = CONFIG_SYS_BOOTM_LEN;const char *type_name = genimg_get_type_name (os.type);        /*通过image头配置情况,查看压缩与否以及压缩的模式,并解压或者搬移至enter point,ep的初始化在boot_get_kernel中设置的*/switch (comp) {case IH_COMP_NONE:if (load == blob_start) {printf ("   XIP %s ... ", type_name);} else {printf ("   Loading %s ... ", type_name);if (load != image_start) {memmove_wd ((void *)load,(void *)image_start, image_len, CHUNKSZ);}}*load_end = load + image_len;puts("OK\n");break;case IH_COMP_GZIP:printf ("   Uncompressing %s ... ", type_name);if (gunzip ((void *)load, unc_len,(uchar *)image_start, &image_len) != 0) {puts ("GUNZIP: uncompress, out-of-mem or overwrite error ""- must RESET board to recover\n");if (boot_progress)show_boot_progress (-6);return BOOTM_ERR_RESET;}*load_end = load + image_len;break;#ifdef CONFIG_BZIP2case IH_COMP_BZIP2:printf ("   Uncompressing %s ... ", type_name);/* * If we've got less than 4 MB of malloc() space, * use slower decompression algorithm which requires * at most 2300 KB of memory. */int i = BZ2_bzBuffToBuffDecompress ((char*)load,&unc_len, (char *)image_start, image_len,CONFIG_SYS_MALLOC_LEN < (4096 * 1024), 0);if (i != BZ_OK) {printf ("BUNZIP2: uncompress or overwrite error %d ""- must RESET board to recover\n", i);if (boot_progress)show_boot_progress (-6);return BOOTM_ERR_RESET;}*load_end = load + unc_len;break;#endif /* CONFIG_BZIP2 */#ifdef CONFIG_LZMAcase IH_COMP_LZMA:printf ("   Uncompressing %s ... ", type_name);int ret = lzmaBuffToBuffDecompress((unsigned char *)load, &unc_len,(unsigned char *)image_start, image_len);if (ret != SZ_OK) {printf ("LZMA: uncompress or overwrite error %d ""- must RESET board to recover\n", ret);show_boot_progress (-6);return BOOTM_ERR_RESET;}*load_end = load + unc_len;break;#endif /* CONFIG_LZMA */default:printf ("Unimplemented compression type %d\n", comp);return BOOTM_ERR_UNIMPLEMENTED;}puts ("OK\n");debug ("   kernel loaded at 0x%08lx, end = 0x%08lx\n", load, *load_end);if (boot_progress)show_boot_progress (7);if ((load < blob_end) && (*load_end > blob_start)) {debug ("images.os.start = 0x%lX, images.os.end = 0x%lx\n", blob_start, blob_end);debug ("images.os.load = 0x%lx, load_end = 0x%lx\n", load, *load_end);return BOOTM_ERR_OVERLAP;}return 0;}
boot_load_os函数功能以及流程都比较清晰。

4.do_bootm_linux

在do_bootm中,函数指针被赋值为boot_fn = boot_os[images.os.os];

images.os.os赋值在bootm_get_kernel中,并被设置为IH_OS_LINUX,

boot_os结构体为:

boot_os_fn * boot_os[] = {#ifdef CONFIG_BOOTM_LINUX[IH_OS_LINUX] = do_bootm_linux,          /*需要的函数*/#endif#ifdef CONFIG_BOOTM_NETBSD[IH_OS_NETBSD] = do_bootm_netbsd,#endif#ifdef CONFIG_LYNXKDI[IH_OS_LYNXOS] = do_bootm_lynxkdi,#endif#ifdef CONFIG_BOOTM_RTEMS[IH_OS_RTEMS] = do_bootm_rtems,#endif#if defined(CONFIG_CMD_ELF)[IH_OS_VXWORKS] = do_bootm_vxworks,[IH_OS_QNX] = do_bootm_qnxelf,#endif#ifdef CONFIG_INTEGRITY[IH_OS_INTEGRITY] = do_bootm_integrity,#endif};
do_boot_linux函数为:

int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images){bd_t*bd = gd->bd;char*s;intmachid = bd->bi_arch_number;void(*theKernel)(int zero, int arch, uint params);#ifdef CONFIG_CMDLINE_TAG/* add core board serial number temp solution*/char commandline[256] ;memset(commandline , 0, sizeof(commandline));strcat(commandline,getenv ("bootargs"));strcat(commandline,get_inand_cid_psn());printf("COMMANDLINE:%s\n",commandline);#endifif ((flag != 0) && (flag != BOOTM_STATE_OS_GO))return 1;        /*将函数的指针指向kernel起始地址,这样,运行这个函数指针,就相当于执行kernel了*/theKernel = (void (*)(int, int, uint))images->ep;s = getenv ("machid");if (s) {machid = simple_strtoul (s, NULL, 16);printf ("Using machid 0x%x from environment\n", machid);}show_boot_progress (15);debug ("## Transferring control to Linux (at address %08lx) ...\n",       (ulong) theKernel);/*下面是配置需要传递到kernel的参数,其中跟启动相关的主要有两个,一个command_line,一个就是刚才的rd_start,rd_end*/#if defined (CONFIG_SETUP_MEMORY_TAGS) || \    defined (CONFIG_CMDLINE_TAG) || \    defined (CONFIG_INITRD_TAG) || \    defined (CONFIG_SERIAL_TAG) || \    defined (CONFIG_REVISION_TAG) || \    defined (CONFIG_LCD) || \    defined (CONFIG_VFD)setup_start_tag (bd);#ifdef CONFIG_SERIAL_TAGsetup_serial_tag (¶ms);#endif#ifdef CONFIG_REVISION_TAGsetup_revision_tag (¶ms);#endif#ifdef CONFIG_SETUP_MEMORY_TAGSsetup_memory_tags (bd);#endif#ifdef CONFIG_CMDLINE_TAG        setup_commandline_tag (bd, commandline);         /*配置commandline*/#endif#ifdef CONFIG_INITRD_TAGif (images->rd_start && images->rd_end)setup_initrd_tag (bd, images->rd_start, images->rd_end);         /*配置initrd相关的,但是当rd_start,rd_end为0时,值为0*/#endif#if defined (CONFIG_VFD) || defined (CONFIG_LCD)setup_videolfb_tag ((gd_t *) gd);#endifsetup_end_tag (bd);#endif/* we assume that the kernel is in place */printf ("\nStarting kernel ...\n\n");#ifdef CONFIG_USB_DEVICE{extern void udc_disconnect (void);udc_disconnect ();}#endif        cleanup_before_linux ();        /*运行kernel,像所说的,never return*/theKernel (0, machid, bd->bi_boot_params);/* does not return */return 1;}
一般配置参数的做法,可以参考上面的两种方法,在内核中解析,并在启动阶段做你想做的。。。。

如上所述:

1. 在uboot阶段,通过对是否需要运行recovery的检测,来设置不同的环境变量

2. 通过对环境变量的执行,加载kernel(ramdisk),并进行校验,检测,解压等操作,搬移到相应的位置

3.对ramdisk的操作,初始化rd_start,rd_end,并传递进内核,这样,内核就可以通过这两个参数,来决定是否存在ramdisk,如存在,就挂载并运行,入不存在,则检测是否传递进commandline中有root=字样,分析并挂载运行。

这样,recovery以及android system启动的模式,相同点与不同点,大致如此。

kernel阶段另行研究

原创粉丝点击