Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1148599
  • 博文数量: 241
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 2279
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-27 19:53
个人简介

JustForFun

文章分类

全部博文(241)

文章存档

2023年(8)

2022年(2)

2021年(3)

2020年(30)

2019年(11)

2018年(27)

2017年(54)

2016年(83)

2015年(23)

我的朋友

分类: LINUX

2016-09-18 20:32:04

 1.uboot启动内核的代码缩减如下:(代码在uboot里)
common/main.c/mainloop函数
s = getenv ("bootcmd");
debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "");
if (bootdelay >= 0 && s && !abortboot (bootdelay))
{
        run_command (s, 0);
}
/////////////////////////////////////////////////////////////////////////////////
这是我smdk6410开发板从nandflash 第三个分区启动的参数,看看里面的bootcmd 和bootm
bootcmd=nand read 50008000 40000 400000;bootm 50008000
bootargs=noinitrd console=ttySAC0,115200 root=/dev/mtdblock2

/////////////////////////////////////////////////////////////////////////////////
2.假设bootcmd = nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0
<1> nand read.jffs2 0x30007FC0 kernel
nand read.jffs2 0x30007FC0 kernel;
从nand读出内核:从哪里读?   从kernel分区
        放到哪里去?-0x30007FC0
下面讲解什么是分区:
就是将nand划分为几个区域,一般如下:
bootloader-》params-》kernel-》root
这些分区的划分是在/include/configs/mini2440.h中写死的:
#define MTDPARTS_DEFAULT "mtdparts=nandflash0:250k@0(bootloader)," \
           "128k(params)," \
           "5m(kernel)," \
           "-(root)"
注:@0表示从0地址开始,250k的bootloader分区可能对某些uboot不够用,这里只是举例而已。
将上面的信息换算成十六进制:
#    name             大小        在nand上的起始地址    
0    bootloader     0x00040000        0x00000000
1    params        0x00020000              0x00040000       
2    kernel        0x00200000        0x00060000
3    root        0xfda00000        0x00260000
那么上面的nand read.jffs2 0x30007FC0 kernel就等价于:
nand read.jffs2 0x30007FC0 0x00060000 0x00200000
注:这里的read.jffs2并不是指定要什么特定的格式,而是用read.jffs2不需要块/页对齐,所以这个kernel的分区大小可以
随意定。
查看我的博客《linux2.6.28 MTD 内存技术设备(块设备)platform device源码分析》////////////////////////////////arch/arm/plat-s3c/include/plat/partition.h
struct mtd_partition s3c_partition_info[] = {
        {
                .name        = "Bootloader",
                .offset        = 0,
                .size        = (256*SZ_1K),
                .mask_flags    = MTD_CAP_NANDFLASH,
        },
        {
                .name        = "Kernel",
                .offset        = (256*SZ_1K),
                .size        = (4*SZ_1M) - (256*SZ_1K),
                .mask_flags    = MTD_CAP_NANDFLASH,
        },
#if defined(CONFIG_SPLIT_ROOT_FILESYSTEM)
        {
                .name        = "Rootfs",
                .offset        = (4*SZ_1M),
                .size        = (80*SZ_1M),//(48*SZ_1M),
        },
#endif
        {
                .name        = "File System",
                .offset        = MTDPART_OFS_APPEND,
                .size        = MTDPART_SIZ_FULL,
        }
};
<2> bootm 0x30007FC0     这是setenv
关键函数do_bootm()
flash上存的内核:uImage
uImage = 64字节信息头部+真正的内核
头部的定义如下:
typedef struct image_header {
    uint32_t    ih_magic;    /* Image Header Magic Number    */魔数
    uint32_t    ih_hcrc;    /* Image Header CRC Checksum    */CRC校验
    uint32_t    ih_time;    /* Image Creation Timestamp    */
    uint32_t    ih_size;    /* Image Data Size        */    镜像文件大小
    uint32_t    ih_load;    /* Data     Load  Address        */镜像加载地址  就是镜像文件到时候会被搬运到哪里存放
        //theKernel函数指针指向这个地址,也就是从uboot跳到内核的地址,* 镜像入口*/就是跳转时候的PC指针
    uint32_t    ih_ep;        /* Entry Point Address        */
    uint32_t    ih_dcrc;    /* Image Data CRC Checksum    */
    uint8_t        ih_os;        /* Operating System        */操作系统类型 linux vxwork
    uint8_t        ih_arch;    /* CPU architecture        */架构arm  MIPS
    uint8_t        ih_type;    /* Image Type            */
    uint8_t        ih_comp;    /* Compression Type        */压缩类型
    uint8_t        ih_name[IH_NMLEN];    /* Image Name        */
} image_header_t;
我们需要关心的是:
    uint32_t    ih_load;    /* Data     Load  Address        */
    uint32_t    ih_ep;        /* Entry Point Address        */
