引言:最近要改动uboot,实现像微软PC上,u盘一键刷机或手机上安全模式下刷机的操作
专门去好好研究了点uboot的启动过程;以下为总结:

嵌入式系统                                                        微软-PC
————————————————————————

bootloader   -引导.启动内核                              Bios

内核                                                                   引导操作系统Windows

挂载根文件                                                        识别系统盘(C/D盘)

应用程序                                                            应用程序....
————————————————————————
bootloader之uboot的作用:引导、启动内核

从flash中读内核到SDRAM,在这之前,要求先先关开门口内初始化时钟和初始化SDRAM(通常称为硬件相关初始化)

uboot三个步奏:
1)从flash读出内核,

2)将其放到sdram中运行(要求可:写读flash->初始化sdram(初始化时钟、初始化串口)

3)然后启动内核

4)为开发方便,额外加入其他功能--烧写flash(比如从网络,usb或串口传进来的内核)!

分析Makefile,达到分析文件结构;分析配置过程:

1)配置:比如make Linux-menuconfig

2)编译:makez

二.读出内核并启动内核

1.了解系统的上电过程:
board_init_r --> init_sequence_r --> run_main_loop --> main_loop --> bootdelay_process-->autoboot_command 主要就是这么个流程(下图从右向左)



所以:具体怎么决定是进命令行还是启动kernel是在autoboot_command决定的!!!
正常自动启动如下:
左边为终端打印:右方tstc()即为获取键值;此处可以设置特定键值为启动内核开关!!

如果看到:

if (bootdelay >= 0)
{ //此处:键盘按Ctrl+C、enter、或者Space将abort置1,将不再启动内核if (tstc()) {    /* we got a key press    */             key = getc(); /* consume input */             puts("\b\b\b 0");             switch (key) {                 case 0x03:      /* ^C - Ctrl+C */                 case 0x0d:      /* Enter */                 case 0x20:      /* Space */ //only "enter" key can triger abort                 abort = 1;    /* don't auto boot    */             }
}

如果abortboot_single_key / abortboot_normal返回1,则autoboot_command执行完成,回到main_loop继续跑到cli_loop-->cli_simple_loop进入,并停在命令行模式。
2.上面是命令行模式,如果abortboot_single_key/abortboot_normal返回0.则abortboot返回0,那么autoboot_command里调用run_command_list,run_command_list中执行命令bootcmd启动kernel!
接下来说,上电从flash读取内核存入系统内存并启动kernel的过程:
如上说到run_command_list函数,该函数会调取board_run_command(buff);
#ifdef CONFIG_CMDLINE
    rcode = cli_simple_run_command_list(buff, flag);
#else
    rcode = board_run_command(buff);
#endif


在调取之前,需要读取环境变量的数据参数;根据参数去读取指定位置flash的内核!
如下,是环境参数:

--------下面涉及到一般执行一个内核镜像的四个步骤-------
第一步先读取头信息,然后在头信息的特定地址找MAGIC_NUM,由此来确定种类,第二步对镜像进行校验,第三步再次读取头信息,由头信息的特定地址知道这个镜像的各种信息,包括长度,种类,入口地址等等,第四步就是去entrypoint处开始执行镜像,

第一步:如果直接在kernel底下去make uImage会提示mkimage没找到,解决方案是在 /uboot/tool下去复制到 /usr/local/bin.下面去,复制它到系统目录下,再去执行make uImage就可以了;

do_bootm函数一直到397行之前都是进行zImage镜像的头部信息校验。校验时就要根据不同种类的image类型进行不同的校验。所以do_bootm函数的核心就是去分辨传进来的image到底是什么类型,然后按照这种类型的头信息格式去校验。校验通过则进入下一步准备启动内核;若果校验失败则认为镜像有问题,所以不能启动


do_bootm调用内核获取和校验


