BootLoader与 Linux 内核的参数传递

BootLoader Linux 内核的参数传递

夏传凯,吴乃陵

东南大学电子科学与工程学院,南京(210096

E-mailxchk215@163.com

  要:本文介绍了嵌入式系统 BootLoader Linux-2.6.19.2内核参数传递的具体实现。主

要内容包括:系统硬件平台的简介,参数链表的结构和创建,内核的接收。

关键词:BootLoaderAT91RM9200LinuxTagged list,内核参数传递

 

0. 引言

在嵌入式系统中,BootLoader是用来初始化硬件,加载内核,传递参数。因为嵌入式系

统的硬件环境各不相同,所以嵌入式系统的 BootLoader 也各不相同,其中比较通用的是

U-Boot 它支持不同的体系结构, ARM PowerPC X86 MIPS等。 本文着重介绍BootLoader

与内核之间参数传递这一基本功能。本文的硬件平台是基于 AT91RM9200 处理器系统,软

件平台是Linux-2.6.19.2 内核。内核映像文件为 zImage

1. 系统硬件平台简介

AT91RM9200处理器,它是由Atmel公司基于 ARM920T内核的微处理器,带有内存管

理单元,CPU 时钟最高可达 240MHz,它具有丰富的标准接口,EBI 接口,内部集成了静态

存储控制器(SMC),SDRAM 控制器,Burst Flash 控制器。有关处理器的说明请参考

AT91RM9200的数据手册。本系统SDRAM64MB)地址为:0x20000000, NorFlash8MB

的地址为:0x10000000[1]。系统硬件平台的原理图如下:

 

 

1  系统硬件平台原理图

 

2. BootLoader设计和实现

内核源代码目录树下的 documentation/arm/booting[2]文档规定了基于 ARM 体系结构

BootLoader 的基本功能。本系统 BootLoader 除了完成这些基本的功能外,还结合自身硬件

的特点加入了代码搬运等功能。

AT91RM9200

SDRAM

64MB

NorFlash

8MB

RS232 接口

USB 接口

网络接口

显示器驱动

模块

JTAG接口

SD卡接口 http://www.paper.edu.cn

  - 2 -

BootLoader的流程是:系统上电复位后,首先从NorFlash 开始运行(由处理器 BMS

脚连接决定),因为处理器此时的 0地址就是 NorFlash 的首地址(0x10000000)BootLoader

就是被烧写在这个位置,AT91RM9200 处理器能够映射的地址范围只有 0x0000

00000x001f ffff BootLoader 执行的第一步就是将自身代码从 NorFlash 中搬运到处理器

内部的 RAM 中(0x00200000),然后将 0 地址映射到内部 RAM,并且跳转到内部 RAM

相应地址处继续执行。进入内部 RAM后才进入真正的硬件初始化阶段,这个阶段初始化的

各种控制器都是内核所必须的,包括:PMC, EBI, SMC, SDRAM, USART等。接着就是创建

内核参数链表(Tagged list),创建完链表就是搬运事先烧写在NorFlash 中的内核映像和根文

件系统映像到 SDRAM 根据内核对BootLoader的基本要求关闭中断,MMU和数据Cache

并且配置r0=0, r1=0x0000 00fb或者0x00000106(根据内核中linux/arch/arm/tools/mach-types[2]

规定的机器编号)r2=0x20000100BootLoader传递给内核参数链表的物理地址),在ARM

体系结构中,这个地址在同一种处理器的机器描述符(machine_desc)中都是默认的,所以

在这里可以不指定。最后BootLoader直接跳转到 SDRAM的内核处执行。

3. 内核参数链表

BootLoader 可以通过两种方法传递参数给内核,一种是旧的参数结构方式

parameter_struct),主要是 2.6 之前的内核使用的方式。另外一种就是现在的 2.6内核在用

的参数链表 (tagged list)  方式。这些参数主要包括,系统的根设备标志,页面大小,内存的

起始地址和大小,RAMDISK的起始地址和大小,压缩的RAMDISK根文件系统的起始地址

和大小,内核命令参数等[3][4][5]

内核参数链表的格式和说明可以从内核源代码目录树中的 include/asm-arm/setup.h[2]

找到,参数链表必须以ATAG_CORE 开始,以ATAG_NONE结束。这里的 ATAG_CORE

ATAG_NONE是各个参数的标记,本身是一个32位值,例如:ATAG_CORE=0x54410001

其它的参数标记还包括: ATAG_MEM32 ATAG_INITRD ATAG_RAMDISK

ATAG_COMDLINE 等。每个参数标记就代表一个参数结构体,由各个参数结构体构成了参