ih_load是加载地址,即内核运行时应该位于的地方  
ih_ep是入口地址,即内核的入口地址
这与uboot是类似的,uboot的加载地址是TEXT_BASE = 0x33F80000  ?????;入口地址是start.S中的_start。
其实我们把内核中nand读出来的时候是可以放在内核的任何地方的,如0x31000000,0x32000000等等,只要它不破坏uboot所占用的内存空间就可以了,如下图:
从0x33F4DF74-0x30000000(这是哪个CPU芯片的内存?)都是可以用的。
那么为什么既然设定好了加载地址和入口地址内核还能随意放呢?
那是因为uImage有一个头部!头部里有加载地址和入口地址,当我们用bootm xxx的时候,
do_bootm这个函数会先去读uImage的头部以获取该uImage的加载地址和入口地址,当发现该uImage目前所处的内存地址不等于它的加载地址时,该函数会将该uImage移动到它的
加载地址上,在代码中体现如下:
case IH_COMP_NONE::
if (load != image_start)
{
        memmove_wd ((void *)load, (void *)image_start, image_len, CHUNKSZ);
}
另外,当我们的内核正好处于头部指定的加载地址的话,那么就不用uboot的do_bootm函数来帮我们搬运内核了,这样可以节省启动时间。这就是为什么我们一般都下载uImage

0x50008000的原因了!
我们所用的内核加载地址是0x50008000,而头部的大小为64个字节,所以加载头部的64个字节后,内核正好位于0x50008040处!
此处是
#./mkimage -n //#tftp 50003000 uImage                        //uboot烧录uImage到内存50003000
//#nand erase  40000 400000
//#nand write 50003000 40000 400000  //将内存50003000开始的东西烧录到40000 nandflash地址
//#set bootcmd "nand read 50008000 40000 400000;bootm 50008000
//
#./mkimage -n 'linux-3.2.1' -A arm -O linux -T kernel -C none -a 0x50008000 -e 0x50008040 -d zImage uImage



///////////////////////////////////////////////////////////////////////////////////
common/cmd_bootm.c
ulong load_addr = CFG_LOAD_ADDR;        /* Default Load Address */

//cmd_tbl_t 是描述每一个命令的结构体
int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
///bootm 50008000命令
    ulong    iflag;
    ulong    addr;
    ulong    data, len, checksum;
    ulong  *len_ptr = NULL; /* not to make warning. by scsuh */
    uint    unc_len = CFG_BOOTM_LEN;
    int    i, verify;
    char    *name, *s;
    int    (*appl)(int, char *[]);
    image_header_t *hdr = &header;

    s = getenv ("verify");
    verify = (s && (*s == 'n')) ? 0 : 1;

    if (argc < 2) {
        addr = load_addr;
    } else {
        addr = simple_strtoul(argv[1], NULL, 16); //bootm 50001000
    }
//#define LINUX_ZIMAGE_MAGIC    0x016f2818
//(1)这是一个魔数,0x016f2818表示这个镜像是zImage,
//也就是说zImage格式的镜像中,在头部的一个固定位置存放了这个数,作为格式标记,
//如果我们拿到了一个image,去他的那个位置去取4个字节,判断它是否等于这个魔数LINUX_ZIMAGE_MAGIC。则可以知道这个镜像是不是zImage
#ifdef CONFIG_ZIMAGE_BOOT
#define LINUX_ZIMAGE_MAGIC    0x016f2818
    if (*(ulong *)(addr + 9*4) == LINUX_ZIMAGE_MAGIC) {
                ////zImage从头部开始的第37到40个字节,存的是zImage的标志的魔数
        printf("Boot with zImage\n");
            //addr == 50008000
        addr = virt_to_phys(addr);
            //virt_to_phys之后还是50008000
        hdr->ih_os = IH_OS_LINUX;
        hdr->ih_ep = ntohl(addr);
        goto after_header_check;//一下子跳了过去,中间一大段memmove的东东都不执行了。如果烧录的是zImage
    }