image_header_t结构体
(1)这个数据结构是我们uboot启动内核使用的一个标准启动数据结构,zImage头信息也是一个image_header_t,但是在实际启动之前需要进行一些改造,
if (*(ulong *)(addr + 9*4) == LINUX_ZIMAGE_MAGIC) {
        printf("Boot with zImage\n");
        addr = virt_to_phys(addr);
        hdr = (image_header_t *)addr;
        hdr->ih_os = IH_OS_LINUX;
        hdr->ih_ep = ntohl(addr);
        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;

这里就是在进行改造。
(2)image全局变量是在bootm函数中使用,目的是用来指向 os/initrd/fdt images,也就是用来完成启动的,zImage校验过程先确定是不是zImage,然后再修改zImage头信息,到合适,也就是上面的改造,最后再用这个头信息去初始化image,然后完成了校验。
zImage启动方式是后来添加的,而且用了goto的方式跳转了一部分代码,本身对uboot的结构上添加的。
uImage启动
(1)在uboot启动的do_boot中有一个legacy的方法,指的就是uImage这样的方式,为什么是legacy(遗留的),是因为uImage本身是uboot发明的一种启动的方式,后来这种方式是不好的,被废弃,于是被一种新的方式给替代了,新的方式就是设备树的方式,在这里被叫做fit,这个就是设备树的方式。
(2)uImage启动校验函数是在boot_get_kernel这个函数里,主要任务就是校验我们的uImage的头信息,并且得到真正的kernel的起始位置去启动。
总结:uboot本身也只支持uImage方式启动的,后来有了设备树之后,就把uImage方式命名为legacy方式,fdt方式就命名为fit方式,于是乎多了#if  #endif添加代码。后来移植的人又为了省事添加了zImage的方式,又为了省事,添加了#if  #endif .
第二阶段校验头信息结束!

第三阶段,启动Linux内核,调用do_bootm_linux这个函数

do_bootm_linux:找到do_bootm_linux,这个函数在lib_arm/bootm.c中() ,给内核传参-image结构体

 
第四步:镜像的entrypoint:
ep就是程序入口,一个镜像的起始部分不是在镜像的开头(镜像的开头有很多字节的头信息),真正开始执行的代码在中间的某个部分,相对于头有一定偏移量的,这个偏移量放在头信息中的。
 一般执行一个镜像都是:第一步先读取头信息,然后在头信息的特定地址找MAGIC_NUM,由此来确定种类,第二步对镜像进行校验,第三步再次读取头信息,由头信息的特定地址知道这个镜像的各种信息,包括长度,种类,入口地址等等,第四步就是去entrypoint处开始执行镜像(此处第四步)
theKernel = (void (*)(int, int, uint))ep;将真正的入口地址赋值给thekernel,就是操作系统的第一句代码
Starting kernel ...这里打印是uboot的最后打印信息,如果这句后,串口没输出信息了,说明内核没有成功被执行,原因是传参错误(80%),内核在DDR中的加载地址。。。
如果传参正确:"Starting kernel ..."是内核启动的第0条

接下来查看给内核传参并启动内核的操作

tag方式传参
(1)struct tag,tag是一个数据结构,在uboot和linux kernel中都有定义tag数据机构,而且定义是一样的。
(2)tag_header和tag_xxx。tag_header中有这个tag的size和类型编码,kernel拿到一个tag后先分析tag_header得到tag的类型和大小,然后将tag中剩余部分当作一个tag_xxx来处理。
(3)tag_start与tag_end。kernel接收到的传参是若干个tag构成的,这些tag由tag_start起始,到tag_end结束。
(4)tag传参的方式是由linux kernel发明的,kernel定义了这种向我传参的方式,uboot只是实现了这种传参方式从而可以支持给kernel传参。

配置传参宏
(1)CONFIG_SETUP_MEMORY_TAGS,tag_mem,传参内容是内存配置信息。
(2)CONFIG_CMDLINE_TAG,tag_cmdline,传参内容是启动命令行参数,也就是uboot环境变量的bootargs.
(3)CONFIG_INITRD_TAG
(4)CONFIG_MTDPARTITION,传参内容是iNand/SD卡的分区表。
(5)起始tag是ATAG_CORE、结束tag是ATAG_NONE,其他的ATAG_XXX都是有效信息tag。
思考:内核如何拿到这些tag?
uboot最终是调用theKernel函数来执行linux内核的,uboot调用这个函数(其实就是linux内核)时传递了3个参数。这3个参数就是uboot直接传递给linux内核的3个参数,通过寄存器来实现传参的。(第1个参数就放在r0中,第二个参数放在r1中,第3个参数放在r2中)第1个参数固定为0,第2个参数是机器码,第3个参数传递的就是大片传参tag的首地址。
移植时注意事项
(1)uboot移植时一般只需要配置相应的宏即可
(2)kernel启动不成功,注意传参是否成功。传参不成功首先看uboot中bootargs设置是否正确,其次看uboot是否开启了相应宏以支持传参。

附:uboot命令的实现-命令为输入的字符串+参数[比较简单,详细可以去看韦东山的uboot视频]

输入字符串---即为命令name--->存在针对于命令的结构体

结构体

{
。name
。fun =
。。。。
}

出现对应的动作--->函数fune-
run_common()的实现先比较,若name比较正确,执行对应的fun


2021-09-14 uboot移植开发相关推荐

  1. Windows 10如何连接和使用局域网内的打印机(非网络打印机)亲测有效、绝对管用,不定时更新!!!(更新日期2021.09.14,如有不会的可以直接私我)

    (请先看置顶博文)本博打开方式!!!请详读!!!请详读!!!请详读!!!_Cat-CSDN博客 要完成这个Case,步骤很简单,以下是详细过程,慢慢看完就一定可以实现:(一定要保证涉及共享打印机的计算 ...

  2. U-Boot移植教程之二:移植

    内容来自 韦东山<嵌入式Linux应用开发完全手册> 一.U-Boot移植 开发板smdk2410的配置适用于大多数S3C2410单板,或是只需要极少的修改即可使用.但是目前U-Boot中 ...

  3. 实习日志 (2021.09.13)

    2021.09.13星期一 今天把之前的算法题终于给弄明白了,并能够按照自己的思路去把他给完成,总结这个题目并不是很难,最重要的是要把链表给弄懂,一开始由于我对链表不是很熟悉,导致我在写该题目的时候花 ...

  4. fl2440开发板之u-boot移植

    **************************************************************************************************** ...

  5. 嵌入式linux开发环境 cpu,嵌入式Linux开发环境的搭建之:U-Boot移植-嵌入式系统-与非网...

    5.2  U-Boot移植 5.2.1  Bootloader介绍 1.概念 简单地说,Bootloader就是在操作系统内核运行之前运行的一段程序,它类似于PC机中的BIOS程序.通过这段程序,可以 ...

  6. 【正点原子Linux连载】第三十三章 U-Boot移植 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

  7. STM32MP157 Linux系统移植开发篇4: BootLoader(Uboot)移植

    本文章为<STM32MP157 Linux系统移植开发篇>系列中的一篇,笔者使用的开发平台为华清远见FS-MP1A开发板(STM32MP157开发板).stm32mp157是ARM双核,2 ...

  8. 三星官方smdkv210 uboot移植到我的s5pv210开发板

    北京 2020-7-26 19:44 周日 昨天外面闷热 今日凉快.空调一开啥事没有!O(∩_∩)O 用了差不多两个周末蹲家里移植的.进度比较慢,算是把uboot相关的一些东西基本了解了. uboot ...

  9. 野火i.MX6ULL Pro开发板U-Boot移植

    之前一直用STM32跑RTT,最近想做一台游戏机,主屏采用960*640,但是发现STM32的运存实在着急,2M根本不够用,64M勉勉强强,但是看了看价格就呵呵了.于是在网上搜了搜发现i.MX6ULL ...

最新文章

  1. CVPR 2020丨UDVD:用于可变退化的统一动态卷积超分辨率网络
  2. [題解](最小生成樹)luogu_P2916安慰奶牛
  3. java文件怎么建立关联_如何创建两个Java Web应用程序并相互关联jar依赖关系和其他文件?...
  4. 上架过程中遇到的问题
  5. OpenCV实战中:blender-feed(img_warped_s, mask_warped, corners[img_idx]);这里有异常的处理方法
  6. android颜色值的表示方法android:background=#FFFFFFFF的意思
  7. oracle监听启动命令6,[转] oracle 监听
  8. C++ and Java template class and function 模板类和模板函数
  9. 微信小程序源码及H5小游戏源码内核构建方法
  10. mysql请假表_[源码和文档分享]基于JSP和MYSQL数据库实现的请假管理系统
  11. 使用python bloomfilter实现大文本去重
  12. Geodesic flow kernel for unsupervised domain adaptation
  13. 特征选择之互信息(mutual information)算法思想及其python代码实现
  14. 微信文件管理更改文件夹移动报错
  15. steam在连接至steam服务器时发生错误解决办法
  16. android蓝牙配对 自动联接,如何实现android蓝牙开发 自动配对连接,并不弹出提示框...
  17. 同步与异步通信的区别
  18. Fabric交易流程
  19. Growth Hacker:新型的市场 VP
  20. postGresql关键字字段重名

热门文章

  1. 转:利用python调用谷歌翻译API
  2. Android 开发的猜拳游戏
  3. NCBI引物设计、检验引物特异性、检索基因序列、BLAST
  4. 本科毕业工作五年,一点感慨(转)
  5. Tomcat 8.5.40下载及安装(Windows版本)
  6. linux unix shell programming,UNIX Shell Programming, 4th Edition
  7. 身份证在日常生活重要性 OCR身份证识别的作用
  8. iPhone双镜头离单反相机的距离
  9. 51单片机c语言485通讯案例,485通讯协议程序怎么写(51单片机的485通信程序案例)...
  10. Excel表生成键盘上的ANSI值(ASCII值)