英文原文见于
http://www.ibm.com/developerworks/linux/tutorials/l-embedded-distro/section5.html
Boot loaders
What is a boot loader?
A boot loader (or bootstrap loader) is a program that loads another program. The boot loader is a small and specialized hunk of code, specific to a target system, that has just enough complexity to find the kernel and load it without being a full-featured kernel. Different systems use a variety of different boot loaders, from the huge and complicated BIOS programs common on desktop PCs, to very small and simple programs more common on embedded systems.
什么是Boot Loaders?boot loader(或者,bootstrap loader)是加载另一个程序的程序。boot loader是一段小的,特定的代码,针对于特定的目标系统,具有充分的复杂性,以便找到kernel,并将其加载到内存中,即使kernel并不不具备完全特性。不同的系统使用各种不同的boot loaders,从桌面PC上较普遍的巨大且复杂的BIOS程序到嵌入式系统中较普遍的短小且简单的程序。
A simple boot loader
The TS-7800 uses an unusually simple boot loader, which simply picks up the kernel from a predetermined partition of the SD card or on-board flash. A jumper determines whether the board looks first at the on-board flash, or at the SD cards. There are no other configuration settings. More complicated boot loaders (such asgrub
, commonly used on desktop PCs) have options for configuring kernel options and so on at boot time. On this system, the kernel's default options must be compiled in, as described previously.
The decision to compile in kernel options is a typical example of a choice that makes some sense in an embedded system, but would be uncomfortably limiting on a desktop.
一个简单的boot loaderTS-7800使用的不是平常的简单的boot loader,它从SD卡或者板载flash上预先定义好的分区加载kernel。跳线则决定了是先从板载flash还是先从sd卡寻找kernel。除此之外,没有其他的设置了。更复杂的boot loaders(比如,grub,通常用在桌面PC上)在启动时有选项可以配置内核选项。在该系统中,像之前描述的那样,内核的默认选项必须编译进内核中。
编译进内核的内核选项的决定,对于嵌入式系统而言,是有意义的选择的典型的例子,对桌面系统而言,则有让人感觉不太舒服的限制了。
Kernel formats
There are a variety of formats in which kernels are stored. The initial Linux kernel binary, namedvmlinux
, is rarely the file that a boot loader will work with. On the TS-7800, the boot loader can use two files, eitherImage
(uncompressed) or zImage
(compressed). These files are created in thearch/arm/boot
directory within the kernel tree.
People often describe the zImage
kernel as a compressed kernel, and so expect the boot loader to need to provide decompression. In fact, it's rather more clever. ThezImage
kernel is an uncompressed executable, which contains a particularly large static data object which is a compressed kernel image. When the boot loader loads and runs thezImage
executable, that executable then unpacks the kernel image and executes it. This way, you get most of the benefit of compression without imposing additional effort on the boot loader.
内核格式
内核能够以很多的格式进行存储。初始的Linux内核二进制文件,命名为vmlinux,而boot loader却很少与这个文件打交道。在TS-7800上,boot loader可以使用2个文件,Image(未压缩的),或者zImage(压缩的)。这些创建的文件位于内核树的arch/arm/boot目录下。
人们经常将zImage内核描述为压缩的内核,也因此,期望boot loader能够提供解压缩。事实上,可以更聪明些。zImage内核是一个未压缩的可执行文件,里边包含一个特别大的静态数据对象,即一个压缩的内核镜像。当boot loader加载并运行zImage可执行文件的时候,该可执行文件解包内核镜像并执行该镜像。用这个方法,你可以得到压缩带来的最多的好处,不用担心会对boot loader强加额外的工作。
Setting up the SD card
The SD card needs an MBR table containing DOS-style partition information. A sample MBR table is available for download from Technologic's site; this is for a 512MB card, but it is easy to edit the fourth partition to a size suiting whatever size card you want to use. The first three partitions are 4MB each; the first is unused on smaller cards, and the second and third hold the kernel and initial ramdisk image respectively.
For my purposes, I used the sfdisk
utility, which is not always recommended but has the desirable trait of trusting me when I ask it to create a partition that does not align on a partition boundary.
建立SD卡
SD卡需要一个MBR表,它包含DOS风格的分区信息。可以从Technologic的网址下载MBR表的一个样例,该样例是用于512MB的卡的,但是可以很容易的编辑第四个分区的大小以便与你想要使用的任何大小的卡相匹配。前3个分区,每个分区4MB;在较小的卡上,第一个分区并没有使用,第二个和第三个分区分别存储着内核和initial ramdisk镜像。
对于我的目的而言,我使用sfdisk工具,它是一个不总是能被推荐的工具,但它有一个令人期望的特点,当我让它在非分区边界对齐的位置创建分区的时候,它依然信任我。
Installing the initial kernel
The kernel for the TS-7800 is dumped directly into the second partition of the SD card. The exact path to the card depends on how you are accessing it; typically, if you have the card on a USB card reader, it will be detected as a SCSI device. Note that there is no file system access involved; the raw kernel is just dumped into the partition. Thedd
command copies raw data from one source to another, as in this example:
$ dd if=zImage of=/dev/sdd2 bs=16k
93+1 records in
93+1 records out
1536688 bytes (1.5 MB) copied, 0.847047 s, 1.8 MB/s
This command dumps raw data from the zImage
file to the second partition of/dev/sdd
, using 16KB blocks.
TS-7800的内核直接输出到SD卡的第二个分区。到SD卡的确切的路径依赖于你怎么样访问它;典型的情况是,如果你把SD卡插在了USB接口的读卡器上,它会被检测为一个SCSI设备。注意到,这里还没有文件系统访问的事;只是原始的内核被输出到了该分区而已。dd 命令将原始的数据从一个源拷贝到了另外一个,正如下面这个例子:
$dd if=zImage of=/dev/sdd2 bs=16k // 源为zImage,目的为 /dev/sdd2,块大小为16KBytes
93+1 records in
93+1 records out
1536688 bytes (1.5 MB) copied, 0.847047 s, 1.8 MB/s
该命令从zImage文件输出原始数据到/dev/sdd的第二个分区,使用的块大小是16KBytes。
A bit about block sizes
The output of this command is a little cryptic (as are its inputs, honestly). Whendd
runs, it copies data in "records," which are by default 512-byte blocks; this command specifies a block size of 16k (whichdd
understands to mean 16*1024).
The dd
command reports the amount of data copied first in blocks; the number after the plus sign is the number of partial blocks copied. In this case, because 1,536,688 is not an exact multiple of the block size, the remaining bytes of the file are read (and written) separately as a partial block. This information is harmless for most modern devices but crucial to diagnosing problems with some older ones.
The ability to control block sizes (and reblock data when transferring it) was exceptionally useful for working with tape devices and other specialized media that required writes to be of particular fixed sizes, and also helps for performance and reliability reasons with flash devices.
While the kernel device representing flash media can often take writes of arbitrary sizes, it is common for the underlying device to work only in full blocks, often of somewhat larger sizes (4KB or larger). To do a partial write, the flash device must extract the current contents of the full block, modify them with the input data, and flash the whole block back. If a device uses 4KB blocks, and you write to it in 512-byte blocks, each device block gets rewritten eight times for a single copy. This is bad for the device's longevity, and also bad for performance. (A 512-byte write of the same file was half as fast on the flash card I used.)
关于块的大小该命令的output有点神秘(诚实地讲,该命令的input也一样)。当 dd 运行的时候,它以“records”的形式拷贝数据,即,默认是512字节的块;而上面的命令则定义了一个16KBytes大小的块(dd 的理解是 16 * 1024)。
dd 命令首先以块的形式报告拷贝的数据的量;加号+之后的数是拷贝的partial块的数目。在这个实例中,因为1536688并不是快大小的倍数,文件中剩下的字节就作为一个非完整的块独立地进行读取(和写入)。对于大部分的现代的设备而言,该信息是无害的,而对于调试比较老的设备的问题,该信息却是很重要的。
在与tape设备以及其他要求固定大小写入的介质而言,控制块大小的能力(在传输中对数据重分块)是尤其有用的,对与flash设备的交互,该能力也帮助提升了性能和稳定性。
而表示为flash介质的内核设备经常可以进行任意大小的写入,对于相关设备而言,仅工作在块模式是很普遍的,经常有更大的大小(4KBytes,或者更大)。为了进行非完整的块的写入,flash设备必须提取出整个块的当前的内容,用输入数据来修改该块,然后再将整个块写回。如果设备使用4KBytes的块,而你以512字节的块对它进行写入,对于一个单一的拷贝,每一个设备块就需要写8次。
对于设备的寿命而言,这可不好,对于性能也无益。(相同文件的1个512字节的写入,也就是我所使用的flash卡的速度的一半。)
Booting the kernel
Booting the kernel is simple enough. Set the jumper for an SD boot, put the card in the system, and power it up. If you started with a blank card, this produces a predictable result:
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(1,0)
This cryptic message indicates that the kernel has been unable to find its root filesystem. That means it's about time to create one.
启动内核启动内核也是简单的可以。设置跳线为从SD启动,将SD卡插入系统,启动系统。如果以一个空的SD卡启动,会得到下面这样一个可预期的结果:
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(1,0)
该神秘信息指出,内核不能找到它的根文件系统。这意味着,是时候创建一个 root file system了。