#endif

    SHOW_BOOT_PROGRESS (1);
    printf ("## Booting image at %08lx ...\n", addr);

    /* Copy header so we can blank CRC field for re-calculation */
#ifdef CONFIG_HAS_DATAFLASH
    if (addr_dataflash(addr)){
        read_dataflash(addr, sizeof(image_header_t), (char *)&header);
    } else
#endif
    //获得uimage 头部信息? ////读取kernel image的header
        //从镜像内存首地址读取镜像头部,为下面的分析校验做准备
    //判断魔数,一般不会出错

    memmove (&header, (char *)addr, sizeof(image_header_t));

    if (ntohl(hdr->ih_magic) != IH_MAGIC) {
        {
 ////如果是引导uImage镜像,不会进入这里
#ifdef CONFIG_IMAGE_BOOT
        printf("Boot with Image\n");
        addr = virt_to_phys(addr);
        hdr->ih_os = IH_OS_LINUX;
        hdr->ih_ep = ntohl(addr);
        hdr->ih_comp = IH_COMP_NONE;
        goto after_header_check;
#endif
        puts ("Bad Magic Number\n");
        SHOW_BOOT_PROGRESS (-1);
        return 1;
        }
    }
    SHOW_BOOT_PROGRESS (2);

    data = (ulong)&header;
    len  = sizeof(image_header_t);

    checksum = ntohl(hdr->ih_hcrc);//对镜像头做crc校验
    hdr->ih_hcrc = 0;

    if (crc32 (0, (uchar *)data, len) != checksum) {
        puts ("Bad Header Checksum\n");
        SHOW_BOOT_PROGRESS (-2);
        return 1;
    }
    SHOW_BOOT_PROGRESS (3);

#ifdef CONFIG_HAS_DATAFLASH
    if (addr_dataflash(addr)){
        len  = ntohl(hdr->ih_size) + sizeof(image_header_t);
        read_dataflash(addr, len, (char *)CFG_LOAD_ADDR);
        addr = CFG_LOAD_ADDR;
    }
#endif


    /* for multi-file images we need the data part, too */
    print_image_hdr ((image_header_t *)addr);

    data = addr + sizeof(image_header_t);//指向后面的kernel部分 也就是镜像文件uImage的zImage部分
    len  = ntohl(hdr->ih_size);////kernel的实际大小,就是编译后的大小

    if (verify) {//对镜像的数据部分做crc校验
        puts ("   Verifying Checksum ... ");
        if (crc32 (0, (uchar *)data, len) != ntohl(hdr->ih_dcrc)) {
            printf ("Bad Data CRC\n");
            SHOW_BOOT_PROGRESS (-3);
            return 1;
        }
        puts ("OK\n");
    }
    SHOW_BOOT_PROGRESS (4);

    len_ptr = (ulong *)data;

#if defined(__PPC__)
    if (hdr->ih_arch != IH_CPU_PPC)
#elif defined(__ARM__)
    if (hdr->ih_arch != IH_CPU_ARM)
#elif defined(__I386__)
    if (hdr->ih_arch != IH_CPU_I386)
#elif defined(__mips__)此处有省略
#else
# error Unknown CPU type
#endif
    {
        printf ("Unsupported Architecture 0x%x\n", hdr->ih_arch);
        SHOW_BOOT_PROGRESS (-4);
        return 1;
    }
    SHOW_BOOT_PROGRESS (5);

    switch (hdr->ih_type) {
    case IH_TYPE_STANDALONE:
        name = "Standalone Application";
        /* A second argument overwrites the load address */
        if (argc > 2) {
            hdr->ih_load = htonl(simple_strtoul(argv[2], NULL, 16));
        }
        break;
    case IH_TYPE_KERNEL:
        name = "Kernel Image";
        break;
    case IH_TYPE_MULTI:
        name = "Multi-File Image";
        len  = ntohl(len_ptr[0]);
        /* OS kernel is always the first image */
        data += 8; /* kernel_len + terminator */
        for (i=1; len_ptr[i]; ++i)
            data += 4;
        break;
    default: printf ("Wrong Image Type for %s command\n", cmdtp->name);
        SHOW_BOOT_PROGRESS (-5);
        return 1;
    }
    SHOW_BOOT_PROGRESS (6);

    /*
     * 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();

#ifdef CONFIG_AMIGAONEG3SE
    /*
     * We've possible left the caches enabled during
     * bios emulation, so turn them off again
     */
    icache_disable();
    invalidate_l1_instruction_cache();
    flush_data_cache();
    dcache_disable();
