关闭

uboot源码——内核启动分析

519人阅读 评论(0) 收藏 举报
分类:

以下内容源于朱有鹏嵌入式课程的学习,如有侵权,请告知删除。

参考资料:http://www.cnblogs.com/biaohc/p/6403863.html


总结:uboot启动linux内核的整个流程

开机时会出现倒计时,当没有按键按下的时候,uboot会读取出bootcmd这个环境变量,并使用rum_command函数来执行这个命令;

  • 实质是执行了movi read kernel 30008000;bootm 30008000。
  • movi read kernel,把sd卡中的kernel分区赋值到30008000内存处;
  • bootm 30008000,真正的传参以及跳转到linux内核中执行(实际执行do_bootm()函数)。
  • bootm(do_bootm()函数)首先要做的事情是判断这个内核镜像类型(zImage、uImage、设备树);
  • 通过对镜像文件的头文件的验证,以确定是哪种内核镜像,然后再把必须的信息储存起来(linux操作系统、ep的值等)。
  • 确定好以后调用do_bootm_linux函数来对内核传参并且启动内核。

 


一、uboot作用简介

uboot的主要作用是用来启动linux内核。

  • 因为CPU不能直接从块设备中执行代码,需要把块设备中的程序复制到内存中,而复制之前还需要进行很多初始化工作,如时钟、串口、dram等;
  • 如要想让CPU启动linux内核,只能通过另外的程序,进行必要的初始化工作,在把linux内核中代码复制到内存中,并执行这块内存中的代码,即可启动linux内核;
  • 一般情况下,linux镜像储存在块设备中(SD卡、iNand、Nandflash等)。首先执行uboot代码,把块设备中的内核代码复制到内存地址0x30008000地址处,然后再执行bootm 0x30008000命令以启动内核代码。


 

二、基础知识 

vmlinuz、Image、zImage、uImage的区别与联系

(1)linux内核代码经过编译链接,生成一个elf格式的可执行文件,即vmlinuz或者vmlinux;

  • 此文件不能直接烧录。

(2)vmlinuz文件经过arm-linux-objcopy以后,生成一个Image镜像文件。

  • vmlinuz.elf文件大小为70M以上,而Image镜像文件为7M左右。

(3)Image文件在进一步经过压缩,并添加解压缩代码,形成zImage文件。

  • 当zImage文件作为启动镜像来启动时,首先要解压这个文件,这个解压过程可以由uboot解压或者zImage文件本身自解压。
  • zImage中除了linux内核的镜像以外,还有一些头文件以及这部分解压代码,所以内核实际上在addr地址中再加一个偏移量的位置。

(5)uImage是uboot自己专用的启动内核镜像,相对于zImage他们之间头文件有一定区别。

  • uImage现在基本上要属于过时的技术了,新一点的技术为设备树的启动方式;

 


三、UBOOT启动内核的代码分析


在启动UBOOT时,出现倒计时,如果没有按键按下,则会自动启动内核。

1、start_armboot()函数末尾的main_loop

 



下面这段代码在此main_loop函数中,作用是执行完倒计时函数之后,启动linux内核。

  • 启动方式是s = getenv ("bootcmd");;
  • 假定不使用HUAH_PARSER,则run_command (s, 0);实际上就是读取环境变量bootcmd,然后执行这个命令。

 

 

2、bootcmd命令

  • bootcmd=movi read kernel 30008000; movi read rootfs 30B00000 300000; bootm 30008000 30B00000
  • 这两个命令完成linux内核启动。
  • movi read kernel 30008000,把sd卡中kernel分区复制到30008000内存地址处;
  • bootm 30008000,到内存地址处执行代码;
  • 执行bootm命令,实际执行do_bootm函数。

  

3、do_bootm()函数

 

 

(1)因为bootm 0x30008000,参数为2,因此有addr = simple_strtoul(argv[1], NULL, 16)

  • 此时addr中的值为0x30008000。

(2)接着判断0x30008000偏移36字节以后的地址中的值

  • 如果为0x016f2818,说明启动镜像为zImage,则输出boot with zImage。

