uboot启动内核的实现
来源:互联网 发布:淘宝内衣店铺名字大全 编辑:程序博客网 时间:2024/06/08 02:55
我们知道uboot启动以后所有功能都是通过命令来实现的,启动kernel就是执行了bootcmd里面的命令。命令执行过程在uboot中是非常重要的现在我们就来看uboot命令的实现过程。
在main_loop()代码 中可以知道,uboot处理命令的函数是run_command()
代码在bootable\bootloader\uboot-imx\common\main.c中
- int run_command (const char *cmd, int flag)
- {
- cmd_tbl_t *cmdtp;
- char cmdbuf[CONFIG_SYS_CBSIZE]; /* working copy of cmd */
- char *token; /* start of token in cmdbuf */
- char *sep; /* end of token (separator) in cmdbuf */
- char finaltoken[CONFIG_SYS_CBSIZE];
- char *str = cmdbuf;
- char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
- int argc, inquotes;
- int repeatable = 1;
- int rc = 0;
- #ifdef DEBUG_PARSER
- printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);
- puts (cmd ? cmd : "NULL"); /* use puts - string may be loooong */
- puts ("\"\n");
- #endif
- clear_ctrlc(); /* forget any previous Control C 清除所有的ctrl+c*/
- if (!cmd || !*cmd) {
- return -1; /* 命令为空就返回 */
- }
- if (strlen(cmd) >= CONFIG_SYS_CBSIZE) {
- puts ("##命令过长\n");
- return -1;
- }
- strcpy (cmdbuf, cmd);//拷贝到buff中
- /* Process separators and check for invalid
- * repeatable commands
- */
- #ifdef DEBUG_PARSER
- printf ("[PROCESS_SEPARATORS] %s\n", cmd);
- #endif
- while (*str) {
- /*
- * Find separator, or string end
- * Allow simple escape of ';' by writing "\;"
- */
- //提取出一条命令,命令的结尾是';'或者‘\’
- //注意这里的';'也就是说如果要一次输入多条命令的话,可以用';'隔开
- for (inquotes = 0, sep = str; *sep; sep++) {
- if ((*sep=='\'') &&
- (*(sep-1) != '\\'))
- inquotes=!inquotes;
- if (!inquotes &&
- (*sep == ';') && /* separator */
- ( sep != str) && /* past string start */
- (*(sep-1) != '\\')) /* and NOT escaped */
- break;
- }
- /*
- * Limit the token to data between separators
- */
- token = str;
- if (*sep) {
- str = sep + 1; /* start of command for next pass */
- *sep = '\0';
- }
- else
- str = sep; /* no more commands for next pass */
- #ifdef DEBUG_PARSER
- printf ("token: \"%s\"\n", token);
- #endif
- /* find macros in this token and replace them */
- //处理一些宏定义比如字符串引用时候的“${}”
- //命令分行符'\'等等
- process_macros (token, finaltoken);
- /* Extract arguments */
- //将命令按照格式分配到argv数组中
- //比如我们输入的命令 bootdelay=3;
- //转换以后我们得到argv[0]="bootdelay"
- //argv[1]="3"
- if ((argc = parse_line (finaltoken, argv)) == 0) {
- rc = -1; /* no command at all */
- continue;
- }
- /* Look up command in command table */
- if ((cmdtp = find_cmd(argv[0])) == NULL) {//查找这条命令并得到描述它的结构体
- printf ("Unknown command '%s' - try 'help'\n", argv[0]);
- rc = -1; /* give up after bad command */
- continue;
- }
- 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 */
- }
- /* 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
- };
在我用的板子上有环境变量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"
- );
可知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
- }
- 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
- }
整个过程比较简单,关键是uboot命令实现过程很重要,在自己移植uboot时候很有肯恩更要修改这些代码。需要进一步掌握
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)
- Ghost博客搭建步骤
- MyEclipse配置代码格式化模版
- xtml简单登录表单
- 对于struct file_operations中ioctl消失的学习笔记
- c/c++ 时间日期函数
- uboot启动内核的实现
- 【华为OJ4】字符串分隔
- 328. Odd Even Linked List
- 安装Ubuntu 14.04后要做的5件事情
- 【HFUTXC】1002.校门外的树
- C++实现简单的socket通信
- ARM汇编必知必会
- java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: YES)
- ARM处理器工作模式