2-4 UBoot源码分析1解析
uboot代码完全解析
目录
u-boot-1.1.6 之 cpu/arm920t........................................................................2 u-boot 中.lds 连接脚本文件的分析 ...................................................................................................12 分享一篇我总结的 uboot 学习笔记(转) .....................................................................................15 U-BOOT 内存布局及启动过程浅析 ...................................................................................................22 u-boot 中的命令实现 ..........................................................................................................................25 U-BOOT 环境变量实现 ........................................................................................................................28
U-Boot分析报告
cpu_init_f
其中cpu_init_f位于\cpu\mcf5227x\ 其中cpu_init_f位于\cpu\mcf5227x\cpu_init.c cpu_init_f位于 主要完成以下工作: 主要完成以下工作:
/* * Breath some life into the CPU * * Set up the memory map, * initialize a bunch of registers, * initialize the UPM's */
2.\lib_m68k\board.c系统初始化分析 2.\lib_m68k\board.c系统初始化分析
主要包括刚才涉及的两个函数: 主要包括刚才涉及的两个函数: 1. cpu_init_f 2. board_init_r 下面我们简要分析一下board.c 下面我们简要分析一下board.c
U-Boot的后续工作 Boot的后续工作
进入u boot主循环,并循环调用调用main_loop 进入u-boot主循环,并循环调用调用main_loop 主循环 Bootdelay到期后,会调用run_command函数, Bootdelay到期后,会调用run_command函数,自动执 到期后 run_command函数 bootcmd命令 行bootcmd命令 在run_command函数中调用函数指针cmdtp->cmd来启 run_command函数中调用函数指针cmdtp->cmd来启 函数中调用函数指针cmdtp do_bootm命令 动do_bootm命令 解析镜像的头部,需要解压的就调用解压缩函数解压, 解析镜像的头部,需要解压的就调用解压缩函数解压,就调 do_bootm_linux()去调用去加载linux系统镜像 去调用去加载linux 用do_bootm_linux()去调用去加载linux系统镜像 获取并设置Linux启动参数列表和机器号, 获取并设置Linux启动参数列表和机器号,最后调用函数指 Linux启动参数列表和机器号 针theKernel(0,machid,bd->bi_boot_params) theKernel(0,machid,bd-
uboot代码剖析
Uboot 代码剖析黄雪莉代码重定位编译器在编译一段程序链接过程中,要对所有目标文件进行重定位,建立符号引用规则,同时为变量,函数等分配地址。
程序执行时,把代码加载到链接时指定的地址空间,以保证程序在执行过程中对变量,函数等符号的正确引用,是程序正常运行。
但是在操作系统中,一个进程通常从硬盘等二级存储设备拷贝到内存中去执行,这两者的地址是不同的,因此操作系统要对这个进程进行重定位,才能正确运行该进程。
位置不相关代码:在设计系统引导程序如bootloader时,一般为了提高速度,需要将bootloader 从ROM拷贝到RAM中去执行,这两者的地址也不同。
如果这些代码即使不在链接时指定的地址空间也能正确运行,这就是位置无关代码(position independent code)。
PIC的特点是,它被加载到任意地址空间都可以正确的执行。
其原理是PIC对常量和函数入口地址的操作都是基于PC+偏移量的寻址方式。
即使程序被移动,但是PC也变化了,而偏移量是不变的,所以程序仍然可以找到正确的入口地址或者常量。
位置代码无关在U-boot中的实现:U-Boot中用GOT表(Global Offset Table 全局偏移量表)实现PIC代码位置无关,总的来讲,U-Boot依靠维护GOT表来实现,在GOT表中存放一些全局label 的表项,这些表项记录重要的地址;运行在Flash时,GOT表中存放的是编译时全局label的值(地址);当U-Boot运行时检测RAM大小进行代码搬运之后,利用代码搬运前后产生的地址偏移对(相对偏移)GOT表中的各个表项值进行更新,使其记录RAM中的相应的地址。
这样代码运行时不会出现代码/变量地址出错的问题。
主要代码剖析1.关于GOT的主要宏定义(include/ppc_asm.tmpl)2. .got2段的声明3.上电复位,从flash的起始地址读取硬件复位配置字HRCW(Hard Reset Configuration Word),每次都8位,每四次组成一个32位配置字,分别组成低32位配置字和高32位配置字,分别存放在CFG_HRCW_LOW 和CFG_HRCW_HIGH寄存HRCW控制时钟及其他硬件的功能,如PCI host和Agent模式,启动位置和大小端。
U-boot代码解析
u-boot源码解析u-boot介绍Uboot是德国DENX小组的开发用于多种嵌入式CPU的bootloader程序, UBoot不仅仅支持嵌入式Linux系统的引导,当前,它还支持NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS 嵌入式操作系统。
UBoot除了支持PowerPC系列的处理器外,还能支持MIPS、 x86、ARM、NIOS、XScale等诸多常用系列的处理器。
board:和一些已有开发板有关的文件。
每一个开发板都以一个子目录出现在当前目录中,子目录中存放与开发板相关的配置文件。
它的每个子文件夹里都有如下文件:makefileconfig.mksmdk2410.c 和板子相关的代码(以smdk2410为例)flash.c Flash操作代码memsetup.s 初始化SDRAM代码u-boot.lds 对应的连接文件common:实现uboot命令行下支持的命令,每一条命令都对应一个文件。
例如bootm命令对应就是cmd_bootm.c。
cpu:与特定CPU架构相关目录,每一款Uboot下支持的CPU在该目录下对应一个子目录,比如有子目录arm920t等。
cpu/ 它的每个子文件夹里都有如下文件:makefileconfig.mkcpu.c 和处理器相关的代码interrupts.c 中断处理代码serial.c 串口初始化代码start.s 全局开始启动代码disk:对磁盘的支持。
doc:文档目录。
Uboot有非常完善的文档,推荐大家参考阅读。
drivers:Uboot支持的设备驱动程序都放在该目录,比如各种网卡、支持CFI的Flash、串口和USB等。
fs: 支持的文件系统,Uboot现在支持cramfs、fat、fdos、jffs2和registerfs。
include:Uboot使用的头文件,还有对各种硬件平台支持的汇编文件,系统的配置文件和对文件系统支持的文件。
UBOOT源码分析
UBOOT源码分析UBOOT是一种开放源码的引导加载程序。
作为嵌入式系统启动的第一阶段,它负责初始化硬件设备、设置系统环境变量、加载内核镜像以及跳转到内核开始执行。
Uboot的源码是开放的,让我们可以深入了解其内部工作机制和自定义一些功能。
Uboot源码的文件组织结构非常清晰,主要分为三个大类:目录、文件和配置。
其中目录包含了一系列相关的文件,文件存放具体的源码实现代码,配置文件包含了针对特定硬件平台的配置选项。
Uboot源码的核心部分是启动代码,位于arch目录下的CPU架构相关目录中。
不同的CPU架构拥有不同的启动代码实现,如arm、x86等。
这些启动代码主要包括以下几个关键功能:1. 初始化硬件设备:Uboot首先需要初始化硬件设备,例如设置时钟、中断控制器、串口等设备。
这些初始化操作是在启动代码中完成的。
通过查看该部分代码,我们可以了解硬件的初始化过程,以及如何配置相关寄存器。
2. 设置启动参数:Uboot启动参数存储在一个称为"bd_info"的数据结构中,它包含了一些关键的设备和内存信息,例如DRAM大小、Flash 大小等。
这些参数是在启动代码中设置的,以便内核启动时能够正确识别硬件情况。
3. 加载内核镜像:Uboot负责加载内核镜像到内存中,以便内核可以正确执行。
在启动代码中,会通过读取Flash设备或者网络等方式,将内核镜像加载到指定的内存地址处。
加载过程中,可能会进行一些校验和修正操作,以确保内核数据的完整性。
4. 启动内核:在内核镜像加载完成后,Uboot会设置一些寄存器的值,并执行一个汇编指令,跳转到内核开始执行。
此时,Uboot的使命即结束,控制权交由内核处理。
除了启动代码,Uboot源码中还包含了许多其他功能模块,如命令行解析器、存储设备驱动、网络协议栈等。
这些功能模块可以根据需求进行配置和编译,以满足不同平台的需求。
例如,可以通过配置文件选择启用一些功能模块,或者自定义一些新的功能。
嵌入式linux开发uboot启动过程源码分析(一)
嵌⼊式linux开发uboot启动过程源码分析(⼀)⼀、uboot启动流程简介与⼤多数BootLoader⼀样,uboot的启动过程分为BL1和BL2两个阶段。
BL1阶段通常是开发板的配置等设备初始化代码,需要依赖依赖于SoC体系结构,通常⽤汇编语⾔来实现;BL2阶段主要是对外部设备如⽹卡、Flash等的初始化以及uboot命令集等的⾃⾝实现,通常⽤C语⾔来实现。
1、BL1阶段uboot的BL1阶段代码通常放在start.s⽂件中,⽤汇编语⾔实现,其主要代码功能如下: (1)指定uboot的⼊⼝。
在链接脚本uboot.lds中指定uboot的⼊⼝为start.S中的_start。
(2)设置异常向量(exception vector) (3)关闭IRQ、FIQ,设置SVC模式 (4)关闭L1 cache、设置L2 cache、关闭MMU (5)根据OM引脚确定启动⽅式 (6)在SoC内部SRAM中设置栈 (7)lowlevel_init(主要初始化系统时钟、SDRAM初始化、串⼝初始化等) (8)设置开发板供电锁存 (9)设置SDRAM中的栈 (10)将uboot从SD卡拷贝到SDRAM中 (11)设置并开启MMU (12)通过对SDRAM整体使⽤规划,在SDRAM中合适的地⽅设置栈 (13)清除bss段,远跳转到start_armboot执⾏,BL1阶段执⾏完2、BL2阶段start_armboot函数位于lib_arm/board.c中,是C语⾔开始的函数,也是BL2阶段代码中C语⾔的,同时还是整个u-boot(armboot)的主函数,BL2阶段的主要功能如下: (1)规划uboot的内存使⽤ (2)遍历调⽤函数指针数组init_sequence中的初始化函数 (3)初始化uboot的堆管理器mem_malloc_init (4)初始化SMDKV210开发板的SD/MMC控制器mmc_initialize (5)环境变量重定位env_relocate (6)将环境变量中⽹卡地址赋值给全局变量的开发板变量 (7)开发板硬件设备的初始化devices_init (8)跳转表jumptable_init (9)控制台初始化console_init_r (10)⽹卡芯⽚初始化eth_initialize (11)uboot进⼊主循环main_loop⼆、uboot程序⼊⼝分析1、link.lds链接脚本⽂件分析u-boot.lds⽂件是uboot⼯程的链接脚本⽂件,位于board\samsung\smdkc110⽬录下,对于⼯程项⽬编译后期的链接阶段⾮常重要,决定了uboot程序的组装。
uboot源码分析(2)uboot环境变量实现简析
uboot源码分析(2)uboot环境变量实现简析uboot 环境变量实现简析----------基于u-boot-2010.03u-boot的环境变量是使⽤u-boot的关键,它可以由你⾃⼰定义的,但是其中有⼀些也是⼤家经常使⽤,约定熟成的,有⼀些是u-boot⾃⼰定义的,更改这些名字会出现错误,下⾯的表中我们列出了⼀些常⽤的环境变量:bootdelay 执⾏⾃动启动的等候秒数baudrate 串⼝控制台的波特率netmask 以太⽹接⼝的掩码ethaddr 以太⽹卡的⽹卡物理地址bootfile 缺省的下载⽂件bootargs 传递给内核的启动参数bootcmd ⾃动启动时执⾏的命令serverip 服务器端的ip地址ipaddr 本地ip 地址stdin 标准输⼊设备stdout 标准输出设备stderr 标准出错设备上⾯只是⼀些最基本的环境变量,请注意,板⼦⾥原本是没有环境变量的,u-boot的缺省情况下会有⼀些基本的环境变量,在你执⾏了saveenv之后,环境变量会第⼀次保存到flash或者eeprom中,之后你对环境变量的修改,保存都是基于保存在flash中的环境变量的操作。
环境变量可以通过printenv命令查看环境变量的设置描述,通过setenv 命令进⾏重新设置,设置完成后可以通过saveenv将新的设置保存在⾮易失的存储设备中(nor flash 、nand flash 、eeprom)。
例如:setenv bootcmd "nand read 0x30008000 0x80000 0x500000;bootm 0x30008000"saveenv通过这两条命令就完成了环境变量bootcmd的重新设置,并讲其保存在固态存储器中。
下⾯简单分析下uboot中环境变量的实现流程。
uboot启动后,执⾏玩start.S中的汇编程序,将跳⼊board.c 中定义的start_arm_boot()函数中,在该函数中,uboot讲完成板⼦外设和相关系统环境的初始化,然后进⼊main_loop循环中进⾏系统启动或者等待与⽤户交互,这其中就包括环境变量的初始化和重定位。
uboot源码分析
U-Boot源码分析(u-boot-2009.03)hzb我们开始学习uboot,对于linux我还是个新手,在这只是对学习uboot做下笔记,文中错误之处请谅解。
一、cpu/arm920t/start.S分析#include<config.h>@该文件是第二步中mkconfig文件执行时创建的。
include/config.h#include<version.h>@global声明一个符号可被其他文档引用,相当于声明了一个全局变量。
@该部分为处理器的异常处理向量表。
地址范围为0x00000000~0x00000020,刚好8条指令。
.globl_start_start:b reset@uboot的主入口,跳到后面的标号reset处执行ldr pc,_undefined_instructionldr pc,_software_interruptldr pc,_prefetch_abortldr pc,_data_abortldr pc,_not_usedldr pc,_irqldr pc,_fiq@.word为定义一个4字节的空间_undefined_instruction:.word undefined_instruction_software_interrupt:.word software_interrupt_prefetch_abort:.word prefetch_abort_data_abort:.word data_abort_not_used:.word not_used_irq:.word irq_fiq:.word fiq.balignl16,0xdeadbeef_TEXT_BASE:.word TEXT_BASE@由链接器脚本决定,在/borad/samsung/smdk2410/config.mk.globl_armboot_start_armboot_start:.word_start@_start是在起始代码处定义的标号,当跳到_armboot_start后还是会跳转到_start .globl_bss_start_bss_start:.word__bss_start@在board/samsung/smdk2410/u-boot.lds中定义了__bss_start.globl_bss_end_bss_end:.word_end@在board/samsung/smdk2410/u-boot.lds中定义了__bss_start#ifdef CONFIG_USE_IRQ@这个宏在include/configs/smdk2410.h中定义,可以取消。
Uboot代码分析
UBOOT分析报告整理修改中2011-3-10目录Uboot介绍 (2)Uboot 启动流程 (2)I.Uboot启动过程 (2)II.Uboot启动汇编代码部分 (3)III.Uboot启动C代码部分 (4)IV.Uboot中初试环境变量位置及调整方法 (6)V.Uboot c代码中gd(全局数据)的保存位置 (6)Uboot的编译生成 (6)Uboot 汇编代码探究 (6)Uboot C代码探究 (6)一、Uboot下命令实现 (6)二、env_* 环境变量操作函数实现(如saveenv) (7)1、env_sf.c环境变量要保存在spi flash时调用 (7)Uboot 内部宏定义 (7)1.DECLARE_GLOBLE_DATA_PTR (7)2. CONFIG_ENV_ADDR (8)3. CONFIG_ENV_OFFSET (8)4. CONFIG_ENV_SECT_SIZE (8)5. CONFIG_ENV_IS_EMBEDDED (8)6. CONFIG_ENV_IS_IN_NAND (9)Uboot 目录结构功能 (10)Uboot介绍Uboot全写Universal Boot Loader,是芯片加电或复位后进入操作系统之前运行的一段代码,用于完成从硬件到操作系统的过度。
Uboot 启动流程I.Uboot启动过程Uboot启动过程主要分为7块:1.CPU初始化:设置CPU工作模式与工作频率2.时钟、串口、内存初始化3.划分内存:分配堆、栈,设置环境变量位置、Uboot自身代码位置、指定程序代码入口4.根据Uboot启动选项将自身加载至内存5.加载环境变量6.初始化flash pci以及网口等7.进入命令行或者根据环境变量启动Linux的kernelUboot的启动过程中会有两大步骤,一部分是汇编代码部分,一部分是C代码部分,由于运行C代码部分需要配置堆栈所以前一部分初始化主要由汇编语言完成。
uboot命令解释与运行分析
uboot命令解释与运行分析题记: 省略200字这一回来分析一下uboot中命令行的解释, 所以我们直接从main_loop开始分析.1. 从汇编阶段进入c阶段的第一个函数是start_xxx, 如/lib_unicore/board.c中的start_unicoreboot. 前半部分调用了若干初始化函数来进行部分硬件的初始化, 并设置一下环境. 这里不是我们本回要讨论的所以一一跳过. 在start_xxx的最后调用了main_loop(), 而且还是被一个死循环死死圈住了;2. 现在我们已经进入了这个圈套那么只能往里钻了. common/main.c文件中的main_loop().上面代码主要是对自启动部分的描述, 其中命令执行部分是在run_command中进行的, 这个等在后文分析. 如果我们没有bootcmd 或者在延时中被打断, 那么代码会继续向下执行3.read_line()读取到命令行后会调用common/main.c文件中的run_command().现在是分析run_command()的时候了,不管是从环境变量还是终端获得命令,都是由run_command()来处理的.中场休息,下面要进入处理cmdbuf的循环中了, 长征马上开始以;分割. 忽略'\;'for(inquotes = 0, sep = str;*sep; sep++){if((*sep=='\'')&&(*(sep-1)!='\\'))inquotes=!inquotes;if(!inquotes &&(*sep ==';')&&( sep != str)&&(*(sep-1)!='\\'))break;}//如果上面for循环找到一条以';'结束的命令, 那么sep指向命令末尾token = str;if(*sep){str = sep + 1;*sep ='\0';}elsestr = sep;process_macros (token, finaltoken);if((argc = parse_line (finaltoken, argv))== 0){rc =-1;4.就此打断一下, 我们要分析一下find_cmd了, 不能再跳过了. find_cmd()在.u_boot_cmd段中寻找该命令的cmd_tbl_t结构, 找到后返回该结构. 该命令的结构是通过定义在include/command.h中的宏定义U_BOOT_CMD登记进.u_boot_cmd段中的.5. 刚才我们在长征的半路翻越了一座雪山, 现在继续回到while循环中if(cmdtp->cmd == do_bootd){if(flag & CMD_FLAG_BOOTD){puts("'bootd' recursion detected\n");rc =-1;continue;}else{flag |= CMD_FLAG_BOOTD;}}#endif//长征马上结束, 胜利就在眼前! 调用结构体中注册的cmd函数, 何时注册的呢? 上面不远处介绍的U_BOOT_CMD!if((cmdtp->cmd)(cmdtp, flag, argc, argv)!= 0){ rc =-1;}repeatable &= cmdtp->repeatable;if(had_ctrlc ())return-1;}。
uboot代码详解
.wordTEXT_BASE
//声明_armboot_start并用_start来进行初始化,在board/u-boot.lds中定义。
.globl _armboot_start
_armboot_start:
.word _start
/*
* These are defined in the board-specific linker script.
# define CLKDIVN0x4C000014/* clock divisor register */
#endif
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]
.globl _bss_start
_bss_start:
.word __bss_start
.globl _bss_end
_bss_end:
.word _end
.globl FREE_RAM_END
FREE_RAM_ENREE_RAM_SIZE
FREE_RAM_SIZE:
#if defined(CONFIG_S3C2400)
# define pWTCON0x15300000
# define INTMSK0x14400008/* Interupt-Controller base addresses */
# define CLKDIVN0x14800014/* clock divisor register */
* but WITHOUT ANY WARRANTY; without even the implied warranty of
(三)uboot源码分析
(三)uboot源码分析⼀、九⿍官⽅uboot和三星原版uboot对⽐(1)以九⿍官⽅的uboot为蓝本来学习的,以三星官⽅的这份为对照。
(2)不同版本的uboot或者同⼀版本不同⼈移植的uboot,可能⽬录结构和⽂件内容都有所不同。
将来⼤家懂了后也可以⾃⼰根据需要去添加/删除/更改⽬录结构。
(3)九⿍在以三星的uboot为原材料进⾏移植时,把三星版本的uboot中很多不必要的⽂件夹、⽂件给删除掉了。
这个删除把很多完全⽤不到的⽂件清除出去,减少了整体的⽂件数量,便于⼯作。
⼆、各⽂件介绍(1).gitignore。
git⼯具的⽂件,git是⼀个版本管理⼯具(类似的还有个svn),这个⽂件和git有关,和uboot本⾝⽆关的,不⽤去管。
(2)arm_config.mk。
后缀是.mk,是⼀个Makefile⽂件,将来在某个Makefile中会去调⽤它。
(3)三个Changelog⽂件,修改记录⽂件,该⽂件记录了这个uboot项⽬的版本变迁以及每个版本较上个版本修改的记录。
正式的项⽬都有这些记录的。
可以直接忽略,主要是给维护uboot的⼈⽤的。
(4)config.mk。
和arm_config.mk差不多性质。
(5)COPYING。
版权声明,uboot本⾝是GPL许可证的。
(6)CREDITS。
鸣谢,⾥⾯记录了对uboot有贡献的⼈,感谢⽬录。
(7)image_split。
⼀个脚本,看说明是⽤来分割uboot.bin到BL1的,暂时⽤不到,先不管。
(8)MAINTAINERS。
维护者,就是当前在参与维护uboot源码的社区⼯作者。
(9)MAKEALL。
⼀个脚本,应该是帮助编译uboot的。
(10)Makefile。
这个很重要,是uboot源代码的主Makefile,将来整个uboot被编译时就是⽤这个Makefile管理编译的,所以我们在下个课程中研究uboot 配置编译过程时就要分析这个Makefile。
u-boot源码分析
[在此处输入文章标题]U-Boot启动内核的过程可以分为两个阶段,两个阶段的功能如下:(1)第一阶段的功能硬件设备初始化加载U-Boot第二阶段代码到RAM空间设置好栈跳转到第二阶段代码入口(2)第二阶段的功能初始化本阶段使用的硬件设备检测系统内存映射将内核从Flash读取到RAM中为内核设置启动参数调用内核1.1.1U-Boot启动第一阶段代码分析第一阶段对应的文件是cpu/arm920t/start.S和board/samsung/mini2440/lowlevel_init.S。
U-Boot启动第一阶段流程如下:图 2.1 U-Boot启动第一阶段流程(先列出u-boot在ARM 处理器启动中的几个关键点:系统上电:_start标号 cpu/arm920t/start.Scpu/arm920t/start.S标号 cpu/arm920t/start.S标号 board/smdk2410/low_level_init.S标号cpu/arm920t/start.S_start_arm_boot标号cpu/arm920t/start.S函数lib_arm/board.c函数common/main.c命令行㈠Start.S是u-boot整个程序的入口,该文件使用汇编语言编写,不同体系结构的启动代码是不同的;low_level_init.S是特定开发板的设置代码;board.S包含开发板底层设备驱动;main.C是一个与平台无关的代码,u-boot应用程序的入口在此文件中。
)根据caojing/u-boot-1.1.6/board/TX2440/u-boot.lds中指定的连接方式:OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/OUTPUT_ARCH(arm)ENTRY(_start)SECTIONS{. = 0x00000000;. = ALIGN(4);.text :{cpu/arm920t/start.o (.text)board/TX2440/lowlevel_init.o (.text) board/TX2440/nand_read.o (.text)*(.text)}. = ALIGN(4);.rodata : { *(.rodata) }. = ALIGN(4);.data : { *(.data) }. = ALIGN(4);.got : { *(.got) }. = .;__u_boot_cmd_start = .;.u_boot_cmd : { *(.u_boot_cmd) }__u_boot_cmd_end = .;. = ALIGN(4);__bss_start = .;.bss : { *(.bss) }_end = .;} 第一个链接的是cpu/arm920t/start.o,因此u-boot.bin的入口代码在cpu/arm920t/start.o中,其源代码在cpu/arm920t/start.S中。
Uboot源代码学习
Uboot MakeFile源码学习这里主要涉及到如下几个文件:主目录中的Makfile、mkconfig、config.mk以及各子目录中的Makefile。
因为子目录中Makefile 太多,所以本文中以lib_arm目录中的Makefile为例进行分析。
首先大概介绍一下这几个文件。
主目录中的Makefile是对整个工程的编译链接规则进行了描述。
子目录中的Makfile主要是编译一些源文件并进行归档,生成一些静态库。
config.mk定义了主目录和子目录makefile通用的变量。
Mkconfig是个脚本文件,负责对主目录中makefile进行配置的文件。
创建一些符号链接,并在include目录下创建了两个文件:config.mk和config.h。
config.mk包含了uboot运行的环境,包括体系结构、处理器和板子。
Config.h中指明了板子相关的配置头文件。
下面对源码进行分析HOSTARCH := $(shell uname -m | \sed -e s/i.86/i386/ \-e s/sun4u/sparc64/ \-e s/arm.*/arm/ \-e s/sa110/arm/ \-e s/powerpc/ppc/ \-e s/macppc/ppc/)HOSTOS := $(shell uname -s | tr A-Z a-z | \sed -e 's/\(cygwin\).*/cygwin/')这里是输出两个变量:主机体系结构和主机所用操作系统。
TOPDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)export TOPDIR输出uboot所在的当前目录。
include include/config.mkexport ARCH CPU BOARD VENDOR# load other configurationinclude $(TOPDIR)/config.mk加载包含一些变量的两个config.mk文件。
Uboot关键代码的理解
Uboot关键代码的理解1. u-boot程序的入口地址要理解程序的入口地址,自然想到的是连接文件,首先看连接文件"/board/smdk2410/u-boot.lds"ENTRY(_start)SECTIONS{. = 0x00000000;. = ALIGN(4);.text :{cpu/arm920t/start.o (.text)*(.text)}. = ALIGN(4);.rodata : { *(.rodata) }. = ALIGN(4);.data : { *(.data) }. = ALIGN(4);.got : { *(.got) }__u_boot_cmd_start = .;.u_boot_cmd : { *(.u_boot_cmd) }__u_boot_cmd_end = .;. = ALIGN(4);__bss_start = .;.bss : { *(.bss) }_end = .;}(1) 从ENTRY(_start)可以看出u-boot的入口函数是_start(2) 从. = 0x00000000也许可以看出_start的地址是0x00000000,事实并不是这样的,这里的0x00000000无效,在连接的时候最终会被TETX_BASE所代替的,具体请参考u-boot 根目录下的config.mk.(3) 网上很多说法是 _start=TEXT_BASE,我想这种说法也是正确的,实际上,不是TEXT_BASE这段代码映射到0x0的地方,其实编译器进行编译,是按照链接文件进行的。
也就是说,编译的时候所有的地址都是相对于TEXT_BASE计算出来的。
而这个地址是在连接文件里面指定的为0x338f0000,你可以看链接文件,可以看反汇编里面的地址,全是0x33f8XXXX的地址。
2. SDRAM初始化,lowleverl_init.S_TEXT_BASE:.word TEXT_BASE.globl lowlevel_initlowlevel_init:/* memory control configuration *//* make r0 relative the current location so that it *//* reads SMRDATA out of FLASH rather than memory ! */ldr r0, =SMRDATAldr r1, _TEXT_BASEsub r0, r0, r1ldr r1, =BWSCON /* Bus Width Status Controller */add r2, r0, #13*4不理解SMRDATA与_TEXT_BASE这两个地址相减之后,到底是一个什么值。
uboot第二阶段代码详细分析
uboot第二阶段代码详细分析Stage2 C语言代码部分lib_arm/board.c中的start arm boot是C语言开始的函数也是整个启动代码中C语言的主函数,同时还是整个u-boot(armboot)的主函数,该函数只要完成如下操作:(1)调用一系列的初始化函数。
(2)初始化Flash设备。
(3)初始化系统内存分配函数。
(4)如果目标系统拥有NAND设备,则初始化NAND设备。
(5)如果目标系统有显示设备,则初始化该类设备。
(6)初始化相关网络设备,填写IP、MAC地址等。
(7)进去命令循环(即整个boot的工作循环),接受用户从串口输入的命令,然后进行相应的工作。
对于内核启动来说,这部分主要是完成全局数据gd的初始化,以便内核访问start_armboot是U-Boot执行的第一个C语言函数,完成系统初始化工作,进入主循环,处理用户输入的命令。
这里只简要列出了主要执行的函数流程:void start_armboot (void){init_fnc_t **init_fnc_ptr;char *s;#ifndef CFG_NO_FLASHulong size;#endif#if defined(CONFIG_VFD) || defined(CONFIG_LCD)unsigned long addr;#endif/* Pointer is writable since we allocated a register for it *///获取全局gd指针gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));/* compiler optimization barrier needed for GCC >= 3.4 */ __asm__ __volatile__("": : :"memory");//清空该结构体memset ((void*)gd, 0, sizeof (gd_t));//获取bd_info结构体指针gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));memset (gd->bd, 0, sizeof (bd_t));gd->flags |= GD_FLG_RELOC; //标志位已经重定向//整个代码区的长度monitor_flash_len = _bss_start - _armboot_start;//调用初始化函数,用来初始化gd结构体for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {if ((*init_fnc_ptr)() != 0) {hang ();}}#ifndef CFG_NO_FLASH/* configure available FLASH banks *///board/smdk2410/flash.c配置flash//从其实现来看,好像只是配置nor flashsize = flash_init ();//初始化flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS],nor flash基地址和扇区大小//显示flash信息display_flash_config (size);#endif /* CFG_NO_FLASH *///定义显示类型#ifdef CONFIG_VFD# ifndef PAGE_SIZE# define PAGE_SIZE 4096# endif/** reserve memory for VFD display (always full pages)*//* bss_end is defined in the board-specific linker script *///按页对其方式保留显存addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); size = vfd_setmem (addr);gd->fb_base = addr;//帧缓冲基地址#endif /* CONFIG_VFD *///显示器为LCD,同上#ifdef CONFIG_LCD# ifndef PAGE_SIZE# define PAGE_SIZE 4096# endif/** reserve memory for LCD display (always full pages)*//* bss_end is defined in the board-specific linker script */ addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); size = lcd_setmem (addr);gd->fb_base = addr;#endif /* CONFIG_LCD *///初始化CFG_MALLOC_LEN大小空间/* armboot_start is defined in the board-specific linker script*/mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);//初始化nand flash,这是在nand flash启动的s3c2410移植u-boot的关键,根据flash时序编写函数即可//在include/configs/smdk2410.h中的command definition中增加CONFIG_COMMANDS和CFG_CMD_NAND命令#if (CONFIG_CMD_NAND)puts ("NAND: ");nand_init(); //board/smdk2410/smdk2410.c,获取nand的基地址和大小信息#endif#ifdef CONFIG_HAS_DATAFLASHAT91F_DataflashInit();dataflash_print_info();#endif/* initialize environment *///初始化环境参数env_relocate ();//framebuffer初始化#ifdef CONFIG_VFD/* must do this after the framebuffer is allocated */drv_vfd_init();#endif /* CONFIG_VFD *///通过命令行参数传递获取ip地址/* IP Address */gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");//调用相应驱动函数对硬件设备进行初始化stdio_init (); /* get the devices list going标准输入输出和设备初始化. */#ifdef CONFIG_CMC_PU2load_sernum_ethaddr ();#endif /* CONFIG_CMC_PU2 */jumptable_init ();//初始化串口console_init_r (); /* fully init console as a device */#if defined(CONFIG_MISC_INIT_R)/* miscellaneous platform dependent initialisations */misc_init_r ();#endif/* enable exceptions *///启用中断enable_interrupts ();/* Perform network card initialisation if necessary *///初始化网卡#ifdef CONFIG_DRIVER_CS8900cs8900_get_enetaddr (gd->bd->bi_enetaddr);#endif#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)if (getenv ("ethaddr")) {smc_set_mac_addr(gd->bd->bi_enetaddr);#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 *//* Initialize from environment */if ((s = getenv ("loadaddr")) != NULL) {load_addr = simple_strtoul (s, NULL, 16);}#if (CONFIG_COMMANDS & CFG_CMD_NET)if ((s = getenv ("bootfile")) != NULL) {copy_filename (BootFile, s, sizeof (BootFile));}#endif /* CFG_CMD_NET */#ifdef BOARD_LATE_INITboard_late_init ();#endif#if (CONFIG_COMMANDS & CFG_CMD_NET)#if defined(CONFIG_NET_MULTI)puts ("Net: ");#endifeth_initialize(gd->bd);#endif/* main_loop() can return to retry autoboot, if so just run it again. */for (;;) {main_loop ();}//end start_armboot//下面详细分析下init_sequencetypedef int (init_fnc_t) (void); //注意这种用法,linux内核中也经常使用int print_cpuinfo (void);init_fnc_t *init_sequence[] = {#if defined(CONFIG_ARCH_CPU_INIT)arch_cpu_init, /* basic arch cpu dependent setup //cpu/arm920t/cpu.c中定义,该函数为空,因为没有采用IRQ或FIQ模式*/#endifboard_init, /* basic board dependent ,初始化时钟频率,配置IO口,初始化全局数据bd(如平台号,传递内核参数的地址),setup //board/smdk2410/smdk2410.c */#if defined(CONFIG_USE_IRQ)interrupt_init, /* set up exceptions */#endiftimer_init, /* initialize timer 使用定时器 4 cpu/arm920t/s3c24x0/timer.c */#ifdef CONFIG_FSL_ESDHCget_clocks,#endifenv_init, /* initialize environment common/Env_nand.c 校验环境变量,并获取环境变量的地址 */init_baudrate, /* initialze baudrate settings 获取波特率环境变量,初始化全局数据的中波特率 /lib_arm/board.c */ serial_init, /* serial communications setup driver/serial/serial_s3c24x0.c 初始化串口0,用于打印信息,该平台只支持配置串口1来打印信息 */console_init_f, /* stage 1 init of console */display_banner, /* say that we are here 打印uboot代码段和数据段地址信息 */#if defined(CONFIG_DISPLAY_CPUINFO)print_cpuinfo, /* display cpu info (and speed) */#endif#if defined(CONFIG_DISPLAY_BOARDINFO)checkboard, /* display board info */#endif#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C) init_func_i2c,#endifdram_init, /* configure available RAM ,获取ram的地址和大小,banks board/sunsang/smdk2410/smdk2410.c*/ #if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)arm_pci_init,#endif//打印BANK的相关信息display_dram_config, //lib_arm/board.cNULL,};int board_init (void){;将时间相关的寄存器定义为结构体S3C24X0_CLOCK_POWER,S3C24X0_GPIO也是一样S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();;设置cpu时钟/* to reduce PLL lock time, adjust the LOCKTIME register */ clk_power->LOCKTIME = 0xFFFFFF;/* configure MPLL *///M_MDIV=0xA1,M_PDIV=0x3,M_SDIV=0x1//这样系统时钟为202.80Mclk_power->MPLLCON = ((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV);/* some delay between MPLL and UPLL */delay (4000);;USB时钟为48M/* configure UPLL */clk_power->UPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV);/* some delay between MPLL and UPLL */delay (8000);;设置GPIO/* set up the I/O ports */gpio->GPACON = 0x007FFFFF;gpio->GPBCON = 0x00044555;gpio->GPBUP = 0x000007FF;gpio->GPCCON = 0xAAAAAAAA;gpio->GPCUP = 0x0000FFFF;gpio->GPDCON = 0xAAAAAAAA;gpio->GPDUP = 0x0000FFFF;gpio->GPECON = 0xAAAAAAAA;gpio->GPEUP = 0x0000FFFF;gpio->GPFCON = 0x000055AA;gpio->GPFUP = 0x000000FF;gpio->GPGCON = 0xFF95FFBA;gpio->GPGUP = 0x0000FFFF;gpio->GPHCON = 0x002AFAAA;gpio->GPHUP = 0x000007FF;;初始化bd结构体中的bi_arch_number和bi_boot_params/* arch number of SMDK2410-Board 平台号,定义在include/asm-arm/mach-types.h */gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;/* adress of boot parameters,内核启动时,传递给内核的参数*/gd->bd->bi_boot_params = 0x30000100;;启用指令和数据cache;通过对协处理器的操作了实现cache的使能icache_enable();dcache_enable();return 0;} //end board_initint timer_init(void){;获取计时控制寄存器struct s3c24x0_timers *timers = s3c24x0_get_base_timers();ulong tmr;;使用PWM定时器4/* use PWM Timer 4 because it has no output *//* prescaler for Timer 4 is 16 */writel(0x0f00, &timers->TCFG0);if (timer_load_val == 0) {/** for 10 ms clock period @ PCLK with 4 bit divider = 1/2* (default) and prescaler = 16. Should be 10390* @33.25MHz and 15625 @ 50 MHz*/timer_load_val = get_PCLK() / (2 * 16 * 100);timer_clk = get_PCLK() / (2 * 16);}/* load value for 10 ms timeout */lastdec = timer_load_val;writel(timer_load_val, &timers->TCNTB4);/* auto load, manual update of Timer 4 */tmr = (readl(&timers->TCON) & ~0x0700000) | 0x0600000; writel(tmr, &timers->TCON);/* auto load, start Timer 4 启用定时器4做为系统定时器 */ tmr = (tmr & ~0x0700000) | 0x0500000;writel(tmr, &timers->TCON);timestamp = 0;return (0);} //end timer_initstatic int env_init (void){//这个是自己修改的,和源码有所不同if(pbootflag==1) //by lht 这种情况是从nor启动{env_name_spec = "NOR";env_ptr=(env_t *)CONFIG_ENV_ADDR;//#defineCONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x0F0000) /* addr of environment */return nor_env_init();}else // 从nand 启动{#if defined(ENV_IS_EMBEDDED) || defined(CONFIG_NAND_ENV_DST)int crc1_ok = 0, crc2_ok = 0;env_t *tmp_env1;#ifdef CONFIG_ENV_OFFSET_REDUNDenv_t *tmp_env2;tmp_env2 = (env_t *)((ulong)env_ptr + CONFIG_ENV_SIZE);crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);#endiftmp_env1 = env_ptr;crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);if (!crc1_ok && !crc2_ok) {gd->env_addr = 0;gd->env_valid = 0;return 0;} else if (crc1_ok && !crc2_ok) {gd->env_valid = 1;}#ifdef CONFIG_ENV_OFFSET_REDUNDelse if (!crc1_ok && crc2_ok) {gd->env_valid = 2;} else {/* both ok - check serial */if(tmp_env1->flags == 255 && tmp_env2->flags == 0)gd->env_valid = 2;else if(tmp_env2->flags == 255 && tmp_env1->flags == 0) gd->env_valid = 1;else if(tmp_env1->flags > tmp_env2->flags)gd->env_valid = 1;else if(tmp_env2->flags > tmp_env1->flags)gd->env_valid = 2;else /* flags are equal - almost impossible */gd->env_valid = 1;}if (gd->env_valid == 2)env_ptr = tmp_env2;else#endifif (gd->env_valid == 1)env_ptr = tmp_env1;gd->env_addr = (ulong)env_ptr->data;#else /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */ gd->env_addr = (ulong)&default_environment[0]; //使用默认环境变量,定义在common/env_common.cgd->env_valid = 1;#endif /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */ }return (0);} //end env_init//如果参数中设置了波特率则利用参数用设置的波特率,否则利用默认的CONFIG_BAUDRATE(115200)static int init_baudrate (void){char tmp[64]; /* long enough for environment variables */ int i = getenv_r ("baudrate", tmp, sizeof (tmp));gd->bd->bi_baudrate = gd->baudrate = (i > 0)(int) simple_strtoul (tmp, NULL, 10): CONFIG_BAUDRATE;return (0);} //end init_baudrate//初始化ram信息,设置起始地址和大小,从include/configs/s mdk2410.h中获取这些信息//,这里只是对gd中的 bi_dram结构中的两个成员赋值,//也即BANK的起始地址和大小int dram_init (void){gd->bd->bi_dram[0].start = PHYS_SDRAM_1;gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;return 0;} // end dram_init//显示ram信息,其中的宏也是从include/configs/smdk2410.h中读取static int display_dram_config (void){int i;#ifdef DEBUGputs ("RAM Configuration:n");for(i=0; i<CONFIG_NR_DRAM_BANKS; i++) {printf ("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start);print_size (gd->bd->bi_dram[i].size, "n");}#elseulong size = 0;for (i=0; i<CONFIG_NR_DRAM_BANKS; i++) {size += gd->bd->bi_dram[i].size;}puts("DRAM: ");print_size(size, "n");#endifreturn (0);} //end display_dram_config//以上都是一些初始化的函数,可以看出以上这些函数都是为了初始化一个全局的结构体变量gd而执行的,//该变量地址由寄存器r8指向,该结构体定义了开发板的相关硬件配置,在include/asm-arm/global_data.h中//定义typedef struct global_data {bd_t *bd; 板子数据指针unsigned long flags; //指示标志,如设备已经初始化标志等unsigned long baudrate; /* 串口初始化标志*/unsigned long have_console; /* serial_init() was called */unsigned long env_addr; /* 环境变量的起始地址 */unsigned long env_valid; /* 校验环境变量有效性的标志位*/unsigned long fb_base; /* base address of frame buffer 帧缓冲基地址*/#ifdef CONFIG_VFDunsigned char vfd_type; /* display type lcd显示设备类型 */ #endif#ifdef CONFIG_FSL_ESDHCunsigned long sdhc_clk;#endifvoid **jt; /* jump table */} gd_t;typedef struct bd_info {int bi_baudrate; /* serial console baudrate */unsigned long bi_ip_addr; /* IP Address IP地址*/struct environment_s *bi_env;ulong bi_arch_number; /* unique id for this board 唯一的平台号 */ulong bi_boot_params; /* where this board expects params 启动参数的地址*/struct /* RAM configuration ram配置:起始地址和大小*/{ulong start;ulong size;} bi_dram[CONFIG_NR_DRAM_BANKS];} bd_t;typedef struct environment_s {uint32_t crc; /* CRC32 over data bytes 校验码 */#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENTunsigned char flags; /* active/obsolete flags 是否有效标志位*/#endifunsigned char data[ENV_SIZE]; /* Environment data *//**#define ENV_SIZE (CONFIG_ENV_SIZE - ENV_HEADER_SIZE) #define CONFIG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */#defineCONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x030000) /* addr ofenvironment */} env_t;环境变量指针env_t *env_ptr = (env_t*)(&environment[0]);(common/env_flash.c)env_ptr指向环境参数区,系统启动时默认的环境参数environment[],定义在common/environment.c中。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
struct tag_பைடு நூலகம்eader { u32 size; u32 tag; };
//每个参数的大小 //每个参数的类型
do_bootm_linux流程
• 在do_bootm_linux函数(Uboot/lib_arm/bootm.c)中定义函 数指针theKernel函数指针,并通过读取Linux的内核镜像文 件uImage前面的40字节内容获取Linux内核的入口地址 – theKernel = (void (*)(int, int, uint))images->ep;
• UBoot如何给内核传递参数?
– UBoot和内核交互是单向的,两个程序不能同时运行,那么要实 现参数传递只能通过把参数存放到一个固定内存位置然后调用 theKernel函数给对R0,R1,R2寄存器赋值。Linux启动调用 start_kernel函数读取内容即可。
do_bootm_linux函数
• UBoot如何调用Linux内核?
– UBoot通过命令把Linux内核镜像文件从Flash中读取到内存的某一 位置,然后设置PC寄存器执向该位置UBoot调用Linux内核的
前提条件是?
– R0 =0 – R1=适当的机器码 机器码的位置存放在 linux/arch/arm/tools/mach-type文件中 – R2 =启动参数标记列表在内存中的位置 – CPU必须设置为SVC模式并关闭中断 – MMU必须关闭
theKernel (0, machid, bd->bi_boot_params); //启动Linux内核
theKernel函数
• 参数 zero:设置为0 R0寄存器为0 • 参数:arch 表示机器存储于R1寄存器中 • 参数:params用于传递给Linux的参数地址 (包括命令行参数信息)
• do_bootm_linux是UBoot真正启动Linux的 函数(位于UBoot所在目录/lib_arm/bootm.c)
int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) { bd_t *bd = gd->bd; char *s; int machid = bd->bi_arch_number; void (*theKernel)(int zero, int arch, uint params); .................. theKernel = (void (*)(int, int, uint))images->ep; //传递Linux内核首地址
tag结构体
struct tag { struct tag_header hdr; union { struct tag_core struct tag_mem32 struct tag_videotext struct tag_ramdisk struct tag_initrd struct tag_serialnr struct tag_revision struct tag_videolfb struct tag_cmdline 。。。。。。。 struct tag_memclk } u; }; core; //列表的开始 mem; //描述内存信息 videotext; // ramdisk; initrd; serialnr; //串口信息 revision; //版本信息 videolfb; cmdline; //命令行 memclk; //内存时钟
tag_list参数列表
• UBoot如何组织这么多的参数信息呢?
– UBoot使用struct tag 和struct tag_head来描述这些参数信息。存放位置 (include/asm-arm/setup.h) – 相对应的在Linux内核源代码中也有完全相同的结构体定义存放位置 (linux/arch/arm/include/asm/setup.h) – – – – – – – – – #define ATAG_CORE 0x54410001 #define ATAG_MEM 0x54410002 #define ATAG_VIDEOTEXT 0x54410003 #define ATAG_RAMDISK 0x54410004 #define ATAG_INITRD 0x54410005 #define ATAG_SERIAL 0x54410006 #define ATAG_REVISION 0x54410007 #define ATAG_CMDLINE 0x54410009 #define ATAG_NONE 0x000000001
– 编译Linux内核时可以通过make menuconfig命 令进行命令行参数的配置 – Uboot引导的时候传递启动参数参数地址给内 核。
命令行参数
参数信息
• u-boot要传递给内核的参包含哪些内容?
– MACH_TYPE(即我们所说的机器码)、 – 命令行参数CommandLine – 系统根设备信息(标志,页面大小)、 – 内存信息(起始地址,大小)、 – RAMDISK信息(起始地址,大小)、压缩的 RAMDISK根文件系统信息(起始地址,大小)。 由此可见要传递的参数很多
• UBoot源码解析(一)
主要内容
• 分析UBoot是如何引导Linux内核 • UBoot Makefile分析 • UBoot源码的一阶段解析
UBoot存储空间分布
• UBoot是用来引导OS系统启动,那么它是如何引 导OS启动的呢?
启动参数
内核
根文件系统
bootloader
UBoot和内核的交互
(*theKernel)(int zero, int arch, uint params);
启动参数
• Linux内核启动的时候并不会自己去扫描硬 件的基本信息,因为它启动时都已经假设硬 件都已经准备好了,但是使用过程中不可 避免的要用到硬件信息,这些信息包括内 存大小,串口配置信息等等。那么这信息内 核是如何获的呢?