uClinux 启动过程详细分析(1)bootloader启动
- UID
- 1066743
|
uClinux 启动过程详细分析(1)bootloader启动
本帖最后由 look_w 于 2018-5-19 18:05 编辑
大家对uclinux的启动应该都比较熟悉,作为一名嵌入系统开发者,你一定遇到过下面的情景:
在某论坛上看到一篇帖子,上面贴着uclinux开发板启动时的一堆信息,然后大家在帖子里讨论着这个启动过程中出现的问题,随机举例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
| Linux version 2.4.20-uc1 (root@Local) (gcc version 2.95.3
20010315 (release)(ColdFire patches - 20010318 from http://f
(uClinux XIP and shared lib patches from )) #20 三 6月 1
8 00:58:31 CST 2003
Processor: Samsung S3C4510B revision 6
Architecture: SNDS100
On node 0 totalpages: 4096
zone(0): 0 pages.
zone(1): 4096 pages.
zone(2): 0 pages.
Kernel command line: root=/dev/rom0
Calibrating delay loop... 49.76 BogoMIPS
Memory: 16MB = 16MB total
Memory: 14348KB available (1615K code, 156K data, 40K init)
Dentry cache hash table entries: 2048 (order: 2, 16384 bytes)
Inode cache hash table entries: 1024 (order: 1,
Mount-cache hash table entries: 512 (order: 0, 4096 bytes)
Buffer-cache hash table entries: 1024 (order: 0, 4096 bytes)
Page-cache hash table entries: 4096 (order: 2, 16384 bytes)
POSIX conformance testing by UNIFIX
Linux NET4.0 for Linux 2.4
Based upon Swansea University Computer Society NET3.039
Initializing RT netlink socket
Starting kswapd
Samsung S3C4510 Serial driver version 0.9 (2001-12-27) with no serial options en
abled
ttyS00 at 0x3ffd000 (irq = 5) is a S3C4510B
ttyS01 at 0x3ffe000 (irq = 7) is a S3C451
Blkmem copyright 1998,1999 D. Jeff Dionne
Blkmem copyright 1998 Kenneth Albanowski
Blkmem 1 disk images:
0: BE558-1A5D57 [VIRTUAL BE558-1A5D57] (RO)
RAMDISK driver initialized: 16 RAM disks of 1024K size 1024 blocksize
Samsung S3C4510 Ethernet driver version 0.1 (2002-02-20) <>
eth0: 00:40:95:36:35:34
NET4: Linux TCP/IP 1.0 for NET4.0
IP Protocols: ICMP, UDP, TCP
IP: routing cache hash table of 512 buckets, 4Kbytes
TCP: Hash tables configured (established 1024 bind 1024)
VFS: Mounted root (romfs
Freeing init memory: 40K
|
上面的这些输出信息,也可能包括你自己正在做的uclinux开发板的输出信息,其中的每一行,每一个字的含义,你是否深究过,或者说大部分的含义你能确切地知道的?本人想在这里结合本人在实践中一些体会来和广大uclinux的开发者一起读懂这些信息。
我们在这里将以一个真实的uclinux系统的启动过程为例,来分析这些输出信息。启动信息的原始内容将用标记标出,以区别与注释。
uclinux的启动主要分为两个阶段:
- ① 第一部分bootloader启动阶段
- ② 第二部分linux 内核初始化和启动阶段
- 第一节:start_kernel
- 第二节:用户模式( user_mode )开始,start_kernel结束
- 第三节:加载linux内核完毕,转入cpu_idle进程
第一部分 : bootloader启动图 1:uclinux启动状态转移示意图1
2
3
4
5
| Boot loader v0.12
NOTE: this boot loader is designed to boot kernels made with the
2.4.xx releases
bootloader for XV
Built at Nov 20 2005 10:12:35
|
Bootloader头信息,版本,编译时间等,这个因不同的bootloader的设计而有所不同,由此你能看出bootloader的版本信息,有很多使用的是通用的bootloader,如u-boot,redboot等。
将bootloader加载到内存ram中的0x90060000处,即将bootloader加载到内存的高端地址处。
Linux内核将被bootloader加载到0x90090000处。
1
| Found boot configuration
|
查找到了启动boot的配置信息。
1
| Booted from parallel flash
|
从flash中启动代码,此处的flash为并行闪存。
Flash的分类Flash的分类列举如下,分三类:并行,串行,不可擦除。
① 并行Parallel flash
NOR Flash,Intel于1988年发明.随机读取的速度比较快,随机按字节写,每次可以传输8Bit。一般适合应用于数据/程序的存贮应用中.NOR还可以片内执行(execute-in-place)XIP.写入和擦除速度很低。
NAND Flash,1989年,东芝公司发明.是以块和页为单位来读写的,不能随机访问某个指定的点.因而相对来说读取速度较慢,而擦除和写入的速度则比较快,每次可以传输16Bit,一般适用在大容量的多媒体应用中,容量大。如:CF,SM。
② 串行Serial Flash 是以字节进行传输的,每次可以传输1-2Bit.如:MMC,SD,MS卡.串行闪存器件体积小,引脚也少,成本相对也更低廉。
③ 不可擦除Mask Rom Flash的特点是一次性录入数据,具有不可更改性,经常运用于游戏和需版权保护文件等的录入。其显著特点是成本低。
注意:任何flash器件的写入操作只能在空或已擦除的单元内进行,所以大多数情况下,在进行写入操作之前必须先执行擦除。NAND器件执行擦除操作是十分简单的,而NOR则要求在进行擦除前先要将目标块内所有的位都写为0。
从上面的信息,我们可以对flash类型特点有个比较明确的了解。
1
| CPU clock rate: 200 MHz
|
开发板上所使用的CPU的主频为200MHZ。
1
| DRAM size is 128MB (128MB/0MB)
|
动态内存ram大小为128M。
在嵌入式系统中使用DRAM内存的设计比较广泛。
在uclinux的系统中,系统运行时间较长后,会出现内存碎片的问题,导致再分配大块内存时会失败。这是在uclinux系统中经常遇到的问题,解决的办法通常有使用静态内存、应用程序启动时预先分配大内存、使用内存池等。
地址辅助说明:
内存的类型及工作原理这里我们列举一下内存的类型及工作原理。根据内存的工作原理可以划分出两种内存:DRAM和SRAM。
① DRAM表示动态随机存取存储器。这是一种以电荷形式进行存储的半导体存储器。DRAM中的每个存储单元由一个晶体管和一个电容器组成。数据存储在电容器中。电容器会由于漏电而导致电荷丢失,因而DRAM器件是不稳定的。为了将数据保存在存储器中,DRAM器件必须有规律地进行刷新。
② SRAM是静态的,因此只要供电它就会保持一个值。一般而言,SRAM 比DRAM要快,这是因为SRAM没有刷新周期。每个SRAM存储单元由6个晶体管组成,而DRAM存储单元由一个晶体管和一个电容器组成。相比而言,DRAM比SRAM每个存储单元的成本要高。照此推理,可以断定在给定的固定区域内DRAM的密度比SRAM 的密度要大。
SRAM常常用于高速缓冲存储器,因为它有更高的速率;而DRAM常常用于PC中的主存储器,因为其拥有更高的密度。
先说明一下内存地址数字情况,主要是为了方便记忆。
1
2
3
4
5
6
7
8
9
10
11
12
13
| 可以访问的内存为4G。
0x40000000是1GB处;
0x00040000是256K处,
0x00020000是128K处,
0x90000000是2GB多的地方。
1M->0x00100000,
2M->0x00200000,
8M->0x00800000,
16M->0x01000000,
32M->0x02000000,
256M->0x10000000,
64K->0x00010000,
4K->0x00001000
|
这个是个快速记忆的方法,你可以根据地址中1的位置和其后0的个数来快速知道换算后的地址是在多少兆的地方。比如,1的后面5个0,代表1M的大小,6个0,代表16M,以此类推。
1
| ROMFS found at 0x46040000, Volume name = rom 43f291aa
|
romfs,只读文件系统所在的地址为:0x46040000 (flash映射后的第3分区)。卷名为rom。
romfs和rootfs概念上有所区别。flash在内存中的的起始地址为0x46000000,而ROMFS在flash分区上的起始位置为0x00040000,所以ROMFS在内存地址中的位置就为0x46040000。这个细节的部分可以参考flash分区时的地方,Creating 3 MTD partitions。
romfs中包括kernel和app应用,不包括bootloader和firmware信息头。romfs只读文件系统里的内容有很多种分类方法,我们可以将kernel和app同时放里面,作为根文件系统下的一个文件,也可以在flash上另外划分区域来分别存放。
VFS虚拟文件系统交换器在linux系统中,目前已经开发出多种文件系统,那么如何让这些文件系统能共存在一个系统中呢,从linux 2.0开始,引入了虚拟文件系统管理器 VFS的概念。
Linux 下的文件系统主要可分为三大块:
- ① 一是上层的文件系统的系统调用,
- ② 二是虚拟文件系统交换器 VFS(Virtual Filesystem Switch),
- ③ 三是挂载到 VFS 中的各实际文件系统,例如 ext2,jffs 等。
VFS的确切叫法是Virtual Filesystem Switch虚拟文件系统交换器,这里的VFS中的“S”是指的switch,这个需要强调一下的,它很容易被混淆成“system”,如果理解成“system”将是不正确的,请多加注意。
VFS是具体文件系统filesystem的一个管理器。VFS是Linux内核中的一个软件层,一种软件机制,它也提供了内核中的一个抽象功能,允许不同的文件系统共存,可以称它为 Linux 的文件系统管理者,与它相关的数据结构只存在于物理内存当中。所以在每次系统初始化期间,Linux 都首先要在内存当中构造一棵 VFS 的目录树。VFS 中的各目录其主要用途是用来提供实际文件系统的挂载点。而rootfs将是这个目录树的根结点的(root),即 "/"目录,VFS的结构就是从这个rootfs开始的。有了VFS,那么对文件的操作将使用统一的接口,将来通过文件系统调用对 VFS 发起的文件操作等指令将被 rootfs 文件系统中相应的函数接口所接管。
注意:rootfs并不是一个具体的文件系统类型,如jffs。它只是一个理论上的概念。在具体的嵌入系统实例中,可以将某种具体的文件系统设置为根文件系统rootfs,如我们可以设置romfs为根文件系统,也可以设置jffs为根文件系统。
这里的ROMFS只读文件系统只是一种具体的文件系统类型,也是在嵌入系统中经常使用到的类型。
看完了上面的内容,以后你对出现的类似“kernel Panic:VFS:Unable to mount root fs on 0:00”的含义应该已经了解了。其中“VFS:”就是虚拟文件系统管理器操作时的输出信息了。
1
| File linux.bin.gz found
|
linux kernel内核文件名,它是在只读文件系统romfs上的一个组成部分。
1
| Unzipping image from 0x4639DE60 to 0x90090000, size = 1316021
|
将romfs中的linux kernel解压缩到0x90090000,之后会从这个内存地址启动内核。romfs为压缩格式文件,使用压缩的只读文件系统,是为了保持制作出来的整个系统所占用的flash空间减小。这个内核的大小为1.3M左右,这也是目前大多数嵌入系统所使用的方法。
1
2
| Inptr = 0x00000014(20)
Inflating....
|
释放……
1
2
3
4
| Outcnt = 0x0030e7c8(3205064)
Final Inptr = 0x001414ad(1316013)
Original CRC = 0xcbd73adb
Computed CRC = 0xcbd73adb
|
做释放后的CRC检查。
1
| Boot kernel at 0x90090000 with ROMFS at 0x46040000
|
kernel已经被从romfs中释放到内存地址0x90090000处,可以跳转到此处启动kernel了,这里是指定的kernel的起始地址。
系统等待启动,后面将看到linux kernel的启动过程了。 |
|
|
|
|
|