(3)内核的操作系统类型,和内核真正的入口

  • hdr->ih_os = IH_OS_LINUX;zImage header中ih_os赋值为 IH_OS_LINUX;
  • hdr->ih_ep = ntohl(addr);ih_ep中存放的是point address,这个值是真正内核代码的地址(起始执行入口地址);

(4)image变量

  • static bootm_headers_t images
  • images为uboot内定义的一个bootm_header_t格式的全局变量,用来完成启动过程的。
  • bootm_header_t类型为一个结构体,如下图:
  • 包含一个image_header_t类型的指针,这个指针最后指向了0x30008000处的zImage header。
  • 包含一个image_header_t类型的结构体,后面会把0x30008000处的zImage header复制一份到此结构体;
  • 包含一个标志位 legacy_hdr_valid。如果上面两个赋值以后,把legacy_hdr_valid赋值为1;

 

(5)memmove (&images.legacy_hdr_os_copy, hdr, sizeof(image_header_t));

  • 把hdr中的值复制一份到 image.legacy_hdr_os_copy中,即把内存地址0x30008000处设置好的zImage头复制一份到uboot的data段。

(6)直接跳转到after_header_check处,os为IH_OS_LINUX。



4、after_header_check

  • 判断操作系统,然后调用do_bootm_linux函数

 


5、do_bootm_linux()函数

 

 

(1)获取环境变量bootargs;

(2)判断全局变量images中的legacy_hdr_valid是否为1,如果为1获取ep值,如果不为1则error。

(3)把ep强制类型换换为函数指针类型赋值给thekernel;

(4)从环境变量中读取machid的值,赋值给s,如果s不空则machid = 环境变量中machid的值,并打印machid;



----------------------------------uboot给内核传参-----------------------------------------------

6、uboot给内核传参

  • 传参主要是uboot把与硬件有关的信息传给linux内核,如memory信息(多少bank、size、起始地址)、命令行信息、lcd 串口、initrd、MTD等信息。
  • 如要定义了任意一个CONFIG_XXXXX,则执行setup_start_tag(bd)

一、setup_start_tag函数

  • 初始化第一块参数tag

  



(1)params = (struct tag *) bd->bi_boot_params; 

  • gd->bd->bi_boot_params = (PHYS_SDRAM_1+0x100);
  • 这句代码,把uboot中的全局变量(即gd)的bi_boot_params内存地址,强制转换为stuct tag* 类型,然后赋值给params;
  • 把PHYS_SDRAM_1+0x100这个地址设置为传参的起始地址;  

(2)struct tag结构体


  • 此结构体由一个stuct tag_header类型的结构体,加上一个由一系列结构体组成的union联合体组成;
  • 这一系列结构体中存放的就是与board有关的参数;

(3)hdr.tag 与hdr.size赋值

  • params->hdr.tag = ATAG_CORE; params->hdr.size = tag_size (tag_core);
(4)对联合体中的结构体参数赋值
  • params->u.core.flags = 0;
  • params->u.core.pagesize = 0;
  • params->u.core.rootdev = 0;
(5)对下一个params进行初始化
  • params = tag_next (params); 
  • //#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size)),把params移动sizeof(tag_core)大小继续赋值



二、传递内存参数,setup_memory_tags函数

  • 把内存每个bank的信息放到这里:第一个扇区的起始地址和大小,第二个扇区的起始地址和大小……

 


三、传递命令行参数,setup_commandline_tag函数

  • commandline是一个char *类型,指向环境变量中的bootargs的值,即:
  • #define CONFIG_BOOTARGS  "root=/dev/mtdblock4 rootfstype=yaffs2 init=/init console=ttySAC0,115200"

 



四、setup_end_tag (bd):结束传参


-----------------------------------------uboot给内核传参结束-----------------------------------------------



 7、uboot中最后一句代码

  • 通过执行thekernel函数直接启动linux内核,传递三个参数:0、machid、传参的首地址;
  • 这三个参数是通过r0、r1、r2三个寄存器来传递,r0传递0、r1传递machid、r2传递传参的首地址。
  • 这样就把内核启动起来了。

 







