uboot启动内核的实现
来源:互联网 发布:简单 三维建模软件 编辑:程序博客网 时间:2024/06/01 10:40
- cmd_tbl_t *find_cmd (const char *cmd)
- {
- int len = &__u_boot_cmd_end - &__u_boot_cmd_start;
- return find_cmd_tbl(cmd, &__u_boot_cmd_start, len);
- }
- cmd_tbl_t *find_cmd (const char *cmd)
- {
- int len = &__u_boot_cmd_end - &__u_boot_cmd_start;
- return find_cmd_tbl(cmd, &__u_boot_cmd_start, len);
- }
//是uboot所有命令的结构体的一个列表的起始地址和结束地址。
- /***************************************************************************
- * find command table entry for a command
- */
- cmd_tbl_t *find_cmd_tbl (const char *cmd, cmd_tbl_t *table, int table_len)
- {
- cmd_tbl_t *cmdtp;
- cmd_tbl_t *cmdtp_temp = table; /*Init value */
- const char *p;
- int len;
- int n_found = 0;
- /*
- * Some commands allow length modifiers (like "cp.b");
- * compare command name only until first dot.
- */
- len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd);
- //从首地址开始逐条往下查找,看能否找到相应的命令,如果找到就返回相应命令的结构体指针,找不到就返回NULL
- for (cmdtp = table;
- cmdtp != table + table_len;
- cmdtp++) {
- if (strncmp (cmd, cmdtp->name, len) == 0) {
- if (len == strlen (cmdtp->name))
- return cmdtp; /* full match */
- cmdtp_temp = cmdtp; /* abbreviated command ? */
- n_found++;
- }
- }
- if (n_found == 1) { /* exactly one match */
- return cmdtp_temp;
- }
- return NULL; /* not found or ambiguous command */
- }
- /***************************************************************************
- * find command table entry for a command
- */
- cmd_tbl_t *find_cmd_tbl (const char *cmd, cmd_tbl_t *table, int table_len)
- {
- cmd_tbl_t *cmdtp;
- cmd_tbl_t *cmdtp_temp = table; /*Init value */
- const char *p;
- int len;
- int n_found = 0;
- /*
- * Some commands allow length modifiers (like "cp.b");
- * compare command name only until first dot.
- */
- len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd);
- //从首地址开始逐条往下查找,看能否找到相应的命令,如果找到就返回相应命令的结构体指针,找不到就返回NULL
- for (cmdtp = table;
- cmdtp != table + table_len;
- cmdtp++) {
- if (strncmp (cmd, cmdtp->name, len) == 0) {
- if (len == strlen (cmdtp->name))
- return cmdtp; /* full match */
- cmdtp_temp = cmdtp; /* abbreviated command ? */
- n_found++;
- }
- }
- if (n_found == 1) { /* exactly one match */
- return cmdtp_temp;
- }
- return NULL; /* not found or ambiguous command */
- }
- /* found - check max args */
- //检测最大参数个数
- if (argc > cmdtp->maxargs) {
- cmd_usage(cmdtp);
- rc = -1;
- continue;
- }
- #if defined(CONFIG_CMD_BOOTD)
- /* avoid "bootd" recursion */
- if (cmdtp->cmd == do_bootd) {
- #ifdef DEBUG_PARSER
- printf ("[%s]\n", finaltoken);
- #endif
- if (flag & CMD_FLAG_BOOTD) {
- puts ("'bootd' recursion detected\n");
- rc = -1;
- continue;
- } else {
- flag |= CMD_FLAG_BOOTD;
- }
- }
- #endif
- /* OK - call function to do the command */
- if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {//执行命令处理函数
- rc = -1;
- }
- repeatable &= cmdtp->repeatable;
- /* Did the user stop this? */
- //处理用户输入的ctrl+c
- if (had_ctrlc ())
- return -1; /* if stopped then not repeatable */
- }
- return rc ? rc : repeatable;
- }
- /* found - check max args */
- //检测最大参数个数
- if (argc > cmdtp->maxargs) {
- cmd_usage(cmdtp);
- rc = -1;
- continue;
- }
- #if defined(CONFIG_CMD_BOOTD)
- /* avoid "bootd" recursion */
- if (cmdtp->cmd == do_bootd) {
- #ifdef DEBUG_PARSER
- printf ("[%s]\n", finaltoken);
- #endif
- if (flag & CMD_FLAG_BOOTD) {
- puts ("'bootd' recursion detected\n");
- rc = -1;
- continue;
- } else {
- flag |= CMD_FLAG_BOOTD;
- }
- }
- #endif
- /* OK - call function to do the command */
- if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {//执行命令处理函数
- rc = -1;
- }
- repeatable &= cmdtp->repeatable;
- /* Did the user stop this? */
- //处理用户输入的ctrl+c
- if (had_ctrlc ())
- return -1; /* if stopped then not repeatable */
- }
- return rc ? rc : repeatable;
- }
cmd_tbl_t *cmdtp;
- struct cmd_tbl_s {
- char *name; /* Command Name命令名称 */
- int maxargs; /* maximum number of arguments 最大参数个数*/
- int repeatable; /* autorepeat allowed? 是否允许重复输入 */
- /* Implementation function */
- int (*cmd)(struct cmd_tbl_s *, int, int, char *[]);//命令处理函数
- char *usage; /* Usage message(short) 比较短的帮助信息*/
- #ifdef CONFIG_SYS_LONGHELP
- char *help; /* Help message(long)比较长的帮助信息 */
- #endif
- #ifdef CONFIG_AUTO_COMPLETE
- /* do auto completion on the arguments */
- int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);
- #endif
- };
- struct cmd_tbl_s {
- char *name; /* Command Name命令名称 */
- int maxargs; /* maximum number of arguments 最大参数个数*/
- int repeatable; /* autorepeat allowed? 是否允许重复输入 */
- /* Implementation function */
- int (*cmd)(struct cmd_tbl_s *, int, int, char *[]);//命令处理函数
- char *usage; /* Usage message(short) 比较短的帮助信息*/
- #ifdef CONFIG_SYS_LONGHELP
- char *help; /* Help message(long)比较长的帮助信息 */
- #endif
- #ifdef CONFIG_AUTO_COMPLETE
- /* do auto completion on the arguments */
- int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);
- #endif
- };
在我用的板子上有环境变量bootcmd=booti mmc3,也就是说,系统启动的时候要执行booti mmc3这条命令,那么booti的结构体的定义在\bootable\bootloader\uboot-imx\common\cmd_bootm.c
- U_BOOT_CMD(
- booti, 3, 1, do_booti,
- "booti - boot android bootimg from memory\n",
- "[<addr> | mmc0 | mmc1 | mmc2 | mmcX] [<partition>] \n - boot application image stored in memory or mmc\n"
- "\t'addr' should be the address of boot image which is zImage+ramdisk.img\n"
- "\t'mmcX' is the mmc device you store your boot.img, which will read the boot.img from 1M offset('/boot' partition)\n"
- "\t 'partition' (optional) is the partition id of your device, if no partition give, will going to 'boot' partition\n"
- );
- U_BOOT_CMD(
- booti, 3, 1, do_booti,
- "booti - boot android bootimg from memory\n",
- "[<addr> | mmc0 | mmc1 | mmc2 | mmcX] [<partition>] \n - boot application image stored in memory or mmc\n"
- "\t'addr' should be the address of boot image which is zImage+ramdisk.img\n"
- "\t'mmcX' is the mmc device you store your boot.img, which will read the boot.img from 1M offset('/boot' partition)\n"
- "\t 'partition' (optional) is the partition id of your device, if no partition give, will going to 'boot' partition\n"
- );
可知booti的处理函数是do_booti
- /* booti <addr> [ mmc0 | mmc1 [ <partition> ] ] */
- int do_booti(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
- {
- unsigned addr = 0;
- char *ptn = "boot";
- int mmcc = -1;
- boot_img_hdr *hdr = (void *)boothdr;
- if (argc < 2) //至少有1个有效参数
- return -1;
- if (!strncmp(argv[1], "mmc", 3))
- mmcc = simple_strtoul(argv[1]+3, NULL, 10); //得到启动的mmc名字
- else
- addr = simple_strtoul(argv[1], NULL, 16);
- if (argc > 2)
- ptn = argv[2];
- if (mmcc != -1) {
- #ifdef CONFIG_MMC
- struct fastboot_ptentry *pte;
- struct mmc *mmc;
- disk_partition_t info;
- block_dev_desc_t *dev_desc = NULL;
- unsigned sector, partno = -1;
- memset((void *)&info, 0 , sizeof(disk_partition_t));
- /* i.MX use MBR as partition table, so this will have
- to find the start block and length for the
- partition name and register the fastboot pte we
- define the partition number of each partition in
- config file
- */
- mmc = find_mmc_device(mmcc); //查找启动的mmc设备
- if (!mmc) {
- printf("booti: cannot find '%d' mmc device\n", mmcc);
- goto fail;
- }
- dev_desc = get_dev("mmc", mmcc);//得到设备描述
- if (NULL == dev_desc) {
- printf("** Block device MMC %d not supported\n", mmcc);
- goto fail;
- }
- /* below was i.MX mmc operation code */
- if (mmc_init(mmc)) { //初始化mmc
- printf("mmc%d init failed\n", mmcc);
- goto fail;
- }
- #ifdef CONFIG_ANDROID_BOOT_PARTITION_MMC
- #ifdef CONFIG_ANDROID_RECOVERY_PARTITION_MMC
- if (!strcmp(ptn, "boot"))
- partno = CONFIG_ANDROID_BOOT_PARTITION_MMC;
- if (!strcmp(ptn, "recovery"))
- partno = CONFIG_ANDROID_RECOVERY_PARTITION_MMC;
- if (get_partition_info(dev_desc, partno, &info)) { //获取mmc的分区信息
- printf("booti: device don't have such partition:%s\n", ptn);
- goto fail;
- }
- #endif
- #endif
- #ifdef CONFIG_FASTBOOT
- 。。。。。。。。//没配置fastboot
- #else
- // 这里首先说明一下bootimage的构成
- /*
- ** +-----------------+
- ** | boot header | 1 page
- ** +-----------------+
- ** | kernel | n pages
- ** +-----------------+
- ** | ramdisk | m pages
- ** +-----------------+
- ** | second stage | o pages
- ** +-----------------+
- **
- ** n = (kernel_size + page_size - 1) / page_size
- ** m = (ramdisk_size + page_size - 1) / page_size
- ** o = (second_size + page_size - 1) / page_size
- **
- ** 0. all entities are page_size aligned in flash
- ** 1. kernel and ramdisk are required (size != 0)
- ** 2. second is optional (second_size == 0 -> no second)
- ** 3. load each element (kernel, ramdisk, second) at
- ** the specified physical address (kernel_addr, etc)
- ** 4. prepare tags at tag_addr. kernel_args[] is
- ** appended to the kernel commandline in the tags.
- ** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
- ** 6. if second_size != 0: jump to second_addr
- ** else: jump to kernel_addr
- */
- if (mmc->block_dev.block_read(mmcc, info.start,//读取mmc的第一块数据,即boot header
- 1, (void *)hdr) < 0) {
- printf("booti: mmc failed to read bootimg header\n");
- goto fail;
- }
- /* flush cache after read */
- //这是个空函数
- flush_cache((ulong)hdr, 512); /* FIXME *///
- if (memcmp(hdr->magic, BOOT_MAGIC, 8)) {//看是否是android
- printf("booti: bad boot image magic\n");
- goto fail;
- }
- sector = info.start + (hdr->page_size / 512);//得到kernel的首地址
- #endif
- if (mmc->block_dev.block_read(mmcc, sector, //读取kernel到内存中
- (hdr->kernel_size / 512) + 1,
- (void *)hdr->kernel_addr) < 0) {
- printf("booti: mmc failed to read kernel\n");
- goto fail;
- }
- /* flush cache after read */
- flush_cache((ulong)hdr->kernel_addr, hdr->kernel_size); /* FIXME */
- sector += ALIGN_SECTOR(hdr->kernel_size, hdr->page_size) / 512;得到ramdisk的首地址
- if (mmc->block_dev.block_read(mmcc, sector, //读取ramdisk到内存中
- (hdr->ramdisk_size / 512) + 1,
- (void *)hdr->ramdisk_addr) < 0) {
- printf("booti: mmc failed to read kernel\n");
- goto fail;
- }
- /* flush cache after read */
- flush_cache((ulong)hdr->ramdisk_addr, hdr->ramdisk_size); /* FIXME */
- #else
- return -1;
- #endif
- } else {
- //如果没有得到mmc设备,就从参数中得到bootimage的地址然后初始化hdr
- unsigned kaddr, raddr;
- /* set this aside somewhere safe */
- memcpy(hdr, (void *) addr, sizeof(*hdr));
- if (memcmp(hdr->magic, BOOT_MAGIC, 8)) {
- printf("booti: bad boot image magic\n");
- return 1;
- }
- bootimg_print_image_hdr(hdr);
- kaddr = addr + hdr->page_size;
- raddr = kaddr + ALIGN_SECTOR(hdr->kernel_size, hdr->page_size);
- memmove((void *) hdr->kernel_addr, (void *)kaddr, hdr->kernel_size);
- memmove((void *) hdr->ramdisk_addr, (void *)raddr, hdr->ramdisk_size);
- }
- printf("kernel @ %08x (%d)\n", hdr->kernel_addr, hdr->kernel_size);
- printf("ramdisk @ %08x (%d)\n", hdr->ramdisk_addr, hdr->ramdisk_size);
- do_booti_linux(hdr);//启动内核
- puts ("booti: Control returned to monitor - resetting...\n");
- do_reset (cmdtp, flag, argc, argv);
- return 1;
- fail:
- #ifdef CONFIG_FASTBOOT
- return do_fastboot(NULL, 0, 0, NULL);
- #else
- return -1;
- #endif
- }
- /* booti <addr> [ mmc0 | mmc1 [ <partition> ] ] */
- int do_booti(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
- {
- unsigned addr = 0;
- char *ptn = "boot";
- int mmcc = -1;
- boot_img_hdr *hdr = (void *)boothdr;
- if (argc < 2) //至少有1个有效参数
- return -1;
- if (!strncmp(argv[1], "mmc", 3))
- mmcc = simple_strtoul(argv[1]+3, NULL, 10); //得到启动的mmc名字
- else
- addr = simple_strtoul(argv[1], NULL, 16);
- if (argc > 2)
- ptn = argv[2];
- if (mmcc != -1) {
- #ifdef CONFIG_MMC
- struct fastboot_ptentry *pte;
- struct mmc *mmc;
- disk_partition_t info;
- block_dev_desc_t *dev_desc = NULL;
- unsigned sector, partno = -1;
- memset((void *)&info, 0 , sizeof(disk_partition_t));
- /* i.MX use MBR as partition table, so this will have
- to find the start block and length for the
- partition name and register the fastboot pte we
- define the partition number of each partition in
- config file
- */
- mmc = find_mmc_device(mmcc); //查找启动的mmc设备
- if (!mmc) {
- printf("booti: cannot find '%d' mmc device\n", mmcc);
- goto fail;
- }
- dev_desc = get_dev("mmc", mmcc);//得到设备描述
- if (NULL == dev_desc) {
- printf("** Block device MMC %d not supported\n", mmcc);
- goto fail;
- }
- /* below was i.MX mmc operation code */
- if (mmc_init(mmc)) { //初始化mmc
- printf("mmc%d init failed\n", mmcc);
- goto fail;
- }
- #ifdef CONFIG_ANDROID_BOOT_PARTITION_MMC
- #ifdef CONFIG_ANDROID_RECOVERY_PARTITION_MMC
- if (!strcmp(ptn, "boot"))
- partno = CONFIG_ANDROID_BOOT_PARTITION_MMC;
- if (!strcmp(ptn, "recovery"))
- partno = CONFIG_ANDROID_RECOVERY_PARTITION_MMC;
- if (get_partition_info(dev_desc, partno, &info)) { //获取mmc的分区信息
- printf("booti: device don't have such partition:%s\n", ptn);
- goto fail;
- }
- #endif
- #endif
- #ifdef CONFIG_FASTBOOT
- 。。。。。。。。//没配置fastboot
- #else
- // 这里首先说明一下bootimage的构成
- /*
- ** +-----------------+
- ** | boot header | 1 page
- ** +-----------------+
- ** | kernel | n pages
- ** +-----------------+
- ** | ramdisk | m pages
- ** +-----------------+
- ** | second stage | o pages
- ** +-----------------+
- **
- ** n = (kernel_size + page_size - 1) / page_size
- ** m = (ramdisk_size + page_size - 1) / page_size
- ** o = (second_size + page_size - 1) / page_size
- **
- ** 0. all entities are page_size aligned in flash
- ** 1. kernel and ramdisk are required (size != 0)
- ** 2. second is optional (second_size == 0 -> no second)
- ** 3. load each element (kernel, ramdisk, second) at
- ** the specified physical address (kernel_addr, etc)
- ** 4. prepare tags at tag_addr. kernel_args[] is
- ** appended to the kernel commandline in the tags.
- ** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
- ** 6. if second_size != 0: jump to second_addr
- ** else: jump to kernel_addr
- */
- if (mmc->block_dev.block_read(mmcc, info.start,//读取mmc的第一块数据,即boot header
- 1, (void *)hdr) < 0) {
- printf("booti: mmc failed to read bootimg header\n");
- goto fail;
- }
- /* flush cache after read */
- //这是个空函数
- flush_cache((ulong)hdr, 512); /* FIXME *///
- if (memcmp(hdr->magic, BOOT_MAGIC, 8)) {//看是否是android
- printf("booti: bad boot image magic\n");
- goto fail;
- }
- sector = info.start + (hdr->page_size / 512);//得到kernel的首地址
- #endif
- if (mmc->block_dev.block_read(mmcc, sector, //读取kernel到内存中
- (hdr->kernel_size / 512) + 1,
- (void *)hdr->kernel_addr) < 0) {
- printf("booti: mmc failed to read kernel\n");
- goto fail;
- }
- /* flush cache after read */
- flush_cache((ulong)hdr->kernel_addr, hdr->kernel_size); /* FIXME */
- sector += ALIGN_SECTOR(hdr->kernel_size, hdr->page_size) / 512;得到ramdisk的首地址
- if (mmc->block_dev.block_read(mmcc, sector, //读取ramdisk到内存中
- (hdr->ramdisk_size / 512) + 1,
- (void *)hdr->ramdisk_addr) < 0) {
- printf("booti: mmc failed to read kernel\n");
- goto fail;
- }
- /* flush cache after read */
- flush_cache((ulong)hdr->ramdisk_addr, hdr->ramdisk_size); /* FIXME */
- #else
- return -1;
- #endif
- } else {
- //如果没有得到mmc设备,就从参数中得到bootimage的地址然后初始化hdr
- unsigned kaddr, raddr;
- /* set this aside somewhere safe */
- memcpy(hdr, (void *) addr, sizeof(*hdr));
- if (memcmp(hdr->magic, BOOT_MAGIC, 8)) {
- printf("booti: bad boot image magic\n");
- return 1;
- }
- bootimg_print_image_hdr(hdr);
- kaddr = addr + hdr->page_size;
- raddr = kaddr + ALIGN_SECTOR(hdr->kernel_size, hdr->page_size);
- memmove((void *) hdr->kernel_addr, (void *)kaddr, hdr->kernel_size);
- memmove((void *) hdr->ramdisk_addr, (void *)raddr, hdr->ramdisk_size);
- }
- printf("kernel @ %08x (%d)\n", hdr->kernel_addr, hdr->kernel_size);
- printf("ramdisk @ %08x (%d)\n", hdr->ramdisk_addr, hdr->ramdisk_size);
- do_booti_linux(hdr);//启动内核
- puts ("booti: Control returned to monitor - resetting...\n");
- do_reset (cmdtp, flag, argc, argv);
- return 1;
- fail:
- #ifdef CONFIG_FASTBOOT
- return do_fastboot(NULL, 0, 0, NULL);
- #else
- return -1;
- #endif
- }
- void do_booti_linux (boot_img_hdr *hdr)
- {
- ulong initrd_start, initrd_end;
- void (*theKernel)(int zero, int arch, uint params);
- bd_t *bd = gd->bd;
- #ifdef CONFIG_CMDLINE_TAG
- char *commandline = getenv("bootargs");//读取环境变量中的bootargs
- /* If no bootargs env, just use hdr command line */
- if (!commandline)
- commandline = (char *)hdr->cmdline;
- /* XXX: in production, you should always use boot.img 's cmdline !!! */
- printf("kernel cmdline: \n\tuse %s command line:\n\t%s \n",
- getenv("bootargs") ? "uboot" : "boot.img",
- commandline);
- #endif
- theKernel = (void (*)(int, int, uint))(hdr->kernel_addr);//得到内存中kernel的main函数指针
- initrd_start = hdr->ramdisk_addr;
- initrd_end = initrd_start + hdr->ramdisk_size;
- #if defined (CONFIG_SETUP_MEMORY_TAGS)
- 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);//将命令行参数加入到bd中
- #endif
- #ifdef CONFIG_INITRD_TAG
- if (hdr->ramdisk_size)
- 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 ();
- theKernel (0, bd->bi_arch_number, bd->bi_boot_params);//直接传递参数启动kernel
- }
- void do_booti_linux (boot_img_hdr *hdr)
- {
- ulong initrd_start, initrd_end;
- void (*theKernel)(int zero, int arch, uint params);
- bd_t *bd = gd->bd;
- #ifdef CONFIG_CMDLINE_TAG
- char *commandline = getenv("bootargs");//读取环境变量中的bootargs
- /* If no bootargs env, just use hdr command line */
- if (!commandline)
- commandline = (char *)hdr->cmdline;
- /* XXX: in production, you should always use boot.img 's cmdline !!! */
- printf("kernel cmdline: \n\tuse %s command line:\n\t%s \n",
- getenv("bootargs") ? "uboot" : "boot.img",
- commandline);
- #endif
- theKernel = (void (*)(int, int, uint))(hdr->kernel_addr);//得到内存中kernel的main函数指针
- initrd_start = hdr->ramdisk_addr;
- initrd_end = initrd_start + hdr->ramdisk_size;
- #if defined (CONFIG_SETUP_MEMORY_TAGS)
- 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);//将命令行参数加入到bd中
- #endif
- #ifdef CONFIG_INITRD_TAG
- if (hdr->ramdisk_size)
- 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 ();
- theKernel (0, bd->bi_arch_number, bd->bi_boot_params);//直接传递参数启动kernel
- }
0 0
- uboot启动内核的实现
- uboot启动内核的实现
- uboot启动内核的实现
- uboot启动内核的实现
- NFS ROOT 启动内核的配置(UBoot)
- NFS ROOT 启动内核的配置(UBoot)
- 分析uboot是如何启动内核的
- 分析uboot是如何启动内核的
- 分析uboot是如何启动内核的
- NFS ROOT 启动内核的配置(UBoot)
- uboot启动内核的流程分析
- 分析uboot是如何启动内核的
- 分析uboot是如何启动内核的
- 分析uboot是如何启动内核的
- 分析uboot是如何启动内核的
- 分析uboot是如何启动内核的
- 分析uboot是如何启动内核的 .
- NFS ROOT 启动内核的配置(UBoot)
- Cubietruck---7. fex2bin源码简要分析(未完成)
- 离开hover的响应事件
- 流量卡文档
- PHP中间件(middleware)解析
- Linux编辑器vi的使用笔记
- uboot启动内核的实现
- Cubietruck---8. u-boot及boot.img简略分析
- 修改 eclipse 文件编码格式
- 关于预防流氓软件入侵的一点小心得
- AndroidManifest.xml中的minSdkVersion、targetSdkVersion、maxSdkVersion和project.properties中target API lev
- iOS Xcode项目在SVN更新后无法打开解决办法
- RTP协议全解(H264码流和PS流)
- MySQL各版本升级最佳实践
- Cubietruck---9.Linux3.3_initramfs启动分析