回忆上一节,UBoot当前要解析和执行启动命令。该启动命令存储在环境变量bootcmd中。回忆环境变量的内容:


baudrate=115200bloader=ext4load mmc 0:1bootcmd=$bloader 0x48000000 $kernel;$bloader 0x49000000 root.img.gz;bootm 0x48000000bootdelay=0bootfile=uImageethaddr=00:e2:1c:ba:e8:60firstboot=0gatewayip=192.168.1.254ipaddr=192.168.1.165kernel=uImagenetmask=255.255.255.0serverip=192.168.1.164stderr=serialstdin=serialstdout=serial

bootcmd一个有三条命令,通过继续展开后可以得到三条命令的全部内容:


ext4load mmc 0:1 0x48000000 uImageext4load mmc 0:1 0x49000000 root.img.gzbootm 0x48000000

首先先查找第一条命令的相关信息,ext4load。这条命令的实现位于/uboot-root/common/cmd_ext4.c中。下面是其定义:


U_BOOT_CMD(ext4load, 6, 0, do_ext4_load,"load binary file from a Ext4 filesystem","<interface> <dev[:part]> [addr] [filename] [bytes]\n"" - load binary file 'filename' from 'dev' on 'interface'\n"" to address 'addr' from ext4 filesystem");

可以看出,这个命令由do_ext4_load()去执行实现,作用是从具体设备或分区上的ext4文件系统中将指定文件以二进制的形式复制到指定内存地址上。由于其具体实现涉及硬件操作,过程比较复杂,这里就不详细展开了。但需要知道的是,第一和第二条命令,是将Linux系统的内核uImage和Linux系统的根文件系统root.img.gz分别复制到0x4800_0000和0x4900_0000这两个地址中。复制完后内存使用情况如下:


RAM:0xC000_0000-0x5000_0000(RAM_TOP)-0x4FFE_F800UBOOT(Reserve 478K)0x4FF7_8000-0x4FFF_4000TLB table0x4FFF_0000-0x4DF9_8000malloc(Reserve 32768K)0x4DF7_8000Board Info(Reserve 80B) = gd->bd0x4DF7_7FB0New GD0x4DF7_7F10IRQ0x4DF7_7F00(IRQ_SP)-0x4DF7_7EF0root.img.gz0x4900_0000uImage0x4800_0000-0x4500_0000Heap0x4300_0000-0x42C8_C000Page0x42C8_0000-0x42C7_7988UBOOT0x42C0_0000GD0x42BF_FEB8BD Info0x42BF_FE68(START_ADDR_SP)UBoot-Stack0x4000_0000

最后执行的一条命令是bootm 0x4800_0000。该命令的实现在/uboot-root/common/cmd_bootm.c中,下面是其定义:


U_BOOT_CMD(bootm, CONFIG_SYS_MAXARGS, 1, do_bootm,"boot application image from memory", bootm_help_text);

可以看出,该命令是从内存中启动一个应用程序镜像,具体的实现在do_bootm函数中。下面是do_bootm()的具体代码:


int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]){/* determine if we have a sub command */argc--; argv++;if (argc > 0) {char *endp;simple_strtoul(argv[0], &endp, 16);/* endp pointing to NULL means that argv[0] 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);}return do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START |BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER |BOOTM_STATE_LOADOS |BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |BOOTM_STATE_OS_GO, &images, 1);}

这里首先关注中间的if判断。根据注释说明,这里的判断用于判断bootm后面的参数是否跟着一些子命令,如果有则先执行子命令。由于这里传进来的参数就只有0x4800_0000,所以并没有子命令要执行。最后要关注的是do_bootm_states()。该函数的实现如下:


int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],int states, bootm_headers_t *images, int boot_progress){boot_os_fn *boot_fn;ulong iflag = 0;int ret = 0, need_boot_fn;images->state |= states;/** Work through the states and see how far we get. We stop on* any error.*/if (states & BOOTM_STATE_START)ret = bootm_start(cmdtp, flag, argc, argv);if (!ret && (states & BOOTM_STATE_FINDOS))ret = bootm_find_os(cmdtp, flag, argc, argv);if (!ret && (states & BOOTM_STATE_FINDOTHER)) {ret = bootm_find_other(cmdtp, flag, argc, argv);argc = 0; /* consume the args */}/* Load the OS */if (!ret && (states & BOOTM_STATE_LOADOS)) {ulong load_end;iflag = bootm_disable_interrupts();ret = bootm_load_os(images, &load_end, 0);if (ret == 0)lmb_reserve(&images->lmb, images->os.load,(load_end - images->os.load));else if (ret && ret != BOOTM_ERR_OVERLAP)goto err;else if (ret == BOOTM_ERR_OVERLAP)ret = 0;}/* From now on, we need the OS boot function */if (ret)return ret;boot_fn = bootm_os_get_boot_func(images->os.os);need_boot_fn = states & (BOOTM_STATE_OS_CMDLINE |BOOTM_STATE_OS_BD_T | BOOTM_STATE_OS_PREP |BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO);if (boot_fn == NULL && need_boot_fn) {if (iflag)enable_interrupts();printf("ERROR: booting os '%s' (%d) is not supported\n",genimg_get_os_name(images->os.os), images->os.os);bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS);return 1;}/* Call various other states that are not generally used */if (!ret && (states & BOOTM_STATE_OS_CMDLINE))ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, images);if (!ret && (states & BOOTM_STATE_OS_BD_T))ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images);if (!ret && (states & BOOTM_STATE_OS_PREP))ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images);/* Check for unsupported subcommand. */if (ret) {puts("subcommand not supported\n");return ret;}/* Now run the OS! We hope this doesn't return */if (!ret && (states & BOOTM_STATE_OS_GO))ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO,images, boot_fn);/* Deal with any fallout */err:if (iflag)enable_interrupts();if (ret == BOOTM_ERR_UNIMPLEMENTED)bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL);else if (ret == BOOTM_ERR_RESET)do_reset(cmdtp, flag, argc, argv);return ret;}