数链表。参数结构体的定义如下: 

  struct tag {

      struct  tag_header  hdr;

      union {

             struct tag_core    core;

         struct tag_mem32    mem;

           struct tag_videotext  videotext;

struct tag_ramdisk    ramdisk;

struct tag_initrd      initrd;

           struct tag_serialnr     serialnr;

struct tag_revision    revision;

           struct tag_videolfb   videolfb;

          struct tag_cmdline   cmdline;

 struct tag_acorn       acorn;

struct tag_memclk    memclk;

         } u;

};

参数结构体包括两个部分,一个是 tag_header结构体,一个是u联合体。 http://www.paper.edu.cn

  - 3 -

tag_header结构体的定义如下:

   struct tag_header {

                  u32 size;  

                  u32 tag;

};

其中 size:表示整个 tag 结构体的大小(用字的个数来表示,而不是字节的个数),等于

tag_header的大小加上 u联合体的大小,例如,参数结构体 ATAG_CORE

size=(sizeof(tag->tag_header)+sizeof(tag->u.core))>>2,一般通过函数 tag_size(struct * tag_xxx)

来获得每个参数结构体的 size。其中 tag:表示整个 tag 结构体的标记,如:ATAG_CORE

等。

联合体 u 包括了所有可选择的内核参数类型,包括:tag_core, tag_mem32tag_ramdisk

等。参数结构体之间的遍历是通过函数 tag_next(struct * tag)来实现的。本系统参数链表包括

的结构体有:ATAG_COREATAG_MEMATAG_RAMDISKATAG_INITRD32

ATAG_CMDLINEATAG_END。在整个参数链表中除了参数结构体 ATAG_CORE

ATAG_END 的位置固定以外,其他参数结构体的顺序是任意的。本 BootLoader所传递的参

数链表如下:第一个内核参数结构体,标记为ATAG_CORE,参数类型为 tag_core。每个参

数类型的定义请参考源代码文件。

tag_array初始化为指向参数链表的第一个结构体的指针。

tag_array->hdr.tag=ATAG_CORE;

   tag_array->hdr.size=tag_size(tag_core);

   tag_array->u.core.flags=1;               

   tag_array->u.core.pagesize=4096;          

   tag_array->u.core.rootdev=0x00100000; 

   tag_array=tag_next(tag_array);  

         

   tag_array->hdr.tag=ATAG_MEM;

   tag_array->hdr.size=tag_size(tag_mem32);

   tag_array->u.mem.size=0x04000000;      

   tag_array->u.mem.start=0x20000000;      

   tag_array=tag_next(tag_array);

   ……

   tag_array->hdr.tag=ATAG_NONE;

   tag_array->hdr.size=0;

   tag_array=tag_next(tag_array);

 

最后将内核参数链表复制到内核默认的物理地址 0x20000100处。这样参数链表就建好了。

4. 内核接收参数

下面从基于ARM体系结构的zImage映像启动来分析Linux内核是怎样接收BootLoader

传递过来的内核参数,zImage启动过程如下图所示。 http://www.paper.edu.cn

  - 4 -

 

2   参数传递的路径[5]

 

在文件 arch/arm/boot/compressed/head.S[2] startzImage的起始点,部分代码如下:

start:

mov r7, r1      

    mov r8, r2        

        …...

        mov r0, r4

    mov r3, r7             

    bl  decompress_kernel   

  b call_kernel

call_kernel

        ……

  mov r0, #0   

  mov r1, r7   

  mov r2, r8   

  mov pc, r4   

首先将BootLoader传递过来的r1(机器编号)、r2(参数链表的物理地址)的值保存到 r7

r8 中,再将 r7 作为参数传递给解压函数 decompress_kernel()。在解压函数中,再将 r7

递给全局变量__machine_arch_type。在跳到内核(vmlinux)入口之前再将 r7r8 还原到 r1

r2 中。

在文件 arch/arm/kernel/head.S[2]中,内核(vmlinux)入口的部分代码如下:

stext    

  mrc  p15, 0, r9, c0, c0        

bl __lookup_processor_type  

    ………

 bl __lookup_machine_type  

首先从处理器内部特殊寄存器(CP15)中获得 ARM 内核的类型,从处理器内核描述符

proc_info_list)表(__proc_info_begin__proc_info_end)中查询有无此ARM内核的类型,

