Bootloader传参数到Kernel

文章目录

    • 一、bootloader基本概述
        • (1)初始化RAM
        • (2)初始化串口端口
        • (3)检测处理器类型
        • (4)设置Linux启动参数
        • (5)调用Linux内核映像
    • 二、实现bootloader传参数到kernel
      • 【实例】系统识别不同硬件版本方法
        • (1)【uboot】BootLoader 传递参数
        • (2)【Kernel】解析BootLoader参数

本文章大量参考引用: 【写代码的篮球球痴】Bootloader传参数到Kernel

一、bootloader基本概述

Bootloader是嵌入式系统的引导加载程序,它是系统上电后运行的第一段程序,所以他的地址一般是0x0000000,其作用类似于PC机上的BIOS。Bootloader是依赖于硬件而实现的,特别是在嵌入式领域,为嵌入式系统建立一个通用的Bootloader是很困难的,但为了能达到启动Linux内核的目的,所有的Bootloader都必须具备以下功能:
Bootloader传参数到Kernel_第1张图片

(1)初始化RAM

因为Linux内核一般都会在RAM中运行,所以在调用Linux内核之前Bootloader必须设置和初始化RAM,为调用Linux内核做好准备。初始化RAM的任务包括设置CPU的控制寄存器参数,以便能正常使用RAM以及检测RAM大小等。

(2)初始化串口端口

在Linux的启动过程中有着非常重要的作用,它是Linux内核和用户交互的方式之一。Linux在启动过程中可以将信息通过串口输出,这样便可清楚的了解Linux的启动过程。虽然它并不是Bootloader必须要完成的工作,但是通过串口输出信息是调试Bootloader和Linux内核的强有力的工具,所以一般的Bootloader都会在执行过程中初始化一个串口作为调试端口。

(3)检测处理器类型

Bootloader在调用Linux内核前必须检测系统的处理器类型,并将其保存到某个常量中提供给Linux内核。Linux内核在启动过程中会根据该处理器类型调用相应的初始化程序。

(4)设置Linux启动参数

Bootloader在执行过程中必须设置和初始化Linux的内核启动参数。

(5)调用Linux内核映像

Bootloader完成的最后一项工作便是调用Linux内核。如果Linux内核存放在Flash中,并且可直接在上面运行(这里的Flash指NorFlash),那么可直接跳转到内核中去执行。但由于在Flash中执行代码会有种种限制,而且速度也远不及RAM快,所以一般的嵌入式系统都是将Linux内核拷贝到RAM中,然后跳转到RAM中去执行。

  • 问题:Linux内核代码是在RAM中执行还是在Flash中执行的?

答:嵌入式系统中广泛采用的非易失性存储器通常是 Flash,而 Flash 又分为 Nor Flash 和Nand Flash 两种。 它们之间的不同在于:== Nor Flash 支持芯片内执行(XIP, eXecute In Place),这样代码可以在Flash上直接执行而不必拷贝到RAM中去执行。而Nand Flash并不支持XIP,所以要想执行 Nand Flash 上的代码,必须先将其拷贝到 RAM中去,然后跳到 RAM 中去执行。实际应用中的 bootloader根据所需功能的不同可以设计得很复杂,除完成基本的初始化系统和调用 Linux 内核等基本任务外,还可以执行很多用户输入的命令,比如设置 Linux 启动参数,给 Flash 分区等;也可以设计得很简单,只完成最基本的功能。

二、实现bootloader传参数到kernel

硬件开发需要更换芯片,为实现不同硬件的兼容,需要将硬件信息及版本等参数从bootloader传到kernel,kernel通过解析这些参数实现不同硬件的加载。

【实例】系统识别不同硬件版本方法

开发板硬件迭代,需要通过几个gpio的高低电平来表示不同硬件版本,以实现系统识别兼容不同硬件版本。代码修改如下

(1)【uboot】BootLoader 传递参数

snprintf(command_line, sizeof(command_line),
“%s androidboot.wzb220_hw_rev=%d”, command_line, wzb220_hw_rev);

bootloader cmdline参数是androidboot.wzb220_hw_rev
只有在cmdline或者内核CONFIG_DEFAULT_COMMANDLINE中声明此参数,内核在处理参数的时候才会执行相对应的函数。
最终生成ro.boot.wzb220_hw_rev格式的property. 而在HAL, Natvie, APP层都有对应的api去解析property,整个系统都可以使用.

diff --git a/board/rockchip/rk32xx/rk32xx.c b/board/rockchip/rk32xx/rk32xx.c
index fa2f83f..e5aa0c4 100644
--- a/board/rockchip/rk32xx/rk32xx.c
+++ b/board/rockchip/rk32xx/rk32xx.c
@@ -17,6 +17,12 @@
 #include "../common/config.h"
 