在这里首先通过bootm_start()去初始化images变量里的一些参数,并标记UBoot的执行过程。

然后调用bootm_find_os()找到内核的头信息,并继续初始化images变量。

然后调用bootm_find_other()去加载ramdisk,但是这里并没有ramdisk可以加载。

接下来调用的关键函数是botm_load_os()。在这里面主要调用了一个叫decomp_image()的函数,将整个linux内核镜像从0x4800_0000复制到0x4000_8000的位置上。从此,内存空间的使用如下所示:


0xC000_0000-0x5000_0000(RAM_TOP)-0x4FFE_F800UBOOT(Reserve 478K)0x4FF7_8000-0x4FFF_4000TLB table0x4FFF_0000-0x4DF9_8000malloc(Reserve 32768K)0x4DF7_8000Board Info(Reserve 80B) = gd->bd0x4DF7_7FB0New GD0x4DF7_7F10IRQ0x4DF7_7F00(IRQ_SP)-0x4DF7_7EF0root.img.gz0x4900_0000uImage0x4800_0000-0x4500_0000Heap0x4300_0000-0x42C8_C000Page0x42C8_0000-0x42C7_7988UBOOT0x42C0_0000GD0x42BF_FEB8BD Info0x42BF_FE68(START_ADDR_SP)UBoot-Stack-0x4043_6FE8Kernel(uImage)0x4000_8000-0x4000_0000

接下来调用的关键函数是boot_selected_os()。在这里面有一个值得注意的函数指针boot_fn。这个函数指针指向了一个叫do_bootm_linux的函数。该函数位于/uboot-root/arch/arm/lib/bootm.c中。在boot_selected_os()中通过boot_fn这个指针调用了do_bootm_linux()。然后又在do_bootm_linux()这个函数里面调用了boot_jump_linux()这个函数。其代码如下:


static void boot_jump_linux(bootm_headers_t *images, int flag){unsigned long machid = gd->bd->bi_arch_number;char *s;void (*kernel_entry)(int zero, int arch, uint params);unsigned long r2;int fake = (flag & BOOTM_STATE_OS_FAKE_GO);kernel_entry = (void (*)(int, int, uint))images->ep;s = getenv("machid");if (s) {strict_strtoul(s, 16, &machid);printf("Using machid 0x%lx from environment\n", machid);}debug("## Transferring control to Linux (at address %08lx)" \"...\n", (ulong) kernel_entry);bootstage_mark(BOOTSTAGE_ID_RUN_OS);announce_and_cleanup(fake);if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)r2 = (unsigned long)images->ft_addr;elser2 = gd->bd->bi_boot_params;if (!fake)kernel_entry(0, machid, r2);}

在这个函数中,首先通过gd获取了machid(4330)。第二,获取了内核入口的地址(0x4000_8000)。第三,在启动内核之前用announce_and_cleanup()进行了些启动前的初始化工作,如设置cache等。最后,就是准备r2寄存器,存储启动参数的首地址。

最后的最后,就是通过函数指针kernel_entry()去启动内核。从这个时候开始,UBoot就将控制权交给linux内核了,从此完成了引导的使命。

