arm环境u-boot功能和linux启动过程

1. U-BOOT概况总结

一、 启动代码为start.S

二、 由于u-boot为裸板上第一个程序,所以要初始化各个外设,由于u-boot已经初始化了,

包括:中断禁用、分配动态内存、初始化BBS区域、初始化页目录、打开缓存等任务。

所以linux内核不需要全部再次初始化,所以可以理解bootloader和kernel其实是两兄弟。

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*start code on reset*/

Reset:

/*初始化cpu*/
bl set_cpu_mode /*设置特权模式*/

/*初始化中断和时钟外设*/
bl turn_off_watchdog /*关闭看门狗*/
bl mask_irqs /*关闭中断*/
bl set_clock /*设置时钟*/

/*初始化内存*/
bl disable_id_caches /*关闭caches*/
bl init_memory /*初始化sram*/
bl init_stack /*初始化栈*/
bl clean_bss /*初始化bss*/

/*初始化硬盘*/
bl nand_init /*初始化nand*/

/*应用*/
bl copy_to_ram /*复制自身到ram*/
ldr pc, =arm_main /*执行main函数*/

三、 U-boot引导内核第一步要做的的是把内核下到ram中,然后跳到内核的start函数。

四、bootloader必须提供5种功能:RAM初始化、串行端口初始化、查找机器类别、构建tagged list内核、将控制移交到内核镜像。

2. linux内核初始化流程

img

u-boot跳到linux内核的arch/arm/boot/compressed/head.S中start后

img

内核大致可以理解为三部曲:

第一步 解压内核并跳到start_kernel()。

​ 1.arch/arm/boot/compressed/head.S(start)

准备解压内核

​ 2.arch/arm/boot/compressed/head.S

通过decompress_kernel 解压zImage

通过call_kernel调用已解压后内核vmlinux

​ 3.arch/arm/kernel/head.S

通过ENTRY(stext)->

处理器信息搜寻——__look_processor_type

搜寻我的机型——__lookup_machine_type

通过__mmap_switched调用start_kernel

第二步 跳到真正第一个内核代码init/main.c(start_kernel())。 注:在linux 0.11中为init/main.c main()。

其中明星函数(排名不分先后):

1.初始化console(此处为平台相关需要hack的地方<1>)

start_kernel->console_init->serial_pxa_console_init

2.注册SOC初始化函数machine_desc

start_kernel->setup_arch()->setup_machine(machine_arch_type)[/arch/arm/kernel/setup.c]

img

[/arch/arm/mach-s3c2440/mach-mini244.c]

MACHINE_START(MINI2440, “FriendlyARM Mini2440 development board”)

​ .phys_io = S3C2410_PA_UART,

​ .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,

​ .boot_params = S3C2410_SDRAM_PA + 0x100,

​ .init_irq = s3c24xx_init_irq,

​ .map_io = mini2440_map_io,

​ .init_machine = mini2440_machine_init,

​ .timer = &s3c24xx_timer,

MACHINE_END

1)init_machine 在start_kernel()->setup_arch()->do_initcalls()->customize_machine()->mini6410_machine_init()

2)init_irq在start_kernel() -> init_IRQ() -> init_arch_irq()中被调用

3)map_io 在 setup_arch() -> paging_init() -> devicemaps_init()中被调用

4)timer是定义系统时钟,定义TIMER4为系统时钟,在arch/arm/plat-s3c/time.c中体现。

在start_kernel() -> time_init()中被调用。

5)boot_params是bootloader向内核传递的参数的位置,这要和bootloader中参数的定义要一致。

http://blog.csdn.net/boyemachao/article/details/45394363

3.初始化虚拟驱动平台platform

start_kernel->kernel_init()->do_basic_setup()->driver_init()->platform_bus_init()→bus_register(&platform_bus_type)

4.初始化SOC(initcall参考下面的init.h)

start_kernel->kernel_init()->do_basic_setup()->do_initcalls()->do_one_initcall()

img

第三步 就为愉快的init的代码了也就是第一个进程,在linux 0.11中集成在内核中。在之后版本由用户态提供。

​ 当然我已经升级为systemd啦,哈哈。

3. linux初始化代码框架

哪部分是只和CPU相关的部分,

哪部分是SOC平台相关的部分,