+/*add hw version verify. {*/
+#ifdef CONFIG_WZB220_HW_REV
+u8 wzb220_hw_rev = 0;
+#endif
+/*add hw version verify. }*/

 DECLARE_GLOBAL_DATA_PTR;
 static ulong get_sp(void)
 {
@@ -26,6 +32,23 @@
     return ret;
 }

 //宏定义包起来
+/add hw version verify. {*/
+#ifdef CONFIG_WZB220_HW_REV
+    #define GPIO_WZB220_HW_REV1                (GPIO_BANK0 | GPIO_D0)
+    #define GPIO_WZB220_HW_REV2                (GPIO_BANK3 | GPIO_C7)
+    #define GPIO_WZB220_HW_REV3                (GPIO_BANK0 | GPIO_C4)
+    gpio_direction_input(GPIO_WZB220_HW_REV1);
+    gpio_direction_input(GPIO_WZB220_HW_REV2);
+    gpio_direction_input(GPIO_WZB220_HW_REV3);
+     //获取gpio状态
+    wzb220_hw_rev = gpio_get_value(GPIO_WZB220_HW_REV3)<<2 |                                gpio_get_value(GPIO_WZB220_HW_REV2) <<1 |                               gpio_get_value(GPIO_WZB220_HW_REV1);
+    printf("HW board check version:%d\n", wzb220_hw_rev);
+#endif
+/*add hw version verify. }*/


 void board_lmb_reserve(struct lmb *lmb) {
     ulong sp;
     sp = get_sp();

diff --git a/common/cmd_bootrk.c b/common/cmd_bootrk.c
index e44c68f..0b68cff 100755
--- a/common/cmd_bootrk.c
+++ b/common/cmd_bootrk.c
@@ -52,6 +52,13 @@
 extern int rkimage_load_image(rk_boot_img_hdr *hdr,
         const disk_partition_t *boot_ptn, const disk_partition_t *kernel_ptn);
 

+#ifdef CONFIG_WZB220_HW_REV
+extern u8 wzb220_hw_rev;
+#endif

+// 利用u-boot到kernel的cmdline参数androidboot.wzb220_hw_rev传递机制,
+// 到kernel中.
+#ifdef CONFIG_WZB220_HW_REV
+    snprintf(command_line, sizeof(command_line),
+                 "%s androidboot.wzb220_hw_rev=%d", command_line, wzb220_hw_rev);
+#endif


 #ifdef CONFIG_RK_SDCARD_BOOT_EN
     if (StorageSDCardUpdateMode()) { /* sdcard undate */
         snprintf(command_line, sizeof(command_line),


diff --git a/include/configs/rk33plat.h b/include/configs/rk33plat.h
index 5e5d273..24b9614 100755
--- a/include/configs/rk33plat.h
+++ b/include/configs/rk33plat.h
@@ -37,6 +37,8 @@
 /* Generic Timer Definitions */
 #define COUNTER_FREQUENCY        CONFIG_SYS_CLK_FREQ_CRYSTAL

+/*add hw version verify.*/
+#define CONFIG_WZB220_HW_REV

(2)【Kernel】解析BootLoader参数

early_param(“androidboot.idpad_hw_rev”, early_idpad_hw_rev);

start_kernel->parse_early_param->parse_early_options->parse_args->do_early_param

init进程early_param:
parse_args对cmdline每一个參数都遍历__param.init.setup匹配androidboot.idpad_hw_rev参数,匹配成功则函数early_idpad_hw_rev在linux启动时会被调用

    diff --git a/init/main.c b/init/main.c
    old mode 100644
    new mode 100755
    index 86f5ce9e..9acf8ff
    --- a/init/main.c
    +++ b/init/main.c
    @@ -231,6 +231,20 @@
     
     early_param("loglevel", loglevel);
     
    +int idpad_hw_rev;
    +static int __init early_idpad_hw_rev(char *p)
    +{
    +    get_option(&p, &idpad_hw_rev);
    +    printk("androidboot.idpad_hw_rev:%d\n", idpad_hw_rev);
    +    return 0;
    +}
    +early_param("androidboot.idpad_hw_rev", early_idpad_hw_rev);

参考文档:
https://blog.csdn.net/weiqifa0/article/details/82351772
https://blog.csdn.net/eZiMu/article/details/52334258
https://blog.csdn.net/kris_fei/article/details/70226451
https://blog.csdn.net/lemon15071230867/article/details/82344269
https://www.cnblogs.com/tlnshuju/p/6851812.html

你可能感兴趣的:(LINUX,内核驱动)