NanoPC-T2 Uboot启动过程分析 - 3-2 启动命令的执行相关推荐

  1. u-boot启动过程分析(一)

     u-boot启动过程分析(以u-boot-2012.0401为例) u-boot的启动过程可以分为以下几步 将CPU设置为管理者模式(SVC32) 关看门狗 屏蔽中断 设置时钟 设置内存控制器( ...

  2. uboot分析:uboot的启动过程分析

    (注:本文参考资料:朱有鹏嵌入式课程.本文为个人学习记录,如有错误,欢迎指正.) 1. U-Boot启动过程概述 U-Boot的启动过程分为两个阶段. 第一阶段:主要是SOC内部的初始化,板级的初始化 ...

  3. 海思芯片(hi3516dv300)uboot启动过程分析

    1.海思分段式uboot镜像 (1)uboot镜像的生成参考博客:<海思芯片(hi3516dv300)uboot镜像生成过程详解>: (2)海思uboot镜像类似于内核的zImage镜像, ...

  4. OMPL138及U-Boot的启动过程分析(一)

    一直阅读代码以及实验了一段时间,这次就趁着这个时间将过往的一些东西整理一下. OMAPL138是TI的一款DSP+ARM的双核工业处理器. TI的芯片上都有ROM(Read OnlyMemroy)内存 ...

  5. BF533之UBOOT启动过程分析

    本文分析的是在BF533处理器上,以BFIN_BOOT_SPI_MASTER方式启动过程.供交流学习用,引用请注明出处. uboot版本u-boot-2010.06-2010R1-RC2.tar.bz ...

  6. OpenWrt启动过程分析+添加自启动脚本【转】

    一.OpenWrt启动过程分析 转自: http://www.eehello.com/?post=107 总结一下OpenWrt的启动流程:1.CFE->2.linux->3./etc/p ...

  7. linux 重定位arm,Arm linxu启动过程分析(一)

    本文着重分析 FS2410 平台 linux-2.6.14 内核启动的详细过程,主要包括: zImage 解压缩阶段. vmlinux 启动汇编阶段. startkernel 到创建第一个进程阶段三个 ...

  8. Uboot启动分析--start.S启动分析(1)

    总目录 NXP i.MX8M secure boot流程 Uboot链接脚本分析述 Uboot启动分析–start.S启动分析(1) Uboot启动分析–start.S启动分析(2) Uboot启动分 ...

  9. ARM64启动过程分析

    文章目录 arm64启动过程分析 arm64启动过程分析(一)boot protocol arm64启动过程分析(二)内核启动第一步 arm64启动过程分析(三)创建启动阶段页表 arm64启动过程分 ...

最新文章

  1. Oracle Study之--ORA-12537(TNS:connection closed) 错误案例
  2. web标准---html、css、js分离
  3. 关于Unity中Shader的内置值
  4. Spring Boot快速搭建Spring框架
  5. 辅助类BinaryTreeNode(二叉树节点)
  6. c++嵌入linux指令以查找文件夹
  7. 虽然自己不是唱歌的材料
  8. 25.TCP/IP 详解卷1 --- SNMP:简单网络管理协议
  9. 通过JS改变框架的src
  10. 【语音识别】基于matlab GUI HMM中文语音识别【含Matlab源码 1385期】
  11. 什么是前端以及前端的重要性
  12. php 输出中文文件名乱码,PHP fopen中文文件名乱码问题解决方案
  13. iAd框架详细解析 —— ASM
  14. 工商数据采集的10个经典方法
  15. 基于PHP的酒店住宿管理系统毕业设计源码261455
  16. linux 脚本 input,Linux 下通过命令行和脚本开关笔记本触控板和其他输入外设
  17. CentOS/Deepin遇到Qt系列问题的解决方案(例如error: cannot find -lGL和搜狗输入法无效等)
  18. 如何画 1PX 的线
  19. 苹果开发者账号官方翻译篇-团队管理
  20. [linux] 远程服务器安装unrar(无root)

热门文章

  1. 手机中即将大行其道的Flash Lite.
  2. 深入理解并发编程之CAS无锁机制与ABA问题
  3. PCBA加工中常见的两种焊接方式详解
  4. 关于大数据技术原理与应用的学习(4)
  5. 中国计算机软件行业分析2---国内企业分类
  6. 射频功放OIP3,IIP3,IM3,IMD3几个指标的具体计算
  7. 基于SpringBoot 2.x开发的简易版图书管理系统(实现对图书的CRUD)
  8. jquery获取指定元素
  9. IDEA开发工具23 - 开启多个实例
  10. 逻辑回归中的离散变量