#endif
/* 最关键的地方: 搬运kernel到ih_load指定的地址上去*/
 //根据镜像的压缩类型把内核镜像解压到指定的地址,一般是mkimage时-a指定的
那个地址,-a指定的那个地址也就是存储在uImage镜像头里面的hdr->ih_load变量中,

    switch (hdr->ih_comp) {
    case IH_COMP_NONE:/// -C none   
        if(ntohl(hdr->ih_load) == addr) {
 //如果image header中指示的加载地址和bootm命令中参数2指定的地址相同,则表示不需要copy,可以就地(到
hdr->ih_ep)执行代码。
//此处是bootm 50008000;这个bootm的地址(addr)与(
uImage里的hdr->ih_load加载 地址相同) ,所以不memmove代码到ih_load加载地址
//所以hdr->ih_ep必须为50008040 = ih_load(50008000,也就是bootm命令设置的地址)+uImage头部64(0x40)字节
//#tftp 50003000 uImage                        //uboot烧录uImage到内存50003000
//#nand erase  40000 400000
//#nand write 50003000 40000 400000  //将内存50003000开始的东西烧录到40000 nandflash地址
//#set bootcmd "nand read 50008000 40000 400000;bootm 50008000
//
#./mkimage -n 'linux-3.2.1' -A arm -O linux -T kernel -C none -a 0x50008000 -e 0x50008040 -d zImage uImage
            printf ("   XIP %s ... ", name);
        } else {

//bootm地址和uImage头部的hdr->ih_load地址不同
                        //这里就是搬运的代码
//
armlinux.c  在do_bootm_linux函数 theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);    是跳到入口地址运行hdr->ih_ep
//而uImage 后面的数据(也就是zImage部分)被memmove到了加载地址
hdr->ih_load
//所以这种情况是制作镜像uImage时候入口地址等于加载地址
hdr->ih_load == hdr->ih_ep (smdk6410是50008000)
//
#set bootcmd "nand read 51000000 40000 400000;bootm 51000000" uboot 里的bootm地址不能是 hdr->ih_load (50008000)加载地址
            memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);
        }
        break;
    case IH_COMP_GZIP:
        printf ("   Uncompressing %s ... ", name);
        if (gunzip ((void *)ntohl(hdr->ih_load), unc_len,
                (uchar *)data, &len) != 0) {// 把它解压到 ih_load的位置上去
            puts ("GUNZIP ERROR - must RESET board to recover\n");
            SHOW_BOOT_PROGRESS (-6);
            do_reset (cmdtp, flag, argc, argv);
        }
        break;
#ifdef CONFIG_BZIP2
    case IH_COMP_BZIP2:
        printf ("   Uncompressing %s ... ", name);
        /*
         * If we've got less than 4 MB of malloc() space,
         * use slower decompression algorithm which requires
         * at most 2300 KB of memory.
         */
        i = BZ2_bzBuffToBuffDecompress ((char*)ntohl(hdr->ih_load),
                        &unc_len, (char *)data, len,
                        CFG_MALLOC_LEN < (4096 * 1024), 0);
        if (i != BZ_OK) {
            printf ("BUNZIP2 ERROR %d - must RESET board to recover\n", i);
            SHOW_BOOT_PROGRESS (-6);
            udelay(100000);
            do_reset (cmdtp, flag, argc, argv);
        }
        break;
#endif /* CONFIG_BZIP2 */
    default:
        if (iflag)
            enable_interrupts();
        printf ("Unimplemented compression type %d\n", hdr->ih_comp);
        SHOW_BOOT_PROGRESS (-7);
        return 1;
    }