启动(start

解压内核(decompress_kernel())

调用内核(call_kernel())

内核初始化(start_kernel())

setup_arch()

内核 vmlinux入口(stext:) http://www.paper.edu.cn

  - 5 -

如果无就出错退出。处理器内核描述符定义在 include/asm-arm/procinfo.h[2]中,具体的函数

实现在 arch/arm/mm/proc-xxx.S[2]中,在编译连接过程中将各种处理器内核描述符组合成

表。接着从机器描述符(machine_desc)表(__mach_info_begin__mach_info_end)中查询

有无 r1 寄存器指定的机器编号,如果没有就出错退出。机器编号 mach_type_xxx

arch/arm/tools/mach-types[2]文件中说明,每个机器描述符中包括一个唯一的机器编号,机器

描述符的定义在 include/asm-arm/mach/arch.h[2]中,具体实现在 arch/arm/mach-xxxx[2]文件

夹中,在编译连接过程中将基于同一种处理器的不同机器描述符组合成表。例如,基于

AT91RM9200处理器的各种机器描述符可以参考 arch/arm/mach-at91rm9200/board-xxx.c[2]

机器编号为 262的机器描述符如下所示:

  MACHINE_START(AT91RM9200DK, "Atmel AT91RM9200-DK")

  /* Maintainer: SAN People/Atmel */

 .phys_io = AT91_BASE_SYS,

  .io_pg_offst  = (AT91_VA_BASE_SYS >> 18) & 0xfffc,

  .boot_params  = AT91_SDRAM_BASE + 0x100,  

 .timer    = &at91rm9200_timer,

 .map_io   = dk_map_io,

 .init_irq = dk_init_irq,

 .init_machine = dk_board_init,

MACHINE_END

最后就是打开 MMU,并跳转到 init/main.c[2] start_kernel()初始化系统。

init/main.c[2] 中,函数 start_kernel()的部分代码如下: 

{  ……

  setup_arch(); 

……}

arch/arm/kernel/setup.c[2]中,函数 setup_arch()的部分代码如下:

  { ……

setup_processor();

mdesc=setup_machine(machine_arch_type); 

……

parse_tags(tags);            

……

}

setup_processor()函数从处理器内核描述符表中找到匹配的描述符,并初始化一些处理器

变量。setup_machine()用机器编号(在解压函数 decompress_kernel 中被赋值)作为参数

返回机器描述符。从机器描述符中获得内核参数的物理地址,赋值给 tags 变量。然后调用

parse_tags()函数分析内核参数链表,把各个参数值传递给全局变量。这样内核就收到了

BootLoader传递的参数。

5. 参数传递的验证和测试

参数传递的结果可以通过内核启动的打印信息来验证。

Machine: Atmel AT91RM9200-DK

……

Kernel command line: console=ttyS0,115200 root=/dev/ram rw init=/linuxrc http://www.paper.edu.cn

  - 6 -

……

Memory: 64MB = 64MB total

……

checking if image is initramfs...it isn't (no cpio magic); looks like an initrd

Freeing initrd memory: 1024K

……

RAMDISK: Compressed image found at block 0

6. 结束语

      一个完备的 BootLoader 是一个很复杂的工程,本文所介绍的只是嵌入式系统的

BootLoaer基本功能。任何一个BootLoader都离不开这个基本功能,内核只有接收这些参数

才能正确地启动。目前,笔者的 BootLoader 已经能够稳定地运行在硬件平台上,为以后开

发更复杂和完备的 BootLoader 打下了一定的基础,同时也为内核的移植和调试奠定了良好

的基础。

 

 

 

 

参考文献

[1]  杜春雷. ARM 体系结构与编程[M].北京;  清华大学出版社,2003.2

[2]    Linux-2.6.19.2 kernel, www.kernel.org

[3]  李汉强,邱巍.  基于 Intel PXA26X 处理器的 BootLoader 的设计与实现[J].  武汉理工大学学报(交通科学

与工程版)2003,12:27-6

[4]  郑家玲,张云峰,孙荷琨.嵌入式系统的内核载入过程浅析[J].微型计算机应用,2002 年第11

[5]  孙纪坤,张小全.  嵌入式 Linux系统开发技术详解-基于 ARM[M].北京;  人民邮电出版社,2006.

 

 

 

Parameters transferring from bootloader to linux

Xia Chuankai, Wu Nailing

Southeast University, Nanjing, Jiangsu (210096)

Abstract

This article introduce parameters transferring from bootloader of embedded system to linux-2.6.19.2

kernel and implement. It consists of simple introduction of hardware system, structure and implement

of kernel tag lists and how to be received by kernel .

Keywords: BootLoader  AT91RM9200  Linux  Tagged list  Kernel tagged list transferring

 

 

 

 

 

作者简介:

夏传凯,1980,男,硕士研究生;

吴乃陵,男,教授,硕士生导师,E-mailwunailing@mail.edu.cn

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值