也再次标明LINUX下大致逻辑。

第一部分代码arch/arm/boot/

简介:也就是自我解压部分,可以理解为和cpu相关但和SOC无关。

移植:移植时选择对应的cpu。

功能:arch/arm/boot/compressed/head.S自我解压前准备、解压缩。跳到start_kernel。

第二部分代码init/main.c

简介:也就是start_kernel()或0.11中的main() 可以理解内核真正的第一代码。为平台无关代码。

移植:移植时不用管。

功能:此代码虽说简单的大几十行,但功能太多,我还是给个linux 0.11中main()的靓照吧_

img

第三部分代码 arch/arm/PLAT- arch/arm/MACH-

​ 简介:为了完成start_kernel()中初始化的SOC相关部分。

移植:移植时需要考虑对应的SOC。没有对应soc支持时,才是各路玩家大显身手的时候。

功能:看下面的介绍吧。

4. Mini2440的plat和mach

plat-s3c24xx

mach-s3c2440

mach-s3c2410

======================

\1. 三星这样分层的理由是s3c系列的soc具有一定的共通性, plat-实现了一些较通用的封装, 这些封装的具体参数一般是宏, 这些宏如寄存器地址可能是在mach-里面被定义;

linux/arch/arm/plat-s3c24xx/common-smdk.c

​ static struct s3c24xx_led_platdata smdk_pdata_led5 = {

​ .gpio = S3C2410_GPF5,

​ .flags = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,

​ .name = “led5”,

​ .def_trigger = “nand-disk”,

​ };

linux/include/asm-arm/arch-s3c2410/regs-gpio.h

​ #define S3C2410_GPF5 S3C2410_GPIONO(S3C2410_GPIO_BANKF, 5)

\2. 原则上是把所有s3c系列共同的东西放在 plat-里面去, 具体的io或者比较有mach-特色的部分放到mach-里面;

改板时, 实际上大多是直接在mach-里面增删自己的功能. (不按三星预设方案的改动除外)

plat里面需要动的相对更少, 不过在linux/arch/arm/plat-s3c24xx/common-smdk.c里面,

我们可以根据实际情形来分配nand的分区(修改static struct mtd_partition smdk_default_nand_part[] );

\3. 编译时,一般只会选中一个特定的mach-, mach-会调用plat-的功能具体实现平台的资源和设备初始化.

5.内核移植

在一般普通的产品公司,大部分都是在soc上添加自己需要的外设做成产品。

并且常见的soc都已经有了成熟的soc代码支持。

现在讨论内核移植重点在板级支持,这属于BSP工程师的范围。并非属于芯片工程。

BSP工程师的能力就是要在各种板子上移植我们万众期待的linux内核。

总的来说,我们所做的就是要找到外设的区别,熟悉内核的框架,

修改外设的驱动,使内核完美的运行起来就好了。

所涉及到的驱动:GPIO、协处理器、中断、时钟、MMU、存储控制器、NAND、UART、IIC等。

我们可以找出最基本的,启动linux所依赖的。并根据依赖的顺序一一攻破。

我暂时认为,学习此部分好的方法是先在一个成熟板子上写一个裸板程序。

这样可以熟悉板子硬件,也可熟悉一个小的系统是如何跑起来的。

有了这个基础我们就能把我哪些是最为基础的驱动。和依赖的顺序等。

通过本文可以体会到,对于内核,移植它改造它有难度呀。

会裸板驱动、会写bootloader只是基础。

还要熟悉内核代码,真是上知系统、应用,下知硬件、驱动。

参考资料:

[console] early printk实现流程

http://blog.csdn.net/ooonebook/article/details/52654120

linux2.6中的console_init初始化的研究

http://blog.csdn.net/breeze_vickie/article/details/5563375

linux下tty,控制台,虚拟终端,串口,console(控制台终端)详解

http://blog.csdn.net/liaoxinmeng/article/details/5004743

【原创】s3c2440内核启动时如何注册串口为终端设备

http://blog.sina.com.cn/s/blog_70ef2ee90100zc4z.html


arm环境u-boot功能和linux启动过程
http://blog.uanet.cn/KERNEL/arm环境u-boot功能和linux启动过程.html
作者
dnsnat
发布于
2024年4月19日
许可协议