//搬运完毕

    puts ("OK\n");
    SHOW_BOOT_PROGRESS (7);

    switch (hdr->ih_type) {
    case IH_TYPE_STANDALONE:
        if (iflag)
            enable_interrupts();

        /* load (and uncompress), but don't start if "autostart"
         * is set to "no"
         */
        if (((s = getenv("autostart")) != NULL) && (strcmp(s,"no") == 0)) {
            char buf[32];
            sprintf(buf, "%lX", len);
            setenv("filesize", buf);
            return 0;
        }
        appl = (int (*)(int, char *[]))ntohl(hdr->ih_ep);
        (*appl)(argc-1, &argv[1]);
        return 0;
    case IH_TYPE_KERNEL:
    case IH_TYPE_MULTI:
        /* handled below */
        break;
    default:
        if (iflag)
            enable_interrupts();
        printf ("Can't boot image type %d\n", hdr->ih_type);
        SHOW_BOOT_PROGRESS (-8);
        return 1;
    }
    SHOW_BOOT_PROGRESS (8);

#if defined(CONFIG_ZIMAGE_BOOT) || defined(CONFIG_IMAGE_BOOT)
after_header_check:
#endif
    switch (hdr->ih_os) {
    default:            /* handled by (original) Linux case */
    case IH_OS_LINUX:
#ifdef CONFIG_SILENT_CONSOLE
        fixup_silent_linux();
#endif
//接下来就要调用do_bootm_linux() 函数了,这里要启动kernel 
        do_bootm_linux  (cmdtp, flag, argc, argv,
                 addr, len_ptr, verify);
        break;
    case IH_OS_NETBSD:
        do_bootm_netbsd (cmdtp, flag, argc, argv,
                 addr, len_ptr, verify);
        break;


#if (CONFIG_COMMANDS & CFG_CMD_ELF)
    case IH_OS_VXWORKS:
        do_bootm_vxworks (cmdtp, flag, argc, argv,
                  addr, len_ptr, verify);
        break;
    case IH_OS_QNX:
        do_bootm_qnxelf (cmdtp, flag, argc, argv,
                  addr, len_ptr, verify);
        break;
#endif /* CFG_CMD_ELF */
    }

    SHOW_BOOT_PROGRESS (-9);
#ifdef DEBUG
    puts ("\n## Control returned to monitor - resetting...\n");
    do_reset (cmdtp, flag, argc, argv);
#endif
    return 1;
}
///////////////////////////////////////////////////////////////////////////////////////
libarm/armlinux.c
void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
             ulong addr, ulong *len_ptr, int verify)
{
    ulong len = 0, checksum;
    ulong initrd_start, initrd_end;
    ulong data;
    void (*theKernel)(int zero, int arch, uint params);
    image_header_t *hdr = &header;
    bd_t *bd = gd->bd;

#ifdef CONFIG_CMDLINE_TAG
    char *commandline = getenv ("bootargs");
#endif
 
    //uboot set参数命令行bootm 50008000;
    //打印出来发现 hdr->ih_ep = 0x800050  也就是必须ntohl之后才是50008000
    theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);   