0
0
查看评论
发表评论
* 以上用户言论只代表其个人钱柜娱乐开户,不代表CSDN网站的钱柜娱乐开户或立场

U-Boot启动流程(Linux内核)的分析(写得好)

前面一段时间一直在移植U-Boot,Linux内核和构建根文件系统,其中有些地方还不是很明白,现在回过头来,理解一下U-boot的启动流程,以及 u-Boot是如何加载引导内核启动的。这里的分析也都是...
  • hushup
  • hushup
  • 2014-04-02 09:10
  • 2049

深入理解uboot 2016 - 基础篇(处理器启动流程分析)

最近一段时间一直在做uboot相关的移植的工作,需要将uboot-2016-7移植到ARMv7的处理器上。正好元旦放假三天闲来无事,有段完整的时间来整理下最近的工作成果。之前在学习uboot时,在网上...
  • kernel_yx
  • kernel_yx
  • 2016-11-05 14:52
  • 3671

Exynos4412 Uboot 移植(四)—— Uboot引导内核过程分析

bootloader 要想启动内核,可以直接跳到内核的第一个指令处,即内核的起始地址,这样便可以完成内核的启动工作了。但是要想启动内核还需要满足一些条件,如下所示: 1、cpu 寄存器设置     *...
  • zqixiao_09
  • zqixiao_09
  • 2016-03-07 12:32
  • 3044

uboot内核启动过程源码分析

下面是我对uboot如何启动内核的代码进行的分析 需要了解的数据结构: bd 数据结构: typedef struct bd_info {     int bi_baudrate; /* s...
  • Doonavd
  • Doonavd
  • 2012-02-12 13:42
  • 698

uboot源码阅读(六)大佬的命令 uboot引导内核启动

大佬的命令下来了,不过并不是每个人都有资格去执行这样的命令,有资格的都是经过层层选拔了的。在江湖中你也是要不断努力拼搏的,否则,小弟永远都是小弟。 下面就是解析输入的字符串,然后在命令列表中找到相对...
  • ecbtnrt
  • ecbtnrt
  • 2011-07-24 21:05
  • 1890

linux-3.2.36内核启动4-setup_arch中的内存初始化3(arm平台 bootmem_init源码分析)

void__init bootmem_init(void) {         unsigned long min, max_low, max_high;       &#...
  • xxxxxlllllxl
  • xxxxxlllllxl
  • 2013-10-11 15:24
  • 2064

Linux内核源码分析--内核启动命令行的传递过程(Linux-3.0 ARMv7)

http://blog.chinaunix.net/uid-20543672-id-3151113.html  Linux内核在启动的时候需要一些参数,以获得当前硬件的信息或者启动所需资...
  • u012485637
  • u012485637
  • 2015-04-30 16:29
  • 256

Linux内核源码分析--内核启动命令行的传递过程(Linux-3.0 ARMv7)

Linux内核源码分析--内核启动命令行的传递过程(Linux-3.0 ARMv7) Linux内核在启动的时候需要一些参数,以获得当前硬件的信息或者启动所需资源在内存中的位置等等。这些信息可以通过...
  • gx19862005
  • gx19862005
  • 2014-11-12 09:48
  • 505

Linux内核源码分析--内核启动命令行的传递过程(Linux-3.0 ARMv7)

好文,不得不转!! (http://blog.chinaunix.net/uid-20543672-id-3151113.html) Linux内核在启动的时候需要一些参数,以获得...
  • cosmoslhf
  • cosmoslhf
  • 2013-12-05 09:33
  • 637

UBOOT之源码分析——向内核传送参数过程分析

U-boot会给LinuxKernel传递很多参数,如:串口,RAM,videofb、MAC地址等。而Linuxkernel也会读取和处理这些参数。两者之间通过structtag来传递参数。U-boo...
  • yakehy
  • yakehy
  • 2014-09-17 16:19
  • 525
    个人资料
    • 访问:143858次
    • 积分:3270
    • 等级:
    • 排名:第12051名
    • 原创:183篇
    • 转载:200篇
    • 译文:0篇
    • 评论:6条