嵌入式linux启动信息完全注释

来源:互联网 发布:js改变html属性值 编辑:程序博客网 时间:2024/06/04 19:34
摘要
我们在这里讨论的是对嵌入式linux系统的启动过程的输出信息的注释,通过我们的讨论,大家会对嵌入式linux启动过程中出现的、以前感觉熟悉的、但却又似是而非的东西有一个确切的了解,并且能了解到这些输出信息的来龙去脉。
嵌入式linux的启动信息是个很值得我们去好好研究的东西,他能将一幅缩影图呈现在我们面前,来指导我们更加深入地理解linux内核。

关键字:linux,嵌入式,启动,bootloader
正文
作为一名嵌入系统研发者,您一定碰到过下面的情景:
在某论坛上看到一篇帖子,上面贴着嵌入式linux研发板启动时的有关信息,然后大家在帖子里讨论着这个启动过程中出现的问题,随机举例如下:
Linux version 2.4.20-uc0 (root@Local) (gcc version 2.95.3
20010315 (release)(ColdFire patches - 20010318 from http://f
(uClinux XIP and shared lib patches from http://www.snapgear.com/)) #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
上面的这些输出信息,也可能包括您自己正在做的嵌入式linux研发板的输出信息,其中的每一行,每一个字的含义,您是否深究过,或说大部分的含义您能确切地知道的?本人想在这里结合本人在实践中一些体会来和广大嵌入式linux的研发者一起读懂这些信息。
我们在这里将以一个真实的嵌入式linux系统的启动过程为例,来分析这些输出信息。启动信息的原始内容将用标记标出,以区别和注释。

嵌入式linux的启动主要分为两个阶段:
①     第一部分bootloader启动阶段
②     第二部分linux 内核初始化和启动阶段
第一节:start_kernel
第二节:用户模式( user_mode )开始,start_kernel结束
第三节:加载linux内核完毕,转入cpu_idle进程

第一部分 : bootloader启动
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等。
Loaded to 0x90060000
将bootloader加载到内存ram中的0x90060000处,即将bootloader加载到内存的高端地址处。
Linux内核将被bootloader加载到0x90090000处。

Found boot configuration
查找到了启动boot的配置信息

Booted from parallel 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类型特点有个比较明确的了解。

CPU clock rate: 200 MHz
研发板上所使用的CPU的主频为200MHZ.

DRAM size is 128MB (128MB/0MB)
动态内存ram大小为128M。这里我们列举一下内存的类型及工作原理。
根据内存的工作原理能够划分出两种内存:DRAM和SRAM
①DRAM表示动态随机存取存储器。这是一种以电荷形式进行存储的半导体存储器。DRAM中的每个存储单元由一个晶体管和一个电容器组成。数据存储在电容器中。电容器会由于漏电而导致电荷丢失,因而DRAM器件是不稳定的。为了将数据保存在存储器中,DRAM器件必须有规律地进行刷新。
②SRAM是静态的,因此只要供电他就会保持一个值。一般而言,SRAM 比DRAM要快,这是因为SRAM没有刷新周期。每个SRAM存储单元由6个晶体管组成,而DRAM存储单元由一个晶体管和一个电容器组成。相比而言,DRAM比SRAM每个存储单元的成本要高。照此推理,能够断定在给定的固定区域内DRAM的密度比SRAM 的密度要大。

SRAM常常用于高速缓冲存储器,因为他有更高的速率;而DRAM常常用于PC中的主存储器,因为其拥有更高的密度。
在嵌入式系统中使用DRAM内存的设计比较广泛。

地址辅助说明:
先说明一下内存地址数字情况,主要是为了方便记忆。
能够访问的内存为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,以此类推。

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:”就是虚拟文档系统管理器操作时的输出信息了。
File linux.bin.gz found
linux kernel内核文档名,他是在只读文档系统romfs上的一个组成部分。
Unzipping image from 0x4639DE60 to 0x90090000, size = 1316021
将romfs中的linux kernel解压缩到0x90090000,之后会从这个内存地址启动内核。romfs为压缩格式文档,使用压缩的只读文档系统,是为了保持制作出来的整个系统所占用的flash空间减小。这个内核的大小为1.3M左右,这也是现在大多数嵌入系统所使用的方法。
Inptr = 0x00000014(20)
Inflating....
释放,解压中。。。(变大,充气, 膨胀)
Outcnt = 0x0030e7c8(3205064)
Final Inptr = 0x001414ad(1316013)
Original CRC = 0xcbd73adb
Computed CRC = 0xcbd73adb
做释放后的CRC检查
Boot kernel at 0x90090000 with ROMFS at 0x46040000
kernel已被从romfs中释放到内存地址0x90090000处,能够跳转到此处启动kernel了,这里是指定的kernel的起始地址
Press 'enter' to boot
系统等待启动,后面将看到linux kernel的启动过程了。
 
第二部分 : linux内核初始化连同启动
第一节:start_kernel
Linux的源代码能够从
www.kernel.org
得到,或您能够查看linux代码交叉引用网站:
http://lxr.linux.no/
进行在线的代码查看,这是个很好的工具网站。
在start_kernel中将调用到大量的init函数,来完成内核的各种初始化。如:
page_address_init();
sched_init();
page_alloc_init();
init_IRQ();
softirq_init();
console_init();
calibrate_delay();
vfs_caches_init(num_physpages);
rest_init();
具体内容能够参考[http://lxr.linux.no/source/init/main.c]
Linux version 2.4.22-uc0 (root@local) (gcc version 2.95.3 20010315 (release)) #33 .?1.. 20 12:09:106
上面的代码输出信息,是跟踪linux代码分析后得到的,进入init目录下的main.c的start_kernel启动函数.
嵌入式linux使用的是linux内核版本为2.4.22
linux source code代码中start_kernel中输出的linux_banner信息。这个信息是每个linux kernel都会打印一下的信息,假如您没有把这句去掉的话。
Found bootloader memory map at 0x10000fc0.
bootloader经过内存映射后的地址为:0x10000fc0, 按上面的地址换算方法,1后面有7个0,那么虚拟地址256M左右处。
Processor: ARM pt110 revision 0
pT110是ARM微处理器arm核的一种,另一种为pT100。此处为显示ARM的类型。
On node 0 totalpages: 20480
zone(0): 20480 pages.
zone(0): Set minimum memory threshold to 12288KB
Warning: wrong zone alignment (0x90080000, 0x0000000c, 0x00001000)
zone(1): 0 pages.
zone(2): 0 pages.
预留内存大小,在节点0上总共20页, zone(0) 配置最小内存为12MB, zone(1)和zone(2)为0页。警告:对齐不正确
Kernel command line: root=/dev/mtdblock3
Kernel 启动命令设为:/dev/mtdblock3(在后面的说明中会看到mtdblock3是指的flash上的romfs分区。),用来指定根文档系统所在的位置,kernel会将块设备mtdblock3当作文档系统来处理。
也就是说,内核会根据上面的kernel命令行,知道只读文档系统romfs将是根文档系统rootfs。
start_kernel(void)中输出的上面的这句信息。
这行命令是在linux内核启动过程中都会输出的一句。
Console: colour dummy device 80x30
代码中console_init()的输出信息, 显示控制台属性:一般使用VGA text console,标准是80 X 25行列的文本控制台,这里是对属性进行了配置。
serial_xx: setup_console @ 115
串口配置值为115200,此为波特率输出信息。对串口配置的信息做一个打印的动作,在调试时会很有用。
Calibrating delay loop... 82.94 BogoMIPS
Calibrate:校准, 进入时延校准循环。检查CPU的MIPS(每秒百万条指令),Bogo是Bogus(伪)的意思。这里是对CPU进行一个实时测试,来得到一个大体的MIPS数值
Bogomips,是由linus Torvalds写的, 是Linux操作系统中衡量电脑处理器运行速度的一种尺度。提供这种度量的程式被称为BogoMips,当启动电脑时,BogoMips能显示系统选项是否处于最好性能。
linux内核中有一个函数calibrate_delay(),他能够计算出cpu在一秒钟内执行了多少次一个极短的循环,计算出来的值经过处理后得到BogoMIPS值
您能够将电脑的bogomips和电脑处理器的bogomips进行比较。Torvalds称这个程式为BogoMips来暗示两台电脑间的性能度量是错误的,因为并非任何起作用因素都能被显示出来或被认可。尽管电脑基准中经常用到MIPS,但环境的变化容易导致度量的错误。Bogomips能测出一秒钟内某程式运行了多少次。
察看/proc/cpuinfo文档中的最后一行也能得到这个数值。
上面这个输出,在任何的linux系统启动中都会打印出来。

进入内存初始化
mem_init(void), [arch/i386/mm/init.c]
Memory: 80MB = 80MB total
Memory: 76592KB available (1724K code, 2565K data, 72K init)
当前内存使用情况,将列出总的内存大小, 及分配给内核的内存大小:包括代码部分,数据部分,初始化部分,总共刚好4M。请留意此处的内核的内存大小的各个值。

进入虚拟文档系统VFS初始化
vfs_caches_init()
Dentry cache hash table entries: 16384 (order: 5, 131072 bytes)
Inode cache hash table entries: 8192 (order: 4, 65536 bytes)
Mount cache hash table entries: 512 (order: 0, 4096 bytes)
Buffer cache hash table entries: 4096 (order: 2, 16384 bytes)
Page-cache hash table entries: 32768 (order: 5, 131072 bytes)
名词:
①     Dentry:目录数据结构
②     Inode:i节点
③     Mount cache:文档系统加载缓冲
④     buffer cache:内存缓冲区
⑤     Page Cache:页缓冲区
Dentry目录数据结构(目录入口缓存),提供了一个将路径名转化为特定的dentry的一个快的查找机制,Dentry只存在于RAM中;
i节点(inode)数据结构存放磁盘上的一个文档或目录的信息,i节点存在于磁盘驱动器上;存在于RAM中的i节点就是VFS的i节点,dentry所包含的指针指向的就是他;
buffer cache内存缓冲区,类似kupdated,用来在内存和磁盘间做缓冲处理;
Page Cache 用来加快对磁盘上映像和数据的访问。
在内存中建立各个缓冲hash表,为kernel对文档系统的访问做准备。
VFS(virtual filesystem switch)虚拟文档转换目录树有用到类似这样的结构表。
上面的输出信息,在一般的linux启动过程中都会看到。
POSIX conformance testing by UNIFIX
conformance:顺应, 一致。即POSIX适应性检测。UNIFIX是一家德国的技术公司,Linux 原本要基于 POSIX.1 的, 但是 POSIX 不是免费的, 而且 POSIX.1 证书相当昂贵. 这使得 Linux 基于 POSIX 研发相当困难. Unifix公司(Braunschweig, 德国) 研发了一个获得了 FIPS 151-2 证书的 Linux 系统. 这种技术用于 Unifix 的发行版 Unifix Linux 2.0 和 Lasermoon 的 Linux-FT。
在2.6的内核中就将上面的这句输出给拿掉了。

第二节:用户模式( user_mode )开始,start_kernel结束
PCI: bus0: Fast back to back transfers disabled
PCI: Configured XX as a PCI slave with 128MB PCI memory
PCI: Each Region size is 16384KB
PCI: Reserved memory from 0x10080000 to 0x15080000 for DMA and mapped to 0x12000000
设备的初始化 init()--->do_basic_init()--->pci_init(),初始化PCI,检测系统的PCI设备。
Linux NET4.0 for Linux 2.4
Based upon Swansea University Computer Society NET3.039
英国威尔士,斯旺西大学的NET3.039, TCP/IP 协议栈
此信息,在linux启动过程中都会出现。
Initializing RT netlink socket
对Socket的初始化,socket_init(),Netlink 一种路由器管理协议(linux-2.4.22\net\core\Rtnetlink.c,Routing netlink socket interface: protocol independent part。 其中RT是route路由的意思。这句输出是在create产生rtnetlink的socket套接字时的一个调试输出。)
此信息,在linux启动过程中都会出现。
Starting kswapd
启动交换守护进程kswapd,进程IO操作例程kpiod
kswapd能够配合kpiod运行。进程有时候无事可做,当他运行时也不一定需要把其任何的代码和数据都放在内存中。这就意味着我们能够通过把运行中程式不用的内容转换到交换分区来更好的是利用内存。大约每隔1秒,kswapd醒来并检查内存情况。假如在硬盘的东西要读入内存,或内存可用空间不足,kpiod就会被调用来做移入/移出操作。kswapd负责检查,kpiod负责移动。
Journalled Block Device driver loaded
加载日志块设备驱动。
日志块设备是用来对文档系统进行日志记录的一个块设备。日志文档系统是在传统文档系统的基础上,加入文档系统更改的日志记录。
他的设计思想是:跟踪记录文档系统的变化,并将变化内容记录入日志。日志文档系统在磁盘分区中保存有日志记录,写操作首先是对记录文档进行操作,若整个写操作由于某种原因(如系统掉电)而中断,系统重启时,会根据日志记录来恢复中断前的写操作。在日志文档系统中,任何的文档系统的变化都被记录到日志,每隔一定时间,文档系统会将更新后的元数据及文档内容写入磁盘。在对元数据做任何改变以前,文档系统驱动程式会向日志中写入一个条目,这个条目描述了他将要做些什么,然后他修改元数据。
devfs: v1.12c (20020818) Richard Gooch (rgooch@atnf.csiro.au)
devfs: boot_options: 0x1
Devfs模块的输出信息。
设备文档系统devfs,版本1.12c,
pty: 256 Unix98 ptys configured
Pty模块的输出信息,和控制台操作有关的配置。
将通过 devpts 文档系统使用 Unix98 PTYs,(Pseudo-ttys (telnet etc) device是伪ttys设备的缩写。
①              TTY(/dev/tty)是TeleTYpe的一个老缩写,为用户输入提供不同控制台的设备驱动程式。他的名字来源于实际挂接到 UNIX系统的、被称为电传打字机(teletype)的终端。在Linux下,这些文档提供对虚拟控制台的支持,能够通过按<Alt-F1>到<Alt-F6>键来访问这些虚拟控制台。这些虚拟控制台提供单独的、同时进行的本地登录对话过程
②              ttys(/dev/ttys)是电脑终端的串行接口。/dev/ttyS0对应MS-DOS下的 COM1。

使用 make dev脚本MAKEDEV来建立pty文档。这样系统内核就支持Unix98风格的pty了。在进行Telnet登录时将要用到/dev/pty设备。 pty是伪终端设备,在远程登录等需要以终端方式进行连接,但又并非真实终端的应用程式中必须使用这种设备,如telnet或xterm等程式。Linux 2.2以后增添了UNIX98风格的Pty设备,他使用一个新的文档系统(devpts针对伪终端的文档系统)和一个克隆的设备cloning device来实现其功能。
linux-2.4.22\drivers\char\Pty.c, 在devfs_mk_dir (NULL, "pts", NULL);时会输出上面的信息。

loop: loaded (max 8 devices)
加载返还块设备驱动,最多支持8个设备

8139too Fast Ethernet driver 0.9.27
eth0: RealTek RTL8139 at 0x60112000, 00:10:0d:42:a0:03, IRQ 14
eth0: Identified 8139 chip type 'RTL-8100B/8139D'
网卡驱动,基地址为:0x60112000, MAC地址:00:10:0d:42:a0:03, 中断号:14
RTL8139 的接收路径设计成一个环形缓冲区(一段线性的内存,映射成一个环形内存)。当设备接收到数据时,数据的内容就保存在这个环形缓冲区内并更新下个存储数据的地址(第一个数据包的开始地址+第一个数据包的长度)。设备会一直保留缓冲区内的数据直到整个缓冲区耗尽。这样,设备会再次重写缓冲区内起始位置的内容,就像一个环那样。
从 2.2 版内核升级到 2.4 版时, RTL-8139 支持模块已不再叫 rtl8139,而叫他 8139too,现在您再看到8139too就不会不明白他的来由了吧。
SCSI subsystem driver Revision: 1.00
USB设备信息,USB会被当做SCSI来处理。
mumk_register_tasklet: (1) tasklet 0x905bf9c0 status @0x9025e974
软中断信息输出。Tasklet是在2.4中才出现,他是为了更好地利用多CPU。

Probing XX Flash Memory
探测 XX的闪存(Flash Memory),"NOR NAND Flash Memory Technology"
Amd/Fujitsu Extended Query Table v1.3 at 0x0040
number of CFI chips: 1
AMD和富士通合资设立的Flash供货商Spansion。AMD因获利不佳,已退出Flash市场,后续由Spansion合资公司经营.主要生产NOR类型的flash,特点是容量小,速度快。Spansion商标的flash,在我们研发中会经常看到。以后大家看到Spansion的芯片,就能了解到他和AMD更有富士通的来龙去脉了。
Common flash Interface (CFI)是指一个统一的flash访问接口,表示这种flash是这种接口类型的。
Using buffer write method
使用flash写缓冲方式
flash提供了写BUFFER的命令来加快对flash上块的操作。对Flash擦除和写数据是很慢的。假如用写BUFFER的命令会快一点。据手册上说,会快20倍。Buffer Size :5 bytes的buffer缓冲不是每个块都有,是整个flash只有一个5 bytes的buffer,用写BUFFER命令对任何的块进行写操作,都要用同一个buffer,写Buffer是主要检查buffer是否available,其实buffer起缓冲作用,来提高工作效率。
比如某flash有128个128K字节块。允许用户对任意块进行字节编程和写缓冲器字节编程操作,每字节编程时间为210μs;若采用写缓冲器字节编程方式,32字节编程共需218μs,每字节编程时间仅为6.8μs。芯片的块擦除时间为1s,允许在编程或块擦除操作的同时进行悬挂中断去进行读操作,待读操作完成后,写入悬挂恢复命令,再继续编程或块擦除。

Creating 3 MTD partitions on "XX mapped flash":
0x00000000-0x00020000 : "BootLoader"
0x00020000-0x00040000 : "Config"
0x00040000-0x01000000 : "Romfs"
此处为重要信息部分,需要特别留意。
在内存中映射过的flash,创建三个MTD分区:
flash上的内容将被映射到内存中的对应地址
前128K为BootLoader--->0x00000000-0x00020000
接着的128K为系统配置信息Config存放的位置--->0x00020000-0x00040000
再后面的 16M - 2X128K 为romfs的存放处.--->0x00040000-0x01000000
上面的内容,大家能够根据前面的换算公式得到。

A> 编译的bootloader一般大小约50K左右;
B> 在此处就知道了配置信息config是放在第2分区中的;
C> 制作的romfs的大小,一般为8M或10M左右,所以能放得下;
嵌入式Linux内核的块设备驱动:
对于linux 的根文档系统,现在有三种块设备的驱动能够选择,他们分别是:
a) Blkmem 驱动
b) MTD 驱动
c) RAM disk 驱动
Blkmem 驱动是专门为嵌入式linux 研发的一种块设备驱动,他是嵌入式linux系统中最为古老和通用的块设备驱动。他原理相对简单但是配置比较复杂,需要根据您即的Flash的分区使用情况来修改代码。当然修改的结果是他能够对一些NOR型的Flash进行读写操作。但是现在支持的Flash类型不够多。假如新加入对一种Flash的支持需要作的工作量比较大。
Linux的MTD驱动是标准Linux的Flash驱动。他支持大量的设备,有足够的功能来定义Flash的分区,进行地址映射等等。使用MTD您能够在一个系统中使用不同类型的Flash。他能够将不同的Flash组合成一个线性的地址让您来使用。
在标准的Linux 2.4内核中MTD有一系列的选项,您能够根据个人系统的需要来选择,定制。
另外一种选择就是RAM disk 驱动。在PC上他经常用于没有硬盘的Linux的启动过程。他和Flash没有直接的关系。但是当Flash上启动的是经过压缩的内核时。RAM disk 能够作为根文档系统。
MTD 驱动提供了对Flash强大的支持,您通过他甚至能够在Flash上运行一个能够读写的真正的文档系统,比如JFFS2。而Blkmem驱动则望尘莫及。
NET4: Linux TCP/IP 1.0 for NET4.0
调用inet_init [ linux-2.4.22\net\ipv4\Af_inet.c ]时的输出信息, 在启动过程中被socket.c调用到。
IP Protocols: ICMP, UDP, TCP, IGMP
列出能够支持的IP协议,此处为kernel源代码inet_add_protocol(p);的输出。
在linux启动过程中,都会看到这句的输出。
IP: routing cache hash table of 512 buckets, 4Kbytes
IP路由代码的输出信息。
ip_rt_init [ linux-2.4.22\net\ipv4\Route.c ],Set the IP module up,路由缓冲hash表
TCP: Hash tables configured (established 8192 bind 8192)
TCP协议初始化输出信息。tcp_init [ linux-2.4.22\net\ipv4\Tcp.c ],
NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
UNIX网络协议信息。
af_unix_init[ linux-2.4.22\net\unix\Af_unix.c ], 多种连接的一种(IPv4, UNIX domain sockets, IPv6和IrDA). SMP 对称多处理器—Symmetrical Multi Processing,这里主要是指UNIX的一些网络协议.

上面的关于网络的输出信息是在linux启动信息中都会出现的。
加载各种文档系统
cramfs: wrong magic
会出现“cramfs: wrong magic”,别担心这没有什么害处,这个是kernel的书写bug,在2.6中有修改之,他是个警告信息,用来检查cramfs的superblock终极块的。superblock也是VFS要用到的数据结构。
代码linux-2.4.22\fs\cramfs\Inode.c:
2.4
cramfs_read_super(。。。)
/* Do sanity checks on the superblock */
       if (super.magic != CRAMFS_MAGIC) {
              /* check at 512 byte offset */
              memcpy(&super, cramfs_read(sb, 512, sizeof(super)), sizeof(super));
              if (super.magic != CRAMFS_MAGIC) {
                     printk(KERN_ERR "cramfs: wrong magic\n");
                     goto out;
              }
       }

2.6
if (super.magic != CRAMFS_MAGIC) {
                         if (!silent)
                                 printk(KERN_ERR "cramfs: wrong magic\n");
                         goto out;
                 }
终极块是文档系统的“头部”。他包含文档系统的状态、尺寸和空闲磁盘块等信息。假如损坏了一个文档系统的终极块(例如不小心直接将数据写到了文档系统的终极块分区中),那么系统可能会完全不识别该文档系统,这样也就不能安装他了,即使采用e2fsck 命令也不能处理这个问题。

Cramfs文档系统:
cramfs 是 Linus Torvalds 本人研发的一个适用于嵌入式系统的小文档系统。由于他是只读的,所以,虽然他采取了 zlib 做压缩,但是他还是能够做到高效的随机读取。 cramfs 不会影响系统读取文档的速度,又是个高度压缩的文档系统。
我们制作image文档之后,我们还要考虑怎样才能在系统运行的时候,把这个 image 文档 mount 上来,成为一个可用的文档系统。由于这个 image 文档不是个通常意义上的 block 设备,我们必须采用 loopback 设备来完成这一任务,如:
mount -o loop -t cramfs /usr.img /usr
这样,就能够经由 loopback 设备,把 usr.img 这个 cramfs 的 image 文档 mount 到 /usr 目录上去了。内核中需要对loopback这个设备的支持。
cramfs 的压缩效率一般都能达到将近 50%。
Cramfs通过优化索引节点表的尺寸和除去传统文档系统中文档之间的空间浪费来达到节约空间的目的。他还使用了zlib压缩,实现优于2:1的压缩比例。解压缩过程的系统开销并不是很大,因为Cramfs支持指定单块的解压,而并不必解压缩整个文档。
Cramfs不但能节省空间,还能避免非正常关机导致的等待fsck或手工进行fsck的麻烦。他通过只读的方式达到这一目的。
RamDisk有三种实现方式:
在Linux中能够将一部分内存mount为分区来使用,通常称之为RamDisk,分为:
Ramdisk, ramfs, tmpfs.
① 第一种就是传统意义上的,能够格式化,然后加载。
这在Linux内核2.0/2.2就已支持,其不足之处是大小固定,之后不能改变。
为了能够使用Ramdisk,我们在编译内核时须将block device中的Ramdisk支持选上,他下面更有两个选项,一个是设定Ramdisk的大小,默认是4096k;另一个是initrd的支持。
假如对Ramdisk的支持已编译进内核,我们就能够使用他了:
首先查看一下可用的RamDisk,使用ls /dev/ram*
首先创建一个目录,比如test,运行mkdir /mnt/test;
然后对/dev/ram0 创建文档系统,运行mke2fs /dev/ram0;
最后挂载 /dev/ram0,运行mount /dev/ram /mnt/test,就能够象对普通硬盘相同对他进行操作了。
② 另两种则是内核2.4才支持的,通过Ramfs或Tmpfs来实现:
他们不需经过格式化,用起来灵活,其大小随所需要的空间而增加或减少。
Ramfs顾名思义是内存文档系统,他处于虚拟文档系统(VFS)层,而不像ramdisk那样基于虚拟在内存中的其他文档系统(ex2fs)。
因而,他无需格式化,能够创建多个,只要内存足够,在创建时能够指定其最大能使用的内存大小。
假如您的Linux已将Ramfs编译进内核,您就能够很容易地使用Ramfs了。创建一个目录,加载Ramfs到该目录即可:
# mkdir /testRam
# mount -t ramfs none /testRAM
缺省情况下,Ramfs被限制最多可使用内存大小的一半。能够通过maxsize(以kbyte为单位)选项来改变。
# mount -t ramfs none /testRAM -o maxsize=2000 (创建了一个限定最大使用内存为2M的ramdisk)
③ Tmpfs是个虚拟内存文档系统,他不同于传统的用块设备形式来实现的Ramdisk,也不同于针对物理内存的Ramfs。
Tmpfs能够使用物理内存,也能够使用交换分区。在Linux内核中,虚拟内存资源由物理内存(RAM)和交换分区组成,这些资源是由内核中的虚拟内存子系统来负责分配和管理。
Tmpfs向虚拟内存子系统请求页来存储文档,他同Linux的其他请求页的部分相同,不知道分配给自己的页是在内存中还是在交换分区中。同Ramfs相同,其大小也不是固定的,而是随着所需要的空间而动态的增减。
使用tmpfs,首先您编译内核时得选择"虚拟内存文档系统支持(Virtual memory filesystem support)" 。
然后就能够加载tmpfs文档系统了:
# mkdir -p /mnt/tmpfs
# mount tmpfs /mnt/tmpfs -t tmpfs
同样能够在加载时指定tmpfs文档系统大小的最大限制:
# mount tmpfs /mnt/tmpfs -t tmpfs -o size=32m
FAT: bogus logical sector size 21072
具体的文档系统FAT格式。
虚拟逻辑扇区大小为20K,linux-2.4.22\fs\fat\Inode.c。
在初始化MS-DOS文档系统时,读MS-DOS文档系统的superblock,函数fat_read_super中输出的上面的信息。
UMSDOS: msdos_read_super failed, mount aborted.
UMSDOS:一种文档系统,特点容量大但相对而言不大稳定。是Linux 使用的扩展了的DOS文档系统。他在 DOS 文档系统下增加了长文档名、 UID/GID、POSIX 权限和特别文档 (设备、命名管道等)功能,而不牺牲对 DOS 的兼容性。允许一个普通的msdos文档系统用于Linux,而且无须为他建立单独的分区,特别适合早期的硬盘空间不足的硬件条件。
VFS: Mounted root (romfs filesystem) readonly
虚拟文档系统VFS(Virtual Filesystem Switch)的输出信息。
再次强调一下一个概念。VFS 是一种软件机制,也可称他为 Linux 的文档系统管理者,他是用来管理实际文档系统的挂载点,目的是为了能支持多种文档系统。kernel会先在内存中建立一颗 VFS 目录树,是内存中的一个数据对象,然后在其下挂载rootfs文档系统,还能够挂载其他类型的文档系统到某个子目录上。
Mounted devfs on /dev
加载devfs设备管理文档系统到dev安装点上。
/dev是我们经常会用到的一个目录。
在2.4的kernel中才有使用到。每次启动时内核会自动挂载devfs。
devfs提供了访问内核设备的命名空间。他并不是建立或更改设备节点,devfs只是为您的特别文档系统进行维护。一般我们能够手工mknod创件设备节点。/dev目录最初是空的,里面特定的文档是在系统启动时、或是加载模组后驱动程式载入时建立的。当模组和驱动程式卸载时,文档就消失了。
Freeing init memory: 72K
释放1号用户进程init所占用的内存。

第三节:加载linux内核完毕,转入cpu_idle进程

系统启动过程中进程情况:
①init进程
一般来说, 系统在跑完 kernel bootstrapping 内核引导自举后(被装入内存、已开始运行、已初始化了任何的设备驱动程式和数据结构等等), 就去运行 init『万process之父』, 有了他, 才能开始跑其他的进程,因此,init进程,他是内核启动的第一个用户级进程,他的进程号总是1。
您能够用进程查看命令来验证
# ps aux
PID Uid VmSize Stat Command
1 0 SW init
2 0 SW [keventd]
3 0 SWN [ksoftirqd_CPU0]
4 0 SW [kswapd]
5 0 SW [bdflush]
6 0 SW [kupdated]
7 0 SW [rbwdg]
9 0 SW [mtdblockd]
10 0 SW [khubd]
80 0 SW [loop0]
另外 Linux 有两个 kernel 类的 process 也开始跑了起来,一个是 kflushd/bdflush,另一个是 kswapd;
只有这个 init 是完全属于 user 类的进程, 后两者是 kernel假借 process 进程之名挂在进程上。
init有许多很重要的任务,比如象启动getty(用于用户登录)、实现运行级别、连同处理孤立进程。
init 一开始就去读 /etc/inittab (init初始化表),初始化表是按一定格式排列的关于进程运行时的有关信息的。init程式需要读取/etc/inittab文档作为其行为指针。这个 inittab 中对于各个runlevel运行级别要跑哪些 rc 或 spawn 生出什么有很清楚的设定。
一般, 在Linux中初始化脚本在/etc/inittab 文档(或称初始化表)中能够找到关于不同运行级别的描述。inittab是以行为单位的描述性(非执行性)文本,每一个指令行都是固定格式
inittab中有respawn项,但假如一个命令运行时失败了,为了避免重运行的频率太高,init将追踪一个命令重运行了多少次,并且假如重运行的频率太高,他将被延时五分钟后再运行。
② kernel进程
A> 请注意init是1号进程,其他进程id分别是kflushd/ bdflush, kupdate, kpiod and kswapd。这里有一个要指出的:您会注意到虚拟占用(SIZE)和实际占用(RSS)列都是0,进程怎么会不使用内存呢?
这些进程就是内核守护进程。大部分内核并不显示在进程列表里。守护进程在init之后启动,所以他们和其他进程相同有进程ID,但是他们的代码和数据都存放在内核占有的内存中。在列表中使用中括号来区别和其他进程。
B> 输入和输出是通过内存中的缓冲来完成的,这让事情变得更快,程式的写入会存放在内存缓冲中,然后再一起写入硬盘。守护进程kflushd和kupdate 管理这些工作。kupdate间断的工作(每5秒)来检查是否有写过的缓冲,如过有,就让kflushd把他们写入磁盘。
C> 进程有时候无事可做,当他运行时也不一定需要把其任何的代码和数据都放在内存中。这就意味着我们能够通过把运行中程式不用的内容转换到交换分区来更好的是利用内存。把这些进程数据移入/移出内存通过进程IO管理守护进程kpiod和交换守护进程kswapd,大约每隔1秒,kswapd醒来并检查内存情况。假如在硬盘的东西要读入内存,或内存可用空间不足,kpiod就会被调用来做移入/移出操作。
D> bdflush - BUF_DIRTY, 将dirty缓存写回到磁盘的核心守护进程。 对于有许多脏的缓冲区(包含必须同时写到磁盘的数据的缓冲区)的系统提供了动态的响应。他在系统启动的时候作为一个核心线程启动,他叫自己为“kflushd”,而这是您用ps显示系统中的进程的时候您会看得的名字。即定期(5秒)将脏(dirty)缓冲区的内容写入磁盘,以腾出内存;
E> ksoftirqd_CPUx 是个死循环, 负责处理软中断的。他是用来对软中断队列进行缓冲处理的进程。当发生软中断时,系统并不急于处理,只是将相应的cpu的中断状态结构中的active 的相应的位,置位,并将相应的处理函数挂到相应的队列,然后等待调度时机来临,再来处理.
ksoftirqd_CPUx是由cpu_raise_softirq()即cpu触发中断,唤醒的内核线程,这涉及到软中断,ksoftirqd的代码参见 [kernel/softirq.c]
F> keventd,他的任务就是执行 scheduler 调度器队列中的任务,keventd 为他运行的任务提供了可预期的进程上下文。
G> khubd, 是用来检测USB hub设备的,当usb有动态插拔时,将交由此内核进程来处理。在检测到有hub事件时会有相应的动作(usb_hub_events())
H> mtdblockd是用来对flash块设备进行写操作的守护进程。
NAND类型的Flash需要MTD(Memory Technology Devices 内存技术驱动程式)驱动的支持才能被linux所使用。
NAND的特点是不能在芯片内执行(XIP,eXecute In Place),需要把代码读到系统RAM中再执行,传输效率不是最高,最大擦写次数量为一百万次,但写入和擦除的速度很快,擦除单元小,是高数据存储密度的最好选择。
NAND需要I/O接口,因此使用时需要驱动程式。
I> loop0 是负责处理loop块设备的(回环设备)。loopback device指的就是拿文档来模拟块设备, 在我们这里,loop设备主要用来处理需要mount到板上的文档系统,类似mount /tmp/rootfs /mnt -o loop。.我们的实例有:mount -o loop -t cramfs /xxx.bin /xxx 也就是将xxx.bin这个文档mount到板上来模拟cramfs压缩ram文档系统。loop0进程负责对loop设备进行操作。
loopback设备和其他的块设备的使用方法相同。特别的是,能够在该设备上建立一个文档系统,然后利用mount命令把该系统映射到某个目录下以便访问。这种整个建立在一个普通磁盘文档上的文档系统,就是虚拟文档系统 (virtual file system)。

总结:
上面的内容是本人为了在实际研发中更加清楚地了解嵌入式linux的启动过程而做的一个总结性的文章。
在对嵌入式linux的启动过程做了一个周详注释后,大家会对涉及到嵌入系统的各个概念有了一个更加明确的认识,并能对嵌入系统的软件和硬件环境的有关配置更加清楚。当您自己动手结合linux源代码来分析时,将会有一个清楚的全局观。
现在,您假如再回头去看文章前面所列出的启动信息例子中的内容,其中80%的内容,您现在应该能看懂他的来龙去脉了。
阅读(330) | 评论(0) | 转发(0) |
0

上一篇:Mysql使用基础知识

下一篇:在winxp下成功的安装cacti

相关热门文章
  • 蛋彩画
  • 用于C语言与SQL Server的嵌入...
  • 有既往病史者并非就一定不能购...
  • 一室两厅的小型影音室装修案例...
  • u-boot启动完全分析
  • 承接自动化测试培训、外包、实...
  • Solaris PowerTOP 1.0 发布
  • For STKMonitor
  • busybox的httpd使用CGI脚本(Bu...
  • 项目小体会
  • 请教想查12个月的数据条数,看...
  • new/delete 和malloc/free 有...
  • ubuntu下hadoop环境的搭建...
  • 求助:如何用Linux架设ISATAP...
  • redhat图形界面不出先登录界面...
给主人留下些什么吧!~~
原创粉丝点击