//此跳到了内核去执行 设置入口地址为函数theKernel的地址,PC指针倒是后是入口地址,也就跳到入口地址去执行程序了。
    //打印出来发现theKernel == 0x50008000
    //设置内核入口地址(不是加载地址,加载是程序存储地址),入口地址是PC指针,倒是后程序跳到这个地址运行

    /*
     * Check if there is an initrd image 我们的启动参数里就是 noinitrd 此处不执行,参数也没有大于等于3
     */
    if (argc >= 3) {
        SHOW_BOOT_PROGRESS (9);

        addr = simple_strtoul (argv[2], NULL, 16);

        printf ("## Loading Ramdisk Image at %08lx ...\n", addr);

        /* Copy header so we can blank CRC field for re-calculation */
#ifdef CONFIG_HAS_DATAFLASH
        if (addr_dataflash (addr)) {
            read_dataflash (addr, sizeof (image_header_t),
                    (char *) &header);
        } else
#endif
            memcpy (&header, (char *) addr,
                sizeof (image_header_t));

        if (ntohl (hdr->ih_magic) != IH_MAGIC) {
            printf ("Bad Magic Number\n");
            SHOW_BOOT_PROGRESS (-10);
            do_reset (cmdtp, flag, argc, argv);
        }

        data = (ulong) & header;
        len = sizeof (image_header_t);

        checksum = ntohl (hdr->ih_hcrc);
        hdr->ih_hcrc = 0;

        if (crc32 (0, (unsigned char *) data, len) != checksum) {
            printf ("Bad Header Checksum\n");
            SHOW_BOOT_PROGRESS (-11);
            do_reset (cmdtp, flag, argc, argv);
        }

        SHOW_BOOT_PROGRESS (10);

        print_image_hdr (hdr);

        data = addr + sizeof (image_header_t);
        len = ntohl (hdr->ih_size);

#ifdef CONFIG_HAS_DATAFLASH
        if (addr_dataflash (addr)) {
            read_dataflash (data, len, (char *) CFG_LOAD_ADDR);
            data = CFG_LOAD_ADDR;
        }
#endif

        if (verify) {
            ulong csum = 0;

            printf ("   Verifying Checksum ... ");
            csum = crc32 (0, (unsigned char *) data, len);
            if (csum != ntohl (hdr->ih_dcrc)) {
                printf ("Bad Data CRC\n");
                SHOW_BOOT_PROGRESS (-12);
                do_reset (cmdtp, flag, argc, argv);
            }
            printf ("OK\n");
        }

        SHOW_BOOT_PROGRESS (11);

        if ((hdr->ih_os != IH_OS_LINUX) ||
            (hdr->ih_arch != IH_CPU_ARM) ||
            (hdr->ih_type != IH_TYPE_RAMDISK)) {
            printf ("No Linux ARM Ramdisk Image\n");
            SHOW_BOOT_PROGRESS (-13);
            do_reset (cmdtp, flag, argc, argv);
        }

#if defined(CONFIG_B2) || defined(CONFIG_EVB4510) || defined(CONFIG_ARMADILLO)
        /*
         *we need to copy the ramdisk to SRAM to let Linux boot
         */
//与上文的memcpy (&header, (char *) addr,    sizeof (image_header_t));区别??
        memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);
        data = ntohl(hdr->ih_load);
#endif /* CONFIG_B2 || CONFIG_EVB4510 */

        /*
         * Now check if we have a multifile image
         */
    } else if ((hdr->ih_type == IH_TYPE_MULTI) && (len_ptr[1])) {
        ulong tail = ntohl (len_ptr[0]) % 4;
        int i;

        SHOW_BOOT_PROGRESS (13);

        /* skip kernel length and terminator */
        data = (ulong) (&len_ptr[2]);
        /* skip any additional image length fields */
        for (i = 1; len_ptr[i]; ++i)
            data += 4;
        /* add kernel length, and align */
        data += ntohl (len_ptr[0]);
        if (tail) {
            data += 4 - tail;
        }

        len = ntohl (len_ptr[1]);

    } else {
        /*
         * no initrd image
         */
        SHOW_BOOT_PROGRESS (14);

        len = data = 0;
    }

#ifdef    DEBUG
    if (!data) {
        printf ("No initrd\n");
    }
#endif

    if (data) {
        initrd_start = data;
        initrd_end = initrd_start + len;
    } else {
        initrd_start = 0;
        initrd_end = 0;
    }

    SHOW_BOOT_PROGRESS (15);

    debug ("## Transferring control to Linux (at address %08lx) ...\n",
           (ulong) theKernel);

#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_TAG
    setup_serial_tag (?ms);
#endif
#ifdef CONFIG_REVISION_TAG
    setup_revision_tag (?ms);
#endif
#ifdef CONFIG_SETUP_MEMORY_TAGS
    setup_memory_tags (bd);
#endif
#ifdef CONFIG_CMDLINE_TAG
    setup_commandline_tag (bd, commandline);//设置启动命令行tags
#endif
#ifdef CONFIG_INITRD_TAG
    if (initrd_start && initrd_end)
        setup_initrd_tag (bd, initrd_start, initrd_end);
#endif
#if defined (CONFIG_VFD) || defined (CONFIG_LCD)
    setup_videolfb_tag ((gd_t *) gd);
#endif
    setup_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 ();
//传递的参数
//R0必须为0 ????
//R1:机器类型ID ,本机为ARM(bd-> bi_arch_number)
//R2:启动参数列表在内存中的位置(bd-> bi_boot_params)
         theKernel (0, bd->bi_arch_number, bd->bi_boot_params);
//<嵌入式linux应用开发>P264 bd->bi_boot_params就是标记列表的开始地址。

    theKernel (0, bd->bi_arch_number, bd->bi_boot_params);
}



阅读(1226) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~