uClinux.docx
《uClinux.docx》由会员分享,可在线阅读,更多相关《uClinux.docx(32页珍藏版)》请在冰点文库上搜索。
uClinux
uClinux 启动过程详细分析
1
推荐
uclinux启动的详细过程有着诸多的信息可以给我们巨大的启发,我们在这里讨论的就是要对这些信息做一个具体细致的分析,通过我们的讨论,大家会对uclinux启动过程中出现的、以前感觉熟悉的、但却又似是而非的东西有一个确切的了解,并且能了解到这些输出信息的来龙去脉。
uclinux的启动过程,它是一幅缩影图,对它有了一个详细的了解后,有助于指导我们更加深入地了解uclinux的核心。
大家对uclinux的启动应该都比较熟悉,作为一名嵌入系统开发者,你一定遇到过下面的情景:
在某论坛上看到一篇帖子,上面贴着uclinux开发板启动时的一堆信息,然后大家在帖子里讨论着这个启动过程中出现的问题,随机举例如下:
Linuxversion2.4.20-uc1(root@Local)(gccversion2.95.3
20010315(release)(ColdFirepatches-20010318fromhttp:
//f
(uClinuxXIPandsharedlibpatchesfrom#20三6月1
800:
58:
31CST2003
Processor:
SamsungS3C4510Brevision6
Architecture:
SNDS100
Onnode0totalpages:
4096
zone(0):
0pages.
zone
(1):
4096pages.
zone
(2):
0pages.
Kernelcommandline:
root=/dev/rom0
Calibratingdelayloop...49.76BogoMIPS
Memory:
16MB=16MBtotal
Memory:
14348KBavailable(1615Kcode,156Kdata,40Kinit)
Dentrycachehashtableentries:
2048(order:
2,16384bytes)
Inodecachehashtableentries:
1024(order:
1,
Mount-cachehashtableentries:
512(order:
0,4096bytes)
Buffer-cachehashtableentries:
1024(order:
0,4096bytes)
Page-cachehashtableentries:
4096(order:
2,16384bytes)
POSIXconformancetestingbyUNIFIX
LinuxNET4.0forLinux2.4
BaseduponSwanseaUniversityComputerSocietyNET3.039
InitializingRTnetlinksocket
Startingkswapd
SamsungS3C4510Serialdriverversion0.9(2001-12-27)withnoserialoptionsen
abled
ttyS00at0x3ffd000(irq=5)isaS3C4510B
ttyS01at0x3ffe000(irq=7)isaS3C451
Blkmemcopyright1998,1999D.JeffDionne
Blkmemcopyright1998KennethAlbanowski
Blkmem1diskimages:
0:
BE558-1A5D57[VIRTUALBE558-1A5D57](RO)
RAMDISKdriverinitialized:
16RAMdisksof1024Ksize1024blocksize
SamsungS3C4510Ethernetdriverversion0.1(2002-02-20)
eth0:
00:
40:
95:
36:
35:
34
NET4:
LinuxTCP/IP1.0forNET4.0
IPProtocols:
ICMP,UDP,TCP
IP:
routingcachehashtableof512buckets,4Kbytes
TCP:
Hashtablesconfigured(established1024bind1024)
VFS:
Mountedroot(romfs
Freeinginitmemory:
40K
上面的这些输出信息,也可能包括你自己正在做的uclinux开发板的输出信息,其中的每一行,每一个字的含义,你是否深究过,或者说大部分的含义你能确切地知道的?
本人想在这里结合本人在实践中一些体会来和广大uclinux的开发者一起读懂这些信息。
我们在这里将以一个真实的uclinux系统的启动过程为例,来分析这些输出信息。
启动信息的原始内容将用标记标出,以区别与注释。
uclinux的启动主要分为两个阶段:
∙①第一部分bootloader启动阶段
∙②第二部分linux内核初始化和启动阶段
∙
o第一节:
start_kernel
o第二节:
用户模式(user_mode)开始,start_kernel结束
o第三节:
加载linux内核完毕,转入cpu_idle进程
第一部分:
bootloader启动
图1:
uclinux启动状态转移示意图
Bootloaderv0.12
NOTE:
thisbootloaderisdesignedtobootkernelsmadewiththe
2.4.xxreleases
bootloaderforXV
BuiltatNov20200510:
12:
35
Bootloader头信息,版本,编译时间等,这个因不同的bootloader的设计而有所不同,由此你能看出bootloader的版本信息,有很多使用的是通用的bootloader,如u-boot,redboot等。
Loadedto0x90060000
将bootloader加载到内存ram中的0x90060000处,即将bootloader加载到内存的高端地址处。
Linux内核将被bootloader加载到0x90090000处。
Foundbootconfiguration
查找到了启动boot的配置信息。
Bootedfromparallelflash
从flash中启动代码,此处的flash为并行闪存。
Flash的分类
Flash的分类列举如下,分三类:
并行,串行,不可擦除。
①并行Parallelflash
NORFlash,Intel于1988年发明.随机读取的速度比较快,随机按字节写,每次可以传输8Bit。
一般适合应用于数据/程序的存贮应用中.NOR还可以片内执行(execute-in-place)XIP.写入和擦除速度很低。
NANDFlash,1989年,东芝公司发明.是以块和页为单位来读写的,不能随机访问某个指定的点.因而相对来说读取速度较慢,而擦除和写入的速度则比较快,每次可以传输16Bit,一般适用在大容量的多媒体应用中,容量大。
如:
CF,SM。
②串行SerialFlash是以字节进行传输的,每次可以传输1-2Bit.如:
MMC,SD,MS卡.串行闪存器件体积小,引脚也少,成本相对也更低廉。
③不可擦除MaskRomFlash的特点是一次性录入数据,具有不可更改性,经常运用于游戏和需版权保护文件等的录入。
其显著特点是成本低。
注意:
任何flash器件的写入操作只能在空或已擦除的单元内进行,所以大多数情况下,在进行写入操作之前必须先执行擦除。
NAND器件执行擦除操作是十分简单的,而NOR则要求在进行擦除前先要将目标块内所有的位都写为0。
从上面的信息,我们可以对flash类型特点有个比较明确的了解。
CPUclockrate:
200MHz
开发板上所使用的CPU的主频为200MHZ。
DRAMsizeis128MB(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中的主存储器,因为其拥有更高的密度。
先说明一下内存地址数字情况,主要是为了方便记忆。
可以访问的内存为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,以此类推。
ROMFSfoundat0x46040000,Volumename=rom43f291aa
romfs,只读文件系统所在的地址为:
0x46040000(flash映射后的第3分区)。
卷名为rom。
romfs和rootfs概念上有所区别。
flash在内存中的的起始地址为0x46000000,而ROMFS在flash分区上的起始位置为0x00040000,所以ROMFS在内存地址中的位置就为0x46040000。
这个细节的部分可以参考flash分区时的地方,Creating3MTDpartitions。
romfs中包括kernel和app应用,不包括bootloader和firmware信息头。
romfs只读文件系统里的内容有很多种分类方法,我们可以将kernel和app同时放里面,作为根文件系统下的一个文件,也可以在flash上另外划分区域来分别存放。
VFS虚拟文件系统交换器
在linux系统中,目前已经开发出多种文件系统,那么如何让这些文件系统能共存在一个系统中呢,从linux2.0开始,引入了虚拟文件系统管理器VFS的概念。
Linux下的文件系统主要可分为三大块:
∙①一是上层的文件系统的系统调用,
∙②二是虚拟文件系统交换器VFS(VirtualFilesystemSwitch),
∙③三是挂载到VFS中的各实际文件系统,例如ext2,jffs等。
VFS的确切叫法是VirtualFilesystemSwitch虚拟文件系统交换器,这里的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只读文件系统只是一种具体的文件系统类型,也是在嵌入系统中经常使用到的类型。
看完了上面的内容,以后你对出现的类似“kernelPanic:
VFS:
Unabletomountrootfson0:
00”的含义应该已经了解了。
其中“VFS:
”就是虚拟文件系统管理器操作时的输出信息了。
Filelinux.bin.gzfound
linuxkernel内核文件名,它是在只读文件系统romfs上的一个组成部分。
Unzippingimagefrom0x4639DE60to0x90090000,size=1316021
将romfs中的linuxkernel解压缩到0x90090000,之后会从这个内存地址启动内核。
romfs为压缩格式文件,使用压缩的只读文件系统,是为了保持制作出来的整个系统所占用的flash空间减小。
这个内核的大小为1.3M左右,这也是目前大多数嵌入系统所使用的方法。
Inptr=0x00000014(20)
Inflating....
释放……
Outcnt=0x0030e7c8(3205064)
FinalInptr=0x001414ad(1316013)
OriginalCRC=0xcbd73adb
ComputedCRC=0xcbd73adb
做释放后的CRC检查。
Bootkernelat0x90090000withROMFSat0x46040000
kernel已经被从romfs中释放到内存地址0x90090000处,可以跳转到此处启动kernel了,这里是指定的kernel的起始地址。
Press'enter'toboot
系统等待启动,后面将看到linuxkernel的启动过程了。
回页首
第二部分:
linux内核初始化以及启动
回页首
第一节:
start_kernel
Linux的源代码可以从www.kernel.org得到,或者你可以查看linux代码交叉引用网站:
http:
//lxr.linux.no/进行在线的代码查看,这是一个很好的工具网站。
在start_kernel中将调用到大量的init函数,来完成内核的各种初始化。
如:
图2:
kernelstartup初始化过程
具体内容可以参考[http:
//lxr.linux.no/source/init/main.c]
Linuxversion2.4.22-uc0(root@local)(gccversion2.95.320010315(release))#33.?
1..2012:
09:
106
上面的代码输出信息,是跟踪linux代码分析后得到的,进入init目录下的main.c的start_kernel启动函数。
uclinux使用的是linux内核版本为2.4.22。
linuxsourcecode代码中start_kernel中输出的linux_banner信息。
这个信息是每个linuxkernel都会打印一下的信息,如果你没有把这句去掉的话。
Foundbootloadermemorymapat0x10000fc0.
bootloader经过内存映射后的地址为:
0x10000fc0,按上面的地址换算方法,1后面有7个0,那么虚拟地址256M左右处。
Processor:
ARMpt110revision0
pT110是ARM微处理器arm核的一种,另一种为pT100。
此处为显示ARM的类型。
Onnode0totalpages:
20480
zone(0):
20480pages.
zone(0):
Setminimummemorythresholdto12288KB
Warning:
wrongzonealignment(0x90080000,0x0000000c,0x00001000)
zone
(1):
0pages.
zone
(2):
0pages.
预留内存大小,在节点0上总共20页,zone(0)设置最小内存为12MB,zone
(1)和zone
(2)为0页。
警告:
对齐不正确。
Kernelcommandline:
root=/dev/mtdblock3
Kernel启动命令设为:
/dev/mtdblock3(在后面的说明中会看到mtdblock3是指的flash上的romfs分区。
),用来指定根文件系统所在的位置,kernel会将块设备mtdblock3当作文件系统来处理。
也就是说,内核会根据上面的kernel命令行,知道只读文件系统romfs将是根文件系统rootfs。
start_kernel(void)中输出的上面的这句信息。
这行命令是在linux内核启动过程中都会输出的一句。
Console:
colourdummydevice80x30
代码中console_init()的输出信息,显示控制台属性:
一般使用VGAtextconsole,标准是80X25行列的文本控制台,这里是对属性进行了设置。
serial_xx:
setup_console@115
串口设置值为115200,此为波特率输出信息。
对串口设置的信息做一个打印的动作,在调试时会非常有用。
Calibratingdelayloop...82.94BogoMIPS
Bogomips
Bogomips,是由linusTorvalds写的,是Linux操作系统中衡量计算机处理器运行速度的一种尺度。
提供这种度量的程序被称为BogoMips,当启动计算机时,BogoMips能显示系统选项是否处于最佳性能。
linux内核中有一个函数calibrate_delay(),它可以计算出cpu在一秒钟内执行了多少次一个极短的循环,计算出来的值经过处理后得到BogoMIPS值。
你可以将计算机的bogomips与计算机处理器的bogomips进行比较。
Torvalds称这个程序为BogoMips来暗示两台计算机间的性能度量是错误的,因为并非所有起作用因素都能被显示出来或被认可。
尽管计算机基准中经常用到MIPS,但环境的变化容易导致度量的错误。
Bogomips能测出一秒钟内某程序运行了多少次。
察看/proc/cpuinfo文件中的最后一行也能得到这个数值。
Calibrate:
校准,进入时延校准循环。
检查CPU的MIPS(每秒百万条指令),Bogo是Bogus(伪)的意思。
这里是对CPU进行一个实时测试,来得到一个大体的MIPS数值。
上面这个输出,在所有的linux系统启动中都会打印出来。
进入内存初始化:
mem_init(void),[arch/i386/mm/init.c]
Memory:
80MB=80MBtotal
Memory:
76592KBavailable(1724Kcode,2565Kdata,72Kinit)
当前内存使用情况,将列出总的内存大小,及分配给内核的内存大小:
包括代码部分,数据部分,初始化部分,总共刚好4M。
请留意此处的内核的内存大小的各个值。
进入虚拟文件系统VFS初始化:
vfs_caches_init()
Dentrycachehashtableentries:
16384(order:
5,131072bytes)
Inodecachehashtableentries:
8192(order:
4,65536bytes)
Mountcachehashtableentries:
512(order:
0,4096bytes)
Buffercachehashtableentries:
4096(order:
2,16384bytes)
Page-cachehashtableentries:
32768(order:
5,131072bytes)
名词:
∙①Dentry:
目录数据结构
∙②Inode:
i节点
∙③Mountcache:
文件系统加载缓冲
∙④buffercache:
内存缓冲区
∙⑤PageCache:
页缓冲区
Dentry目录数据结构(目录入口缓存),提供了一个将路径名转化为特定的dentry的一个快的查找机制,Dentry只存在于RAM中;i节点(inode)数据结构存放磁盘上的一个文件或目录的信息,i节点存在于磁盘驱动器上;存在于RAM中的i节点就是VFS的i节点,dentry所包含的指针指向的就是它;buffercache内存缓冲区,类似kupdated,用来在内存与磁盘间做缓冲处理;
在内存中建立各个缓冲hash表,为kernel对文件系统的访问做准备。
VFS(virtualfilesystemswitch)虚拟文件切换目录树有用到类似这样的结构表。
上面的输出信息,在一般的linux启动过程中都会看到。
POSIXconformancetestingbyUNIFIX
conformance:
顺应,一致。
即POSIX适应性检测。
UNIFIX是一家德国的技术公司,Linux原本要基于POSIX.1的,但是POSIX不是免费的,而且POSIX.1证书相当昂贵.这使得Linux基于POSIX开发相当困难.Unifix公司(Braunschweig,德国)开发