黑乙一作品集:The DENX U-Boot and Linux Guide (DULG) for TQM8xxL (4)

来源:百度文库 编辑:九乡新闻网 时间:2024/04/30 17:49:25
The DENX U-Boot and Linux Guide (DULG) for TQM8xxL (4)
分享:
參考來源
http://www.denx.de/wiki/publish/DULG/DULG-tqm8xxl.html
7. Booting Embedded Linux7.1. Introduction
7.2. Passing Kernel Arguments
7.3. Boot Arguments Unleashed
7.4. Networked Operation with Root Filesystem over NFS
7.5. Boot from Flash Memory
7.6. Standalone Operation with Ramdisk Image
In principle, if you have a Linux kernel image somewhere in system memory (RAM, ROM, flash...), then all you need to boot the system is the bootm command. Assume a Linux kernel image has been stored at address 0x40080000 - then you can boot this image with the following command:
=> bootm 40080000
In nearly all cases, you will want to pass additional information to the Linux kernel; for instance, information about the root device or network configuration.
In U-Boot, this is supported using the bootargs environment variable. Its contents are automatically passed to the Linux kernel as boot arguments (or "command line" arguments). This allows the use of the same Linux kernel image in a wide range of configurations. For instance, by just changing the contents of the bootargs variable you can use the very same Linux kernel image to boot with an initrd ramdisk image, with a root filesystem over NFS, with aCompactFlash disk or from a flash filesystem.
As one example, to boot the Linux kernel image at address 0x200000 using the initrd ramdisk image at address 0x400000 as root filesystem, you can use the following commands:
=> setenv bootargs root=/dev/ram rw=> bootm 200000 400000
To boot the same kernel image with a root filesystem over NFS, the following command sequence can be used. This example assumes that your NFS server has the IP address "10.0.0.2" and exports the directory "/opt/eldk/ppc_8xx" as root filesystem for the target. The target has been assigned the IP address "10.0.0.99" and the hostname "tqm". A netmask of "255.0.0.0" is used:
=> setenv bootargs root=/dev/nfs rw nfsroot=10.0.0.2:/opt/eldk/ppc_8xx ip=10.0.0.99:10.0.0.2:10.0.0.2:255.0.0.0:tqm::off=> bootm 200000
Please see also the files Documentation/initrd.txt and Documentation/nfsroot.txt in your Linux kernel source directory for more information about which options can be passed to the Linux kernel.
Note: Once your system is up and running, if you have a simple shell login, you can normally examine the boot arguments that were used by the kernel for the most recent boot with the command:
$ cat /proc/cmdline
Passing command line arguments to the Linux kernel allows for very flexible and efficient configuration which is especially important in Embedded Systems. It is somewhat strange that these features are nearly undocumented everywhere else. One reason for that is certainly the very limited capabilities of other boot loaders.
It is especially U-Boot's capability to easily define, store, and use environment variables that makes it such a powerful tool in this area. In the examples above we have already seen how we can use for instance the root and ip boot arguments to pass information about the root filesystem or network configuration. The ip argument is not only useful in configurations with root filesystem over NFS; if the Linux kernel has the CONFIG_IP_PNP configuration enabled (IP kernel level autoconfiguration), this can be used to enable automatic configuration of IP addresses of devices and of the routing table during kernel boot, based on either information supplied on the kernel command line or byBOOTP or RARP protocols.
The advantage of this mechanism is that you don't have to spend precious system memory (RAM and flash) for network configuration tools like ifconfig or route - especially in Embedded Systems where you seldom have to change the network configuration while the system is running.
We can use U-Boot environment variables to store all necessary configuration parameters:
=> setenv ipaddr 10.0.0.99=> setenv serverip 10.0.0.2=> setenv netmask 255.0.0.0=> setenv hostname tqm=> setenv rootpath /opt/eldk/ppc_8xx=> saveenv
Then you can use these variables to build the boot arguments to be passed to the Linux kernel:
=> setenv nfsargs 'root=/dev/nfs rw nfsroot=${serverip}:${rootpath}'
Note how apostrophes are used to delay the substitution of the referenced environment variables. This way, the current values of these variables get inserted when assigning values to the "bootargs" variable itself later, i. e. when it gets assembled from the given parts before passing it to the kernel. This allows us to simply redefine any of the variables (say, the value of "ipaddr" if it has to be changed), and the changes will automatically propagate to the Linux kernel.
Note: You cannot use this method directly to define for example the "bootargs" environment variable, as the implicit usage of this variable by the "bootm" command will not trigger variable expansion - this happens only when using the "setenv" command.
In the next step, this can be used for a flexible method to define the "bootargs" environment variable by using a function-like approach to build the boot arguments step by step:
=> setenv ramargs setenv bootargs root=/dev/ram rw=> setenv nfsargs 'setenv bootargs root=/dev/nfs rw nfsroot=${serverip}:${rootpath}'=> setenv addip 'setenv bootargs ${bootargs} ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}::off'=> setenv ram_root 'run ramargs addip;bootm ${kernel_addr} ${ramdisk_addr}'=> setenv nfs_root 'run nfsargs addip;bootm ${kernel_addr}'
In this setup we define two variables, ram_root and nfs_root, to boot with root filesystem from a ramdisk image or over NFS, respecively. The variables can be executed using U-Boot's run command. These variables make use of the run command itself:
First, either run ramargs or run nfsargs is used to initialize the bootargs environment variable as needed to boot with ramdisk image or with root over NFS.
Then, in both cases, run addip is used to append the ip parameter to use the Linux kernel IP autoconfiguration mechanism for configuration of the network settings.
Finally, the bootm command is used with two resp. one address argument(s) to boot the Linux kernel image with resp. without a ramdisk image. (We assume here that the variables kernel_addr and ramdisk_addr have already been set.)
This method can be easily extended to add more customization options when needed.
If you have used U-Boot's network commands before (and/or read the documentation), you will probably have recognized that the names of the U-Boot environment variables we used in the examples above are exactly the same as those used with the U-Boot commands to boot over a network usingDHCP orBOOTP. That means that, instead of manually setting network configuration parameters like IP address, etc., these variables will be set automatically to the values retrieved with the network boot protocols. This will be explained in detail in the examples below.
You can use the printenv command on the Target to find out which commands get executed by U-Boot to load and boot the Linux kernel:
=> printenvbootcmd=bootp; setenv bootargs root=/dev/nfs rw nfsroot=${serverip}:${rootpath} ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}::off; bootmbootdelay=5baudrate=115200stdin=serialstdout=serialstderr=serial...
After Power-On or reset the system will initialize and then wait for a key-press on the console port. The duration of this countdown is determined by the contents of the bootdelay environment variable (default: 5 seconds).
If no key is pressed, the command (or the list of commands) stored in the environment variable bootcmd is executed. If you press a key, you get a prompt at the console port which allows for interactive command input.
In the example above the following commands are executed sequentially:
bootpsetenv bootargs root=/dev/nfs nfsroot=${serverip}:${rootpath} ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}::offbootm
These commands take the following effect (pay attention for the modification of environment variables by these commands):
bootp: This command uses the BOOTP protocol to ask a boot server for information about our system and to load a boot image (which will usually be a Linux kernel image). Since no aguments are passed to this command, it will use a default address to load the kernel image (0x100000 or the last address used by other operations).
=> bootpBOOTP broadcast 1ARP broadcast 0TFTP from server 10.0.0.2; our IP address is 10.0.0.99Filename '/tftpboot/TQM8xxL/uImage'.Load address: 0x100000Loading: ########################################################################################done=> printenvbootcmd=bootp; setenv bootargs root=/dev/nfs rw nfsroot=${serverip}:${rootpath} ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}::off; bootmbootdelay=5baudrate=115200stdin=serialstdout=serialstderr=serialbootfile=/tftpboot/TQM8xxL/uImage gatewayip=10.0.0.2netmask=255.0.0.0hostname=tqmrootpath=/opt/eldk/ppc_8xxipaddr=10.0.0.99serverip=10.0.0.2dnsip=10.0.0.2...
The Target sends a BOOTP request on the network, and (assuming there is aBOOTP server available) receives a reply that contains the IP address (ipaddr=10.0.0.99) and other network information for the target (hostname=tqm, serverip=10.0.0.2, gatewayip=10.0.0.2, netmask=255.0.0.0).
Also, the name of the boot image (bootfile= /tftpboot/TQM8xxL/uImage ) and the root directory on a NFS server (rootpath=/opt/eldk/ppc_8xx) was transmitted.
U-Boot then automatically downloaded the bootimage from the server using TFTP.
You can use the command iminfo (Image Info, or short imi) to verify the contents of the loaded image:
=> imi 100000 ## Checking Image at 00100000 ... Image Name: Linux-2.4.4 Created: 2002-04-07 21:31:59 UTC Image Type: PowerPC Linux Kernel Image (gzip compressed) Data Size: 605429 Bytes = 591 kB = 0 MB Load Address: 00000000 Entry Point: 00000000 Verifying Checksum ... OK=>
This tells you that we loaded a compressed Linux kernel image, and that the file was not corrupted, since the CRC32 checksum is OK.
setenv bootargs root=/dev/nfs rw nfsroot=${serverip}:${rootpath} ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}::off
This command defines the environment variable bootargs. (If an old definition exists, it is deleted first). The contents of this variable is passed as command line to the LInux kernel when it is booted (hence the name). Note how U-Boot uses variable substitution to dynamically modify the boot arguments depending on the information we got from the BOOTP server.
To verify, you can run this command manually:
=> setenv bootargs root=/dev/nfs rw nfsroot=${serverip}:${rootpath} ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}::off => printenv...bootargs=root=/dev/nfs rw nfsroot=10.0.0.2:/opt/eldk/ppc_8xx ip=10.0.0.99:10.0.0.2:10.0.0.2:255.0.0.0:tqm::off...
This command line passes the following information to the Linux kernel:
root=/dev/nfs rw: the root filesystem will be mounted using NFS, and it will be writable.
nfsroot=10.0.0.2:/opt/eldk/ppc_8xx: the NFS server has the IP address 10.0.0.2, and exports the directory /opt/eldk/ppc_8xx for our system to use as root filesystem.
ip=10.0.0.99:10.0.0.2:10.0.0.2:255.0.0.0:tqm::off: the target has the IP address 10.0.0.99; the NFS server is 10.0.0.2; there is a gateway at IP address 10.0.0.2; the netmask is 255.0.0.0 and our hostname is tqm. The first ethernet interface (eth0) willbe used, and the Linux kernel will immediately use this network configuration and not try to re-negotiate it (IP autoconfiguration is off).
See Documentation/nfsroot.txt in you Linux kernel source directory for more information about these parameters and other options.
bootm: This command boots an operating system image that resides somewhere in the system memory (RAM or flash - the m in the name is for memory). In this case we do not pass any memory address for the image, so the load address 0x100000 from the previousTFTP transfer is used:
=> run flash_nfs## Booting image at 40040000 ... Image Name: Linux-2.4.4 Created: 2002-04-07 21:31:59 UTC Image Type: PowerPC Linux Kernel Image (gzip compressed) Data Size: 605429 Bytes = 591 kB = 0 MB Load Address: 00000000 Entry Point: 00000000 Verifying Checksum ... OK Uncompressing Kernel Image ... OKLinux version 2.4.4 (wd@larry.denx.de) (gcc version 2.95.3 20010111 (prerelease/franzo/20010111)) #1 Sun Apr 7 23:28:08 MEST 2002On node 0 totalpages: 16384zone(0): 16384 pages.zone(1): 0 pages.zone(2): 0 pages.Kernel command line: root=/dev/nfs rw nfsroot=10.0.0.2:/opt/hardhat/devkit/ppc/8xx/target ip=10.0.0.99:10.0.0.2::255.0.0.0:tqm:eth0:off panic=1Decrementer Frequency: 3125000Calibrating delay loop... 49.86 BogoMIPSMemory: 62580k available (1164k kernel code, 564k data, 52k init, 0k highmem)Dentry-cache hash table entries: 8192 (order: 4, 65536 bytes)Buffer-cache hash table entries: 4096 (order: 2, 16384 bytes)Page-cache hash table entries: 16384 (order: 4, 65536 bytes)Inode-cache hash table entries: 4096 (order: 3, 32768 bytes)POSIX conformance testing by UNIFIXLinux NET4.0 for Linux 2.4Based upon Swansea University Computer Society NET3.039Starting kswapd v1.8CPM UART driver version 0.03ttyS0 on SMC1 at 0x0280, BRG1ttyS1 on SMC2 at 0x0380, BRG2pty: 256 Unix98 ptys configuredblock: queued sectors max/low 41520kB/13840kB, 128 slots per queueRAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksizeUniform Multi-Platform E-IDE driver Revision: 6.31ide: Assuming 50MHz system bus speed for PIO modes; override with idebus=xxPCMCIA slot B: phys mem e0000000...ec000000 (size 0c000000)No card in slot B: PIPR=ff00ff00eth0: CPM ENET Version 0.2 on SCC1, 00:d0:93:00:28:81JFFS version 1.0, (C) 1999, 2000 Axis Communications ABJFFS2 version 2.1. (C) 2001 Red Hat, Inc., designed by Axis Communications AB.^M Amd/Fujitsu Extended Query Table v1.0 at 0x0040number of JEDEC chips: 10: offset=0x0,size=0x8000,blocks=11: offset=0x8000,size=0x4000,blocks=22: offset=0x10000,size=0x10000,blocks=13: offset=0x20000,size=0x20000,blocks=31 Amd/Fujitsu Extended Query Table v1.0 at 0x0040number of JEDEC chips: 10: offset=0x0,size=0x8000,blocks=11: offset=0x8000,size=0x4000,blocks=22: offset=0x10000,size=0x10000,blocks=13: offset=0x20000,size=0x20000,blocks=31TQM flash bank 0: Using static image partition definitionCreating 4 MTD partitions on "TQM8xxL Bank 0":0x00000000-0x00040000 : "ppcboot"0x00040000-0x00100000 : "kernel"0x00100000-0x00200000 : "user"0x00200000-0x00400000 : "initrd"TQM flash bank 1: Using static file system partition definitionCreating 2 MTD partitions on "TQM8xxL Bank 1":0x00000000-0x00200000 : "cramfs"0x00200000-0x00400000 : "jffs"NET4: Linux TCP/IP 1.0 for NET4.0IP Protocols: ICMP, UDP, TCPIP: routing cache hash table of 512 buckets, 4KbytesTCP: Hash tables configured (established 4096 bind 4096)NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.Looking up port of RPC 100003/2 on 10.0.0.2Looking up port of RPC 100005/2 on 10.0.0.2VFS: Mounted root (nfs filesystem).Freeing unused kernel memory: 52k initmodprobe: modprobe: Can't locate module char-major-4INIT: version 2.78 bootingActivating swap...Checking all file systems... Parallelizing fsck version 1.19 (13-Jul-2000)Mounting local filesystems...not mounted anythingCleaning: /etc/network/ifstate.Setting up IP spoofing protection: rp_filter.Configuring network interfaces: done.Starting portmap daemon: portmap.Cleaning: /tmp /var/lock /var/run.INIT: Entering runlevel: 2Starting internet superserver: inetd. MontaVista Software's Hard Hat Linux 2.0 tqm login: rootPAM-securetty[76]: Couldn't open /etc/securettyPAM_unix[76]: (login) session opened for user root by LOGIN(uid=0)Last login: Fri Feb 1 02:30:32 2030 on consoleLinux tqm 2.4.4 #1 Sun Apr 7 23:28:08 MEST 2002 ppc unknownlogin[76]: ROOT LOGIN on `console'root@tqm:~#
The previous section described how to load the Linux kernel image over ethernet usingTFTP. This is especially well suited for your development and test environment, when the kernel image is still undergoing frequent changes, for instance because you are modifying kernel code or configuration.
Later in your development cycle you will work on application code or device drivers, which can be loaded dynamically as modules. If the Linux kernel remains the same then you can save the time needed for theTFTP download and put the kernel image into the flash memory of your TQM8xxL board.
The U-Boot command flinfo can be used to display information about the available on-board flash on your system:
=> fli Bank # 1: FUJITSU AM29LV160B (16 Mbit, bottom boot sect) Size: 4 MB in 35 Sectors Sector Start Addresses: 40000000 (RO) 40008000 (RO) 4000C000 (RO) 40010000 (RO) 40020000 (RO) 40040000 40060000 40080000 400A0000 400C0000 400E0000 40100000 40120000 40140000 40160000 40180000 401A0000 401C0000 401E0000 40200000 40220000 40240000 40260000 40280000 402A0000 402C0000 402E0000 40300000 40320000 40340000 40360000 40380000 403A0000 403C0000 403E0000 Bank # 2: FUJITSU AM29LV160B (16 Mbit, bottom boot sect) Size: 4 MB in 35 Sectors Sector Start Addresses: 40400000 40408000 4040C000 40410000 40420000 40440000 40460000 40480000 404A0000 404C0000 404E0000 40500000 40520000 40540000 40560000 40580000 405A0000 405C0000 405E0000 40600000 40620000 40640000 40660000 40680000 406A0000 406C0000 406E0000 40700000 40720000 40740000 40760000 40780000 407A0000 407C0000 407E0000=>
From this output you can see the total amount of flash memory, and how it is divided in blocks (Erase Units or Sectors). The RO markers show blocks of flash memory that are write protected (by software) - this is the area where U-Boot is stored. The remaining flash memory is available for other use.
For instance, we can store the Linux kernel image in flash starting at the start address of the next free flash sector. Before we can do this we must make sure that the flash memory in that region is empty - a Linux kernel image is typically around 600...700 kB, so to be on the safe side we dedicate the whole area from 0x40080000 to 0x4027FFFF for the kernel image. Keep in mind that with flash memory only whole erase units can be cleared.
After having deleted the target flash area, you can download the Linux image and write it to flash. Below is a transcript of the complete operation with a final iminfo command to check the newly placed Linux kernel image in the flash memory.
Note: Included topic DULGData.tqm8xxlInstallKernelTftp does not exist yet
Note how the filesize variable (which gets set by theTFTP transfer) is used to automatically adjust for the actual image size.
Now we can boot directly from flash. All we need to do is passing the in-flash address of the image (40080000) with the bootm command; we also make the definition of the bootargs variable permanent now:
=> setenv bootcmd bootm 40080000=> setenv bootargs root=/dev/nfs rw nfsroot=${serverip}:${rootpath} ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}::off
Use printenv to verify that everything is OK before you save the environment settings:
=> printenvbootdelay=5baudrate=115200stdin=serialstdout=serialstderr=serialbootcmd=bootm 40080000bootargs=root=/dev/nfs rw nfsroot=10.0.0.2:/opt/eldk/ppc_8xxip=10.0.0.99:10.0.0.2:10.0.0.2:255.0.0.0:tqm::off....=> saveenv
To test booting from flash you can now reset the board (either by power-cycling it, or using the U-Boot command reset), or you can manually call the boot command which will run the commands in the bootcmd variable:
Note: Included topic DULGData.tqm8xxlLinuxBootSelf does not exist yet
When your application development is completed, you usually will want to run your Embedded System standalone, i. e. independent from external resources like NFS filesystems. Instead of mounting the root filesystem from a remote server you can use a compressed ramdisk image, which is stored in flash memory and loaded into RAM when the system boots.
Ramdisk images for tests can be found in theftp://ftp.denx.de/pub/LinuxPPC/usr/src/SELF/images/ directories.
Load the ramdisk image into RAM and write it to flash as follows:
Note: Included topic DULGData.tqm8xxlUBootInstallRamdisk does not exist yet
To tell the Linux kernel to use the ramdisk image as root filesystem you have to modify the command line arguments passed to the kernel, and to pass two arguments to the bootm command, the first is the memory address of the Linux kernel image, the second that of the ramdisk image:
Note: Included topic DULGData.tqm8xxlLinuxBootSelf does not exist yet
9. Advanced Topics9.1. Flash Filesystems9.1.1. Memory Technology Devices
9.1.2. Journalling Flash File System
9.1.3. Second Version of JFFS
9.1.4. Compressed ROM Filesystem
9.2. The TMPFS Virtual Memory Filesystem9.2.1. Mount Parameters
9.2.2. Kernel Support for tmpfs
9.2.3. Usage of tmpfs in Embedded Systems
9.3. Using PC Cards for Flash Disks, CompactFlash, and IDE Harddisks9.3.1. PC Card Support in U-Boot
9.3.2. PC Card Support in Linux9.3.2.1. Using a MacOS Partition Table
9.3.2.2. Using a MS-DOS Partition Table
9.3.3. Using PC Card "disks" with U-Boot and Linux
9.4. Adding Swap Space
9.5. Splash Screen Support in Linux
9.6. Root File System: Design and Building9.6.1. Root File System on a Ramdisk
9.6.2. Root File System on a JFFS2 File System
9.6.3. Root File System on a cramfs File System
9.6.4. Root File System on a Read-Only ext2 File System
9.6.5. Root File System on a Flash Card
9.6.6. Root File System in a Read-Only File in a FAT File System
9.7. Root File System Selection
9.8. Overlay File Systems
9.9. The Persistent RAM File system (PRAMFS)9.9.1. Mount Parameters
9.9.2. Example
This section lists some advanced topics of interest to users of U-Boot and Linux.
All currently available flash filesystems are based on the Memory Technology Devices MTD layer, so you must enable (at least) the following configuration options to get flash filesystem support in your system:
CONFIG_MTD=yCONFIG_MTD_PARTITIONS=yCONFIG_MTD_CHAR=yCONFIG_MTD_BLOCK=yCONFIG_MTD_CFI=yCONFIG_MTD_GEN_PROBE=yCONFIG_MTD_CFI_AMDSTD=yCONFIG_MTD_ROM=yCONFIG_MTD_tqm8xxl=y
Note: this configuration uses CFI conformant AMD flash chips; you may need to adjust these settings on other boards.
The layout of your flash devices ("partitioning") is defined by the mapping routines for your board in the LinuxMTD sources (see drivers/mtd/maps/). The configuration for the TQM8xxL looks like this:
/* partition definition for first flash bank * also ref. to "drivers\char\flash_config.c" */static struct mtd_partition tqm8xxl_partitions[] = { { name: "ppcboot", offset: 0x00000000, size: 0x00020000, /* 128KB */ mask_flags: MTD_WRITEABLE, /* force read-only */ }, { name: "kernel", /* default kernel image */ offset: 0x00020000, size: 0x000e0000, mask_flags: MTD_WRITEABLE, /* force read-only */ }, { name: "user", offset: 0x00100000, size: 0x00100000, }, { name: "initrd", offset: 0x00200000, size: 0x00200000, }};/* partition definition for second flahs bank */static struct mtd_partition tqm8xxl_fs_partitions[] = { { name: "cramfs", offset: 0x00000000, size: 0x00200000, }, { name: "jffs", offset: 0x00200000, size: 0x00200000, //size: MTDPART_SIZ_FULL, }};
This splits the available flash memory (8 MB in this case) into 6 separate "partitions":
uboot: size: 128 kB; used to store the U-Boot firmware
kernel: size: 896kB; used to store the (compressed) Linux kernel image
user: size: 1 MB; not used
initrd: size: 2 MB; used to store a (compressed) ramdisk image
cramfs: size: 2 MB; used for a compressed ROM filesystem (read-only)
jffs: size: 2 MB; used for a flash filesystem (using JFFS)
When you boot a system with this configuration you will see the following kernel messages on the console:
Note: Included topic DULGData.tqm8xxlLinuxMtdBoot does not exist yet
Another way to check this information when the system is running is using the proc filesystem:
Note: Included topic DULGData.tqm8xxlLinuxProcMtd does not exist yet
Now we can run some basic tests to verify that the flash driver routines and the partitioning works as expected:
# xd /dev/mtd0 | head -4 0 27051956 7fe5f641 3be91e9d 0008061f |' V A; | 10 00000000 00000000 7667315e 05070201 | vg1^ | 20 4c696e75 782d322e 342e3400 00000000 |Linux-2.4.4 | 30 00000000 00000000 00000000 00000000 | |# xd /dev/mtd1 | head -4 0 27051956 6735cb88 3be79508 000d11bf |' Vg5 ; | 10 00000000 00000000 7d5cbfc8 05070301 | }\ | 20 4170706c 69636174 696f6e20 72616d64 |Application ramd| 30 69736b20 696d6167 65000000 00000000 |isk image |# xd /dev/mtd6 | head -10 0 6a0358f7 626f6f74 64656c61 793d3500 |j X bootdelay=5 | 10 62617564 72617465 3d393630 30006c6f |baudrate=9600 lo| 20 6164735f 6563686f 3d310063 6c6f636b |ads_echo=1 clock| 30 735f696e 5f6d687a 3d310065 74686164 |s_in_mhz=1 ethad| 40 64723d30 303a6362 3a62643a 30303a30 |dr=00:cb:bd:00:0| 50 303a3131 006e6673 61726773 3d736574 |0:11 nfsargs=set| 60 656e7620 626f6f74 61726773 20726f6f |env bootargs roo| 70 743d2f64 65762f6e 66732072 77206e66 |t=/dev/nfs rw nf| 80 73726f6f 743d2428 73657276 65726970 |sroot=$(serverip| 90 293a2428 726f6f74 70617468 29007261 |):$(rootpath) ra|# xd /dev/mtd7 0 ffffffff ffffffff ffffffff ffffffff | | *** same *** 80000
In the tex-dumps of theMTD devices you can identify some strings that verify that we indeed see an U-Boot environment, a Linux kernel, a ramdisk image and an empty partition to play wih.
The last output shows the partition to be empty. We can try write some data into it:
# date >/dev/mtd7# xd /dev/mtd7 0 57656420 4e6f7620 20372031 353a3339 |Wed Nov 7 15:39| 10 3a313220 4d455420 32303031 0affffff |:12 MET 2001 | 20 ffffffff ffffffff ffffffff ffffffff | | *** same *** 80000 | |# sleep 10 ; date >/dev/mtd7Last[3] is 3aa73020, datum is 3a343020date: write error: Input/output error
As you can see it worked the first time. When we tried to write the (new date) again, we got an error. The reason is that the date has changed (probably at least the seconds) and flash memory cannot be simply overwritten - it has to be erased first.
You can use the eraseall Linux commands to erase a wholeMTD partition:
# xd /dev/mtd7 0 57656420 4e6f7620 20372031 353a3339 |Wed Nov 7 15:39| 10 3a303020 4d455420 32303031 0affffff |:00 MET 2001 | 20 ffffffff ffffffff ffffffff ffffffff | | *** same *** 80000 | |# eraseall /dev/mtd7Erased 512 Kibyte @ 0 -- 100% complete.# xd /dev/mtd7 0 ffffffff ffffffff ffffffff ffffffff | | *** same *** 80000 | |# date >/dev/mtd7# xd /dev/mtd7 0 57656420 4e6f7620 20372031 353a3432 |Wed Nov 7 15:42| 10 3a313920 4d455420 32303031 0affffff |:19 MET 2001 | 20 ffffffff ffffffff ffffffff ffffffff | | *** same *** 80000
We have now sufficient proof that theMTD layer is working as expected, so we can try creating a flash filesystem.
At the moment it seems that the Journalling Flash File System JFFS is the best choice for filesystems in flash memory of embedded devices. You must enable the following configuration options to getJFFS support in your system:
CONFIG_JFFS_FS=yCONFIG_JFFS_FS_VERBOSE=0
If the flash device is erased, we can simply mount it, and the creation of theJFFS filesystem is performed automagically.
Note: For simple accesses like direct read or write operations or erasing you use the character device interface (/dev/mtd*) of theMTD layer, while for filesystem operations like mounting we must use the block device interface (/dev/mtdblock*).
# eraseall /dev/mtd2Erased 4096 Kibyte @ 0 -- 100% complete. # mount -t jffs /dev/mtdblock2 /mnt# mount/dev/root on / type nfs (rw,v2,rsize=4096,wsize=4096,hard,udp,nolock,addr=10.0.0.2)proc on /proc type proc (rw)devpts on /dev/pts type devpts (rw)/dev/mtdblock2 on /mnt type jffs (rw)# dfFilesystem 1k-blocks Used Available Use% Mounted on/dev/root 2087212 1232060 855152 60% //dev/mtdblock2 3584 0 3584 0% /mnt
Now you can access the files in theJFFS filesystem in the /mnt directory.
JFFS
Probably even more interesting for embedded systems is the second version ofJFFS, JFFS2, since it not only fixes a few design issues withJFFS, but also adds transparent compression, so that you can save a lot of precious flash memory.
The mkfs.jffs2 tool is used to create a JFFS2 filesystem image; it populates the image with files from a given directory. For instance, to create a JFFS2 image for a flash partition of 3 MB total size and to populate it with the files from the /tmp/flashtools directory you would use:
# mkfs.jffs2 --pad=3145728 --eraseblock=262144 --root=/tmp/flashtools/ --output image.jffs2# eraseall /dev/mtd4Erased 3072 Kibyte @ 0 -- 100% complete. \# dd if=image.jffs2 of=/dev/mtd4 bs=256k12+0 records in12+0 records out# mount -t jffs2 /dev/mtdblock4 /mnt# df /mntFilesystem 1k-blocks Used Available Use% Mounted on/dev/mtdblock4 3072 2488 584 81% /mnt
Note: Especially when you are running time-critical applications on your system you should carefully study if the behaviour of the flash filesystem might have any negative impact on your application. After all, a flash device is not a normal harddisk. This is especially important when your flash filesystem gets full; JFFS2 acts a bit weird then:
You will note that an increasing amount ofCPU time is spent by the filesystem's garbage collection kernel thread.
Access times to the files on the flash filesystem may increase drastically.
Attempts to truncate a file (to free space) or to rename it may fail:...# cp /bin/bash filecp: writing `file': No space left on device# >filebash: file: No space left on device# mv file foomv: cannot create regular file `foo': No space left on deviceYou will have to use rm to actually delete a file in this situation.
This is especially critical when you are using the flash filesystem to store log files: when your application detects some abnormal condition and produces lots of log messages (which usually are especially important in this situation) the filesystem may fill up and cause extreme long delays - if your system crashes, the most important messages may never be logged at all.
In some cases it is sufficent to have read-only access to some files, and if the files are big enough it becomes desirable to use some method of compression. The Compressed ROM Filesystem CramFs might be a solution here.
Please note thatCramFs has - beside the fact that it is a read-only filesystem - some severe limitations (like missing support for timestamps, hard links, and 16/32 bit uid/gids), but there are many situations in Embedded Systems where it's still useful.
To create aCramFs filesystem a special tool mkcramfs is used to create a file which contains theCramFs image. Note that theCramFs filesystem can be written and read only by kernels with PAGE_CACHE_SIZE == 4096, and some versions of the mkcramfs program may have other restrictions like that the filesystem must be written and read with architectures of the same endianness. Especially the endianness requirement makes it impossible to build theCramFs image on x86 PC host when you want to use it on aPowerPC target. The endianness problem has been fixed in the version of mkcramfs that comes with theELDK.
In some cases you can use a target system running with root filesystem mounted over NFS to create theCramFs image on the native system and store it to flash for further use.
Note: The normal version of the mkcramfs program tries to initialize some entries in the filesystem's superblock with random numbers by reading /dev/random; this may hang permanently on your target because there is not enough input (like mouse movement) to the entropy pool. You may want to use a modified version of mkcramfs which does not depend on /dev/random.
To create aCramFs image, you put all files you want in the filesystem into one directory, and then use the mkcramfs= program as follows:
$ mkdir /tmp/test$ cp ... /tmp/test$ du -sk /tmp/test64 /tmp/test$ mkcramfs /tmp/test test.cramfs.imgSuper block: 76 bytes erase eraseall mkfs.jffs lock unlockDirectory data: 176 bytes-54.96% (-4784 bytes) erase-55.46% (-5010 bytes) eraseall-51.94% (-8863 bytes) mkfs.jffs-58.76% (-4383 bytes) lock-59.68% (-4215 bytes) unlockEverything: 24 kilobytes$ ls -l test.cramfs.img-rw-r--r-- 1 wd users 24576 Nov 10 23:44 test.cramfs.img
As you can see, theCramFs image test.cramfs.img takes just 24 kB, while the input directory contained 64 kB of data. Savings of some 60% like in this case are typicalCramFs.
Now we write theCramFs image to a partition in flash and test it:
# cp test.cramfs.img /dev/mtd3# mount -t cramfs /dev/mtdblock3 /mnt# mount/dev/root on / type nfs (rw,v2,rsize=4096,wsize=4096,hard,udp,nolock,addr=10.0.0.2)proc on /proc type proc (rw)devpts on /dev/pts type devpts (rw)/dev/mtdblock3 on /mnt type cramfs (rw)# ls -l /mnttotal 54-rwxr-xr-x 1 wd users 8704 Jan 9 16:32 erase-rwxr-xr-x 1 wd users 9034 Jan 1 01:00 eraseall-rwxr-xr-x 1 wd users 7459 Jan 1 01:00 lock-rwxr-xr-x 1 wd users 17063 Jan 1 01:00 mkfs.jffs-rwxr-xr-x 1 wd users 7063 Jan 1 01:00 unlock
Note that all the timestamps in theCramFs filesyste are bogus, and so is for instance the output of the df command for such filesystems:
# df /mntFilesystem 1k-blocks Used Available Use% Mounted on/dev/mtdblock3 0 0 0 - /mnt
The tmpfs filesystem, formerly known as shmfs, is a filesystem keeping all files in virtual memory.
Everything in tmpfs is temporary in the sense that no files will be created on any device. If you unmount a tmpfs instance, everything stored therein is lost.
tmpfs puts everything into the kernel internal caches and grows and shrinks to accommodate the files it contains and is able to swap unneeded pages out to swap space. It has maximum size limits which can be adjusted on the fly via 'mount -o remount ...'
If you compare it to ramfs (which was the template to create tmpfs) you gain swapping and limit checking. Another similar thing is the RAM disk (/dev/ram*), which simulates a fixed size hard disk in physical RAM, where you have to create an ordinary filesystem on top. Ramdisks cannot swap and you do not have the possibility to resize them.
tmpfs has a couple of mount options:
size: The limit of allocated bytes for this tmpfs instance. The default is half of your physical RAM without swap. If you oversize your tmpfs instances the machine will deadlock since the OOM handler will not be able to free that memory.
nr_blocks: The same as size, but in blocks of PAGECACHE_SIZE.
nr_inodes: The maximum number of inodes for this instance. The default is half of the number of your physical RAM pages.
These parameters accept a suffix k, m or g for kilo, mega and giga and can be changed on remount.
To specify the initial root directory you can use the following mount options:
mode: The permissions as an octal number
uid: The user id
gid: The group id
These options do not have any effect on remount. You can change these parameters with chmod(1), chown(1) and chgrp(1) on a mounted filesystem.
So the following mount command will give you a tmpfs instance on /mytmpfs which can allocate 12MB of RAM/SWAP and it is only accessible by root.
mount -t tmpfs -o size=12M,mode=700 tmpfs /mytmpfs
In order to use a tmpfs filesystem, the CONFIG_TMPFS option has to be enabled for your kernel configuration. It can be found in the Filesystems configuration group. You can simply check if a running kernel supports tmpfs by searching the contents of /proc/fileysystems:
bash# grep tmpfs /proc/filesystemsnodev tmpfsbash#
In embedded systems tmpfs is very well suited to provide read and write space (e.g. /tmp and /var) for a read-only root file system such asCramFs described in section9.1.4. Compressed ROM Filesystem. One way to achieve this is to use symbolic links. The following code could be part of the startup file /etc/rc.sh of the read-only ramdisk:
#!/bin/sh...# Won't work on read-only root: mkdir /tmpfsmount -t tmpfs tmpfs /tmpfsmkdir /tmpfs/tmp /tmpfs/var# Won't work on read-only root: ln -sf /tmpfs/tmp /tmpfs/var /...
The commented out sections will of course fail on a read-only root filesystem, so you have to create the /tmpfs mount-point and the symbolic links in your root filesystem beforehand in order to successfully use this setup.
CompactFlash, and IDE Harddisks
If your board is equipped with a PC-Card adapter (also known as PCMCIA adapter) you can use this for miscellaneous types of mass storage devices like Flash Disks,CompactFlash, and IDE Harddisks.
Please note that there are other options to operate such devices on EmbeddedPowerPC Systems (for instace you can use thePCMCIA controller builtin to the MPC8xxCPUs to build a direct IDE interface, or you can use some external controller to provide such an interface). The following description does not cover such configurations. Only the solution which uses a standard PC Card Slot is described here.
When PC Card support is enabled in your U-Boot configuration the target will try to detect any PC Cards in the slot when booting. If no card is present you will see a message like this:
PPCBoot 1.1.1 (Nov 11 2001 - 18:06:06)CPU: XPC862PZPnn0 at 48 MHz: 16 kB I-Cache 8 kB D-Cache FEC presentBoard: ICU862 BoardDRAM: 32 MBFLASH: 16 MBIn: serialOut: serialErr: serialPCMCIA: No Card found
Depending on the type of PC Card inserted the boot messages vary; for instance with a Flash Disk card you would see:
...PCMCIA: 3.3V card found: SunDisk SDP 5/3 0.6 Fixed Disk Card IDE interface [silicon] [unique] [single] [sleep] [standby] [idle] [low power]Bus 0: OK Device 0: Model: SanDisk SDP3B-8 Firm: Vdd 1.02 Ser#: fq9bu499900 Type: Removable Hard Disk Capacity: 7.7 MB = 0.0 GB (15680 x 512)...
With aCompactFlash Card you get:
...PCMCIA: 3.3V card found: CF 128MB CH Fixed Disk Card IDE interface [silicon] [unique] [single] [sleep] [standby] [idle] [low power]Bus 0: OK Device 0: Model: CF 128MB Firm: Rev 1.01 Ser#: 1969C32AA0210002 Type: Removable Hard Disk Capacity: 122.3 MB = 0.1 GB (250368 x 512)...
Even more exotic memory devices (like the "MemoryStick as used in some Digital Cameras") will usually work without problems:
...PCMCIA: 3.3V card found: SONY MEMORYSTICK(128M) 1.0 Fixed Disk Card IDE interface [silicon] [unique] [single] [sleep] [standby] [idle] [low power]Bus 0: .OK Device 0: Model: MEMORYSTICK 128M 16K Firm: SONY1.00` Ser#: Type: Removable Hard Disk Capacity: 123.8 MB = 0.1 GB (253696 x 512)...
And with a harddisk adapter you would see:
...PCMCIA: 5.0V card found: ARGOSY PnPIDE D5Bus 0: OK Device 0: Model: IBM-DKLA-24320 Firm: KL4AA43A Ser#: YD2YD246800 Type: Hard Disk Capacity: 4126.10 MB = 4.0 GB (8452080 x 512)...
Note that most other cards will be detected by U-Boot, but not supported otherwise, for instance:
...PCMCIA: 5.0V card found: ELSA AirLancer MC-11 Version 01.01 Network Adapter Card...
or
...PCMCIA: 5.0V card found: Elsa MicroLink 56k MC Internet 021 A Serial Port Card...
The standard way to use PC Cards in a Linux system is to install the "PCMCIA Card Services" package. This is a quite complex set of kernel modules and tools that take care of things like automatic detection and handling of "card insert" or "remove" events, identification of the inserted cards, loading the necessary device drivers, etc. This is a very powerful package, but for embedded applications it has several serious disadvantages:
Memory footprint - the package consists of a lot of tools and modules that take a lot of space both in the root filesystem and in system RAM when running
Chicken and Egg Problem - the package loads the needed device drivers as kernel modules, so it needs a root filesystem on another device; that means that you cannot easily put the root filesystem on a PC Card.
For "disk" type PC Cards (FlashDisks,CompactFlash, Hard Disk Adapters - basicly anything that looks like an ordinary IDE drive) an alternative solution is available: direct support within the Linux kernel. This has the big advantage of minimal memory footprint, but of course it comes with a couple of disadvantages, too:
It works only with "disk" type PC Cards - no support for modems, network cards, etc; for these you still need thePCMCIA Card Services package.
There is no support for "hot plug", i. e. you cannot insert or remove the card while Linux is running. (Well, of course you can do this, but either you willnot be able to access any card inserted, or when you remove a card you will most likely crash the system. Don't do it - you have been warned!)
The code relies on initialization of thePCMCIA controller by the firmware (of course U-Boot will do exactly what's required).
On the other hand these are no real restrictions for use in an Embedded System.
To enable the "direct IDE support" you have to select the following Linux kernel configuration options:
CONFIG_IDE=yCONFIG_BLK_DEV_IDE=yCONFIG_BLK_DEV_IDEDISK=yCONFIG_IDEDISK_MULTI_MODE=yCONFIG_BLK_DEV_MPC8xx_IDE=yCONFIG_BLK_DEV_IDE_MODES=y
and, depending on which partition types and languages you want to support:
CONFIG_PARTITION_ADVANCED=yCONFIG_MAC_PARTITION=yCONFIG_MSDOS_PARTITION=yCONFIG_NLS=yCONFIG_NLS_DEFAULT="y"CONFIG_NLS_ISO8859_1=yCONFIG_NLS_ISO8859_15=y
With these options you will see messages like the following when you boot the Linux kernel:
...Uniform Multi-Platform E-IDE driver Revision: 6.31ide: Assuming 50MHz system bus speed for PIO modes; override with idebus=xxPCMCIA slot B: phys mem e0000000...ec000000 (size 0c000000)Card ID: CF 128MB CH Fixed Disk Card IDE interface [silicon] [unique] [single] [sleep] [standby] [idle] [low power]hda: probing with STATUS(0x50) instead of ALTSTATUS(0x41)hda: CF 128MB, ATA DISK driveide0 at 0xc7000320-0xc7000327,0xc3000106 on irq 13hda: 250368 sectors (128 MB) w/16KiB Cache, CHS=978/8/32Partition check: hda: hda1 hda2 hda3 hda4...
You can now access your PC Card "disk" like any normal IDE drive. If you start with a new drive, you have to start by creating a new partition table. For PowerPC systems, there are two commonly used options:
A MacOS partition table is the "native" partition table format onPowerPC systems; most desktopPowerPC systems use it, so you may prefer it when you havePowerPC development systems around.
To format your "disk" drive with a MacOS partition table you can use the pdisk command:
We start printing the help menu, re-initializing the partition table and then printing the new, empty partition table so that we know the block numbers when we want to create new partitions:
# pdisk /dev/hdaEdit /dev/hda -Command (? for help): ?Notes: Base and length fields are blocks, which vary in size between media. The base field can be <nth>p; i.e. use the base of the nth partition. The length field can be a length followed by k, m, g or t to indicate kilo, mega, giga, or tera bytes; also the length can be <nth>p; i.e. use the length of the nth partition. The name of a partition is descriptive text.Commands are: h help p print the partition table P (print ordered by base address) i initialize partition map s change size of partition map c create new partition (standard MkLinux type) C (create with type also specified) n (re)name a partition d delete a partition r reorder partition entry in map w write the partition table q quit editing (don't save changes)Command (? for help): imap already existsdo you want to reinit? [n/y]: yCommand (? for help): pPartition map (with 512 byte blocks) on '/dev/hda' #: type name length base ( size ) 1: Apple_partition_map Apple 63 @ 1 2: Apple_Free Extra 1587536 @ 64 (775.2M)Device block size=512, Number of Blocks=1587600 (775.2M)DeviceType=0x0, DeviceId=0x0
At first we create two small partitions that will be used to store a Linux boot image; a compressed Linux kernel is typically around 400 ... 500 kB, so chosing a partition size of 2 MB is more than generous. 2 MB coresponds to 4096 disk blocks of 512 bytes each, so we enter:
Command (? for help): CFirst block: 64Length in blocks: 4096Name of partition: boot0Type of partition: PPCBootCommand (? for help): pPartition map (with 512 byte blocks) on '/dev/hda' #: type name length base ( size ) 1: Apple_partition_map Apple 63 @ 1 2: PPCBoot boot0 4096 @ 64 ( 2.0M) 3: Apple_Free Extra 1583440 @ 4160 (773.2M)Device block size=512, Number of Blocks=1587600 (775.2M)DeviceType=0x0, DeviceId=0x0
To be able to select between two kernel images (for instance when we want to do a field upgrade of the Linux kernel) we create a second boot partition of exactly the same size:
Command (? for help): CFirst block: 4160Length in blocks: 4096Name of partition: boot1Type of partition: PPCBootCommand (? for help): pPartition map (with 512 byte blocks) on '/dev/hda' #: type name length base ( size ) 1: Apple_partition_map Apple 63 @ 1 2: PPCBoot boot0 4096 @ 64 ( 2.0M) 3: PPCBoot boot1 4096 @ 4160 ( 2.0M) 4: Apple_Free Extra 1579344 @ 8256 (771.2M)Device block size=512, Number of Blocks=1587600 (775.2M)DeviceType=0x0, DeviceId=0x0
Now we create a swap partition - 64 MB should be more than sufficient for our Embedded System; 64 MB means 64*1024*2 = 131072 disk blocks of 512 bytes:
Command (? for help): CFirst block: 8256Length in blocks: 131072Name of partition: swapType of partition: swapCommand (? for help): pPartition map (with 512 byte blocks) on '/dev/hda' #: type name length base ( size ) 1: Apple_partition_map Apple 63 @ 1 2: PPCBoot boot0 4096 @ 64 ( 2.0M) 3: PPCBoot boot1 4096 @ 4160 ( 2.0M) 4: swap swap 131072 @ 8256 ( 64.0M) 5: Apple_Free Extra 1448272 @ 139328 (707.2M)Device block size=512, Number of Blocks=1587600 (775.2M)DeviceType=0x0, DeviceId=0x0
Finally, we dedicate all the remaining space to the root partition:
Command (? for help): CFirst block: 139328Length in blocks: 1448272Name of partition: rootType of partition: LinuxCommand (? for help): pPartition map (with 512 byte blocks) on '/dev/hda' #: type name length base ( size ) 1: Apple_partition_map Apple 63 @ 1 2: PPCBoot boot0 4096 @ 64 ( 2.0M) 3: PPCBoot boot1 4096 @ 4160 ( 2.0M) 4: swap swap 131072 @ 8256 ( 64.0M) 5: Linux root 1448272 @ 139328 (707.2M)Device block size=512, Number of Blocks=1587600 (775.2M)DeviceType=0x0, DeviceId=0x0
To make our changes permanent we must write the new partition table to the disk, before we quit the pdisk program:
Command (? for help): wWriting the map destroys what was there before. Is that okay? [n/y]: y hda: [mac] hda1 hda2 hda3 hda4 hda5 hda: [mac] hda1 hda2 hda3 hda4 hda5Command (? for help): q
Now we can initialize the swap space and the filesystem:
# mkswap /dev/hda4Setting up swapspace version 1, size = 67104768 bytes# mke2fs /dev/hda5mke2fs 1.19, 13-Jul-2000 for EXT2 FS 0.5b, 95/08/09Filesystem label=OS type: LinuxBlock size=4096 (log=2)Fragment size=4096 (log=2)90624 inodes, 181034 blocks9051 blocks (5.00%) reserved for the super userFirst data block=06 block groups32768 blocks per group, 32768 fragments per group15104 inodes per groupSuperblock backups stored on blocks: 32768, 98304, 163840Writing inode tables: doneWriting superblocks and filesystem accounting information: done
The MS-DOS partition table is especially common on PC type computers, which these days means nearly everywhere. You will prefer this format if you want to exchange your "disk" media with any PC type host system.
The fdisk command is used to create MS-DOS type partition tables; to create the same partitioning scheme as above you would use the following commands:
# fdisk /dev/hdaDevice contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabelBuilding a new DOS disklabel. Changes will remain in memory only,until you decide to write them. After that, of course, the previouscontent won't be recoverable.The number of cylinders for this disk is set to 1575.There is nothing wrong with that, but this is larger than 1024,and could in certain setups cause problems with:1) software that runs at boot time (e.g., old versions of LILO)2) booting and partitioning software from other OSs (e.g., DOS FDISK, OS/2 FDISK)Command (m for help): mCommand action a toggle a bootable flag b edit bsd disklabel c toggle the dos compatibility flag d delete a partition l list known partition types m print this menu n add a new partition o create a new empty DOS partition table p print the partition table q quit without saving changes s create a new empty Sun disklabel t change a partition's system id u change display/entry units v verify the partition table w write table to disk and exit x extra functionality (experts only)Command (m for help): nCommand action e extended p primary partition (1-4)pPartition number (1-4): 1First cylinder (1-1575, default 1):Using default value 1Last cylinder or +size or +sizeM or +sizeK (1-1575, default 1575): +2MCommand (m for help): pDisk /dev/hda: 16 heads, 63 sectors, 1575 cylindersUnits = cylinders of 1008 * 512 bytes Device Boot Start End Blocks Id System/dev/hda1 1 5 2488+ 83 LinuxCommand (m for help): nCommand action e extended p primary partition (1-4)pPartition number (1-4): 2First cylinder (6-1575, default 6):Using default value 6Last cylinder or +size or +sizeM or +sizeK (6-1575, default 1575): +2MCommand (m for help): pDisk /dev/hda: 16 heads, 63 sectors, 1575 cylindersUnits = cylinders of 1008 * 512 bytes Device Boot Start End Blocks Id System/dev/hda1 1 5 2488+ 83 Linux/dev/hda2 6 10 2520 83 LinuxCommand (m for help): nCommand action e extended p primary partition (1-4)pPartition number (1-4): 3First cylinder (11-1575, default 11):Using default value 11Last cylinder or +size or +sizeM or +sizeK (11-1575, default 1575): +64MCommand (m for help): tPartition number (1-4): 3Hex code (type L to list codes): 82Changed system type of partition 3 to 82 (Linux swap)Command (m for help): pDisk /dev/hda: 16 heads, 63 sectors, 1575 cylindersUnits = cylinders of 1008 * 512 bytes Device Boot Start End Blocks Id System/dev/hda1 1 5 2488+ 83 Linux/dev/hda2 6 10 2520 83 Linux/dev/hda3 11 141 66024 82 Linux swap
Note that we had to use the t command to mark this partition as swap space.
Command (m for help): nCommand action e extended p primary partition (1-4)pPartition number (1-4): 4First cylinder (142-1575, default 142):Using default value 142Last cylinder or +size or +sizeM or +sizeK (142-1575, default 1575):Using default value 1575Command (m for help): pDisk /dev/hda: 16 heads, 63 sectors, 1575 cylindersUnits = cylinders of 1008 * 512 bytes Device Boot Start End Blocks Id System/dev/hda1 1 5 2488+ 83 Linux/dev/hda2 6 10 2520 83 Linux/dev/hda3 11 141 66024 82 Linux swap/dev/hda4 142 1575 722736 83 LinuxCommand (m for help): wThe partition table has been altered!Calling ioctl() to re-read partition table. hda: hda1 hda2 hda3 hda4 hda: hda1 hda2 hda3 hda4WARNING: If you have created or modified any DOS 6.xpartitions, please see the fdisk manual page for additionalinformation.Syncing disks.
Now we are ready to initialize the partitions:
# mkswap /dev/hda3Setting up swapspace version 1, size = 67604480 bytes# mke2fs /dev/hda4mke2fs 1.19, 13-Jul-2000 for EXT2 FS 0.5b, 95/08/09Filesystem label=OS type: LinuxBlock size=4096 (log=2)Fragment size=4096 (log=2)90432 inodes, 180684 blocks9034 blocks (5.00%) reserved for the super userFirst data block=06 block groups32768 blocks per group, 32768 fragments per group15072 inodes per groupSuperblock backups stored on blocks: 32768, 98304, 163840Writing inode tables: doneWriting superblocks and filesystem accounting information: done
U-Boot provides only basic functionality to access PC Card based "disks": you can print the partition table and read and write blocks (addressed by absolute block number), but there is no support to create new partitions or to read files from any type of filesystem.
[Such features could be easily added as U-Boot extensions aka "standalone programs", but so far it has not been implemented yet.]
As usual, you can get some information about the available IDE commands using the help command in U-Boot:
=> help ide ide reset - reset IDE controlleride info - show available IDE deviceside device [dev] - show or set current deviceide part [dev] - print partition table of one or all IDE deviceside read addr blk# cntide write addr blk# cnt - read/write `cnt' blocks starting at block `blk#' to/from memory address `addr'
That means you will have to partition the "disk" on your host system; U-Boot can be configured for DOS and MacOS type partition tables. Since U-Boot cannot read files from a filesystem you should create one (or more) small partitions (maybe 1 MB or so) if you want to boot from the "disk".
For example on a 128 MBCompactFlash card we could create the following partiton table under Linux:
# fdisk /dev/hda hda: hda1 hda2 hda3 hda4Command (m for help): pDisk /dev/hda: 8 heads, 32 sectors, 978 cylindersUnits = cylinders of 256 * 512 bytes Device Boot Start End Blocks Id System/dev/hda1 1 17 2160 83 Linux/dev/hda2 18 34 2176 83 Linux/dev/hda3 35 803 98432 83 Linux/dev/hda4 804 978 22400 82 Linux swapCommand (m for help): q# mkswap /dev/hda4Setting up swapspace version 1, size = 22933504 bytes
Here we have two small boot partitions (/dev/hda1 and /dev/hda2, 2 MB each), one big partition to hold a filesystem (/dev/hda3, 99 MB), and a swap partition (/dev/hda4, 22 MB). We also initialized /dev/hda4 as swap space.
U-Boot will recognize this partition table as follows:
=> ide partPartition Map for IDE device 0 -- Partition Type: DOSPartition Start Sector Num Sectors Type 1 32 4320 83 2 4352 4352 83 3 8704 196864 83 4 205568 44800 82
We can now load a Linux kernel image over ethernet and store it both of the boot partitions:
=> tftp 100000 /tftpboot/uImageARP broadcast 1TFTP from server 10.0.0.2; our IP address is 10.0.0.99Filename '/tftpboot/uImage'.Load address: 0x100000Loading: ################################################################# ##############################################doneBytes transferred = 566888 (8a668 hex)=> ide write 100000 0x20 0x800IDE write: device 0 block # 32, count 2048 ... 2048 blocks written: OK=> ide write 100000 0x1100 0x800IDE write: device 0 block # 4352, count 2048 ... 2048 blocks written: OK
This requires a little more explanation: as you can see from the output of the help ide command, the write subcommand takes 3 arguments: a memory address from where the data are read, an (absolute) block number on the disk where the writing starts, and a number of disk blocks.
Since U-Boot expects all input in hex notation we have to perform some calculation: partition 1 starts at block (or sector) number 32, which is 0x20; partition 2 starts at block number 4352 = 0x1100.
We used a block count of 0x800 = 2048 in both cases - this means we wrote 2048 block of 512 bytes each, or a 1024 kB - much more than the actual size of the LInux kernel image - but the partition is big enough and we are on the safe side, so we didn't bother to calculate the exact block count.
To boot from a disk you can use the diskboot command:
=> help diskbootdiskboot loadAddr dev:part
The diskboot command (or short disk) expects a load address in RAM, and a combination of device and partition numbers, separated by a colon. It then reads the image from disk and stores it in memory. We can now boot it using the bootm command [to automatically boot the image define the U-Boot environment autostart with the value =yes=].
=> disk 400000 0:1Loading from IDE device 0, partition 1: Name: hda1 Type: PPCBoot Image Name: Linux-2.4.4 Created: 2001-11-11 18:11:11 UTC Image Type: PowerPC Linux Kernel Image (gzip compressed) Data Size: 566824 Bytes = 553 kB = 0 MB Load Address: 00000000 Entry Point: 00000000=> bootm 400000## Booting image at 00400000 ... Image Name: Linux-2.4.4 Created: 2001-11-11 18:11:11 UTC Image Type: PowerPC Linux Kernel Image (gzip compressed) Data Size: 566824 Bytes = 553 kB = 0 MB Load Address: 00000000 Entry Point: 00000000 Verifying Checksum ... OK Uncompressing Kernel Image ... OKLinux version 2.4.4 (wd@denx.denx.de) (gcc version 2.95.2 19991024 (release)) #1 Sun Nov 11 19:05:47 MET 2001On node 0 totalpages: 8192...
We can use the same method that we used to store a Linux kernel image to a disk partition to load a filesystem image into another partiton - as long as the image fits into physical RAM - but usually it's easier to initialize the filesystem either on the host system (swapping the PC Card between host and target is easy enough), or you can use the configuration with root filesystem over NFS to populate the filesystem on the target.
You only have to set the bootargs variable to boot Linux with root filesystem on disk, for instance:
=> setenv bootargs root=/dev/hda3=> setenv autostart yes=> disk 400000 0:1Loading from IDE device 0, partition 1: Name: hda1 Type: PPCBoot Image Name: Linux-2.4.4 Created: 2001-11-11 18:11:11 UTC Image Type: PowerPC Linux Kernel Image (gzip compressed) Data Size: 566824 Bytes = 553 kB = 0 MB Load Address: 00000000 Entry Point: 00000000Automatic boot of image at addr 0x00400000 ...## Booting image at 00400000 ... Image Name: Linux-2.4.4 Created: 2001-11-11 18:11:11 UTC Image Type: PowerPC Linux Kernel Image (gzip compressed) Data Size: 566824 Bytes = 553 kB = 0 MB Load Address: 00000000 Entry Point: 00000000 Verifying Checksum ... OK Uncompressing Kernel Image ... OKLinux version 2.4.4 (wd@denx.denx.de) (gcc version 2.95.2 19991024 (release)) #1 Sun Nov 11 19:05:47 MET 2001On node 0 totalpages: 8192zone(0): 8192 pages.zone(1): 0 pages.zone(2): 0 pages.Kernel command line: root=/dev/hda3 ip=10.0.0.99:10.0.0.2::255.0.0.0:tqm::off panic=1Decrementer Frequency: 3000000Calibrating delay loop... 47.82 BogoMIPSMemory: 30548k available (1088k kernel code, 488k data, 48k init, 0k highmem)Dentry-cache hash table entries: 4096 (order: 3, 32768 bytes)Buffer-cache hash table entries: 1024 (order: 0, 4096 bytes)Page-cache hash table entries: 8192 (order: 3, 32768 bytes)Inode-cache hash table entries: 2048 (order: 2, 16384 bytes)POSIX conformance testing by UNIFIXLinux NET4.0 for Linux 2.4Based upon Swansea University Computer Society NET3.039Starting kswapd v1.8CPM UART driver version 0.03ttyS0 on SMC1 at 0x0280, BRG1ttyS1 on SMC2 at 0x0380, BRG2pty: 256 Unix98 ptys configuredblock: queued sectors max/low 20226kB/6742kB, 64 slots per queueRAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksizeUniform Multi-Platform E-IDE driver Revision: 6.31ide: Assuming 50MHz system bus speed for PIO modes; override with idebus=xxPCMCIA slot B: phys mem e0000000...ec000000 (size 0c000000)Card ID: CF 128MB CH Fixed Disk Card IDE interface [silicon] [unique] [single] [sleep] [standby] [idle] [low power]hda: probing with STATUS(0x50) instead of ALTSTATUS(0x41)hda: CF 128MB, ATA DISK driveide0 at 0xc7000320-0xc7000327,0xc3000106 on irq 13hda: 250368 sectors (128 MB) w/16KiB Cache, CHS=978/8/32Partition check: hda: hda1 hda2 hda3 hda4eth0: FEC ENET Version 0.2, FEC irq 3, MII irq 4, addr 00:cb:bd:00:00:11JFFS version 1.0, (C) 1999, 2000 Axis Communications AB Amd/Fujitsu Extended Query Table v1.1 at 0x0040number of JEDEC chips: 1ICU862 flash bank 0: Using static image partition definitionCreating 8 MTD partitions on "ICU862 Bank 0":0x00000000-0x00100000 : "kernel"0x00100000-0x00400000 : "initrd"0x00400000-0x00800000 : "jffs"0x00800000-0x00c00000 : "cramfs"0x00c00000-0x00f00000 : "jffs2"0x00f00000-0x00f40000 : "ppcboot"0x00f40000-0x00f80000 : "environment"0x00f80000-0x01000000 : "spare"NET4: Linux TCP/IP 1.0 for NET4.0IP Protocols: ICMP, UDP, TCP, IGMPIP: routing cache hash table of 512 buckets, 4KbytesTCP: Hash tables configured (established 2048 bind 2048)NET4: Unix domain sockets 1.0/SMP for Linux NET4.0. hda: hda1 hda2 hda3 hda4 hda: hda1 hda2 hda3 hda4VFS: Mounted root (ext2 filesystem) readonly.Freeing unused kernel memory: 48k initinit started: BusyBox v0.51 (2001.11.06-02:06+0000) multi-call binaryBusyBox v0.51 (2001.11.06-02:06+0000) Built-in shell (lash)Enter 'help' for a list of built-in commands.#
If you are running out of system RAM, you can add virtual memory by using swap space. If you reserved a swap partition on your disk drive, you have to initialize it once using the mkswap command:
# fdisk -l /dev/hdaDisk /dev/hda: 16 heads, 63 sectors, 1575 cylindersUnits = cylinders of 1008 * 512 bytes Device Boot Start End Blocks Id System/dev/hda1 1 5 2488+ 83 Linux/dev/hda2 6 10 2520 83 Linux/dev/hda3 11 141 66024 82 Linux swap/dev/hda4 142 1575 722736 83 Linux# mkswap /dev/hda3Setting up swapspace version 1, size = 67604480 bytes
Then, to activate it, you use the swapon command like this:
# free total used free shared buffers cachedMem: 14628 14060 568 8056 100 11664-/+ buffers/cache: 2296 12332Swap: 0 0 0# free total used free shared buffers cachedMem: 14628 14060 568 8056 100 11664-/+ buffers/cache: 2296 12332Swap: 0 0 0# swapon /dev/hda3Adding Swap: 66016k swap-space (priority -2)# free total used free shared buffers cachedMem: 14628 14084 544 8056 100 11648-/+ buffers/cache: 2336 12292Swap: 66016 0 66016
If you forgot to reserve (sufficient) space in a separate partition on your disk, you can still use an ordinary file for swap space. You only have to create a file of appropriate size, and initialize it as follows:
# mount /dev/hda4 /mnt# dfFilesystem 1k-blocks Used Available Use% Mounted on/dev/root 2087212 1378824 708388 67% //dev/hda4 711352 20 675196 1% /mnt# dd if=/dev/zero of=/mnt/swapfile bs=1024k count=6464+0 records in64+0 records out# mkswap /mnt/swapfileSetting up swapspace version 1, size = 67104768 bytes
Then activate it:
# free total used free shared buffers cachedMem: 14628 14084 544 6200 96 11788-/+ buffers/cache: 2200 12428Swap: 0 0 0# swapon /mnt/swapfileAdding Swap: 65528k swap-space (priority -3)# free total used free shared buffers cachedMem: 14628 14084 544 6200 96 11752-/+ buffers/cache: 2236 12392Swap: 65528 0 65528
To complement theU-Boot Splash Screen feature the new configuration option "CONFIG_8xx_PRE_INIT_FB" was added to the Linux kernel. This allows the Linux kernel to skip certain parts of the framebuffer initialization and to reuse the framebuffer contents that was set up by the U-Boot firmware. This allows to have an image displayed nearly immediately after power-on, so the delay needed to boot the Linux kernel is masked to the user.
The current implementation has some limitations:
We did not succeed in reusing the previously allocated framebuffer contents directly. Instead, Linux will allocate a new framebuffer, copy the contents, and then switch the display. This adds a minimal delay to the boot time, but is otherwise invisible to the user.
Linux manages its own colormap, and we considered it too much effort to keep the same settings as used by U-Boot. Instead we use the "trick" that U-Boot will fill the color map table backwards (top down). This works pretty well for images which use no more than 200...255 colors. If the images uses more colors, a bad color mapping may result.
We strongly recommend to convert all images that will be loaded as Linux splash screens to use no more than 225 colors. The "ppmquant" tool can be used for this purpose (seeBitmap Support in U-Boot for details).
Usually there will be a Linux device driver that is used to adjust the brightness and contrast of the display. When this driver starts, a visible change of brightness will happen if the default settings as used by U-Boot differ.
We recommend to store settings of brightness and contrast in U-Boot environment variables that can be shared between U-Boot and Linux. This way it is possible (assuming adequate driver support) to adjust the display settings correctly already in U-Boot and thus to avoid any flicker of the display when Linux takes over control.
It is not an easy task to design the root file system for an embedded system. There are three major problems to be solved:
what to put in it
which file system type to use
where to store and how to boot it
For now we will assume that the contents of the root file system is aready known; for example, it is given to us as a directory tree or a tarball which contains all the required files.
We will also assume that our system is a typical resource-limited embedded system so we will especially look for solutions where the root file system can be stored on on-board flash memory or other flash memory based devices like CompactFlash or SD cards, MMC or USB memory sticks.
So our focus here is on the second item: the options we have for chosing a file system type and the consequences this has.
In all cases we will base our experiments on the same content of the root filesystem; we use the images of theSELF (Simple Embedded Linux Framework) that come with theELDK. In a first step we will transform theSELF images into a tarball to meet the requirements mentioned above:
In aELDK installation, theSELF images can be found in the /opt/eldk//images/ directory. There is already a compressed ramdisk image in this directory, which we will use (ramdisk_image.gz):
Uncompress ramdisk image:bash$ gzip -d -c -v /opt/eldk/ppc_8xx/images/ramdisk_image.gz >/tmp/ramdisk_image/opt/eldk/ppc_8xx/images/ramdisk_image.gz: 61.4%
Note: The following steps require root permissions!
Mount ramdisk image:bash# mount -o loop /tmp/ramdisk_image /mnt/tmp
Create tarball; to avoid the need for root permissions in the following steps we don't include the device files in our tarball:bash# cd /mnt/tmpbash# tar -zc --exclude='dev/*' -f /tmp/rootfs.tar.gz *
Instead, we create a separate tarball which contains only the device entries so we can use them when necessary (with cramfs):bash# tar -zcf /tmp/devices.tar.gz dev/bash# cd /tmp
Unmount ramdisk image:bash# umount /mnt/tmp
We will use the /tmp/rootfs.tar.gz tarball as master file in all following experiments.
Ram disks are used very often to hold the root file system of embedded systems. They have several advantages:
well-known
well-supported by the Linux kernel
simple to build
simple to use - you can even combine the ramdisk with the Linux kernel into a single image file
RAM based, thus pretty fast
writable file system
original state of file system after each reboot = easy recovery from accidental or malicious data corruption etc.
On the other hand, there are several disadvantages, too:
big memory footprint: you always have to load the complete filesystem into RAM, even if only small parts of are actually used
slow boot time: you have to load (and uncompress) the whole image before the first application process can start
only the whole image can be replaced (not individual files)
additional storage needed for writable persistent data
Actually there are only very few situations where a ramdisk image is the optimal solution. But because they are so easy to build and use we will discuss them here anyway.
In almost all cases you will use an ext2 file system in your ramdisk image. The following steps are needed to create it:
Create a directory tree with the content of the target root filesystem. We do this by unpacking our master tarball:$ mkdir rootfs$ cd rootfs$ tar zxf /tmp/rootfs.tar.gz
We use the genext2fs tool to create the ramdisk image as this allows to use a simple text file to describe which devices shall be created in the generated file system image. That means that no root permissions are required at all. We use the following device table rootfs_devices.tab:# /dev d 755 0 0 - - - - -/dev/console c 640 0 0 5 1 - - -/dev/fb0 c 640 0 0 29 0 - - -/dev/full c 640 0 0 1 7 - - -/dev/hda b 640 0 0 3 0 - - -/dev/hda b 640 0 0 3 1 1 1 16/dev/kmem c 640 0 0 1 2 - - -/dev/mem c 640 0 0 1 1 - - -/dev/mtd c 640 0 0 90 0 0 2 16/dev/mtdblock b 640 0 0 31 0 0 1 16/dev/mtdchar c 640 0 0 90 0 0 1 16/dev/mtdr c 640 0 0 90 1 0 2 16/dev/nftla b 640 0 0 93 0 - - -/dev/nftla b 640 0 0 93 1 1 1 8/dev/nftlb b 640 0 0 93 16 - - -/dev/nftlb b 640 0 0 93 17 1 1 8/dev/null c 640 0 0 1 3 - - -/dev/ptyp c 640 0 0 2 0 0 1 10/dev/ptypa c 640 0 0 2 10 - - -/dev/ptypb c 640 0 0 2 11 - - -/dev/ptypc c 640 0 0 2 12 - - -/dev/ptypd c 640 0 0 2 13 - - -/dev/ptype c 640 0 0 2 14 - - -/dev/ptypf c 640 0 0 2 15 - - -/dev/ram b 640 0 0 1 0 0 1 2/dev/ram b 640 0 0 1 1 - - -/dev/rtc c 640 0 0 10 135 - - -/dev/tty c 640 0 0 4 0 0 1 4/dev/tty c 640 0 0 5 0 - - -/dev/ttyS c 640 0 0 4 64 0 1 8/dev/ttyp c 640 0 0 3 0 0 1 10/dev/ttypa c 640 0 0 3 10 - - -/dev/ttypb c 640 0 0 3 11 - - -/dev/ttypc c 640 0 0 3 12 - - -/dev/ttypd c 640 0 0 3 13 - - -/dev/ttype c 640 0 0 3 14 - - -/dev/ttypf c 640 0 0 3 15 - - -/dev/zero c 640 0 0 1 5 - - -A description of the format of this table is part of the manual page for the genext2fs tool, genext2fs(8).
We can now create an ext2 file system image using the genext2fs tool:$ ROOTFS_DIR=rootfs # directory with root file system content$ ROOTFS_SIZE=3700 # size of file system image$ ROOTFS_FREE=100 # free space wanted$ ROOTFS_INODES=380 # number of inodes$ ROOTFS_DEVICES=rootfs_devices.tab # device description file$ ROOTFS_IMAGE=ramdisk.img # generated file system image$ genext2fs -U -d ${ROOTFS_DIR} -D ${ROOTFS_DEVICES} -b ${ROOTFS_SIZE} -r ${ROOTFS_FREE} -i ${ROOTFS_INODES} ${ROOTFS_IMAGE}
Compress the file system image:$ gzip -v9 ramdisk.imgrootfs.img: 55.6% -- replaced with ramdisk.img.gz
Create an U-Boot image file from it:$ mkimage -T ramdisk -C gzip -n 'Test Ramdisk Image' > -d ramdisk.img.gz uRamdiskImage Name: Test Ramdisk ImageCreated: Sun Jun 12 16:58:06 2005Image Type: PowerPC Linux RAMDisk Image (gzip compressed)Data Size: 1618547 Bytes = 1580.61 kB = 1.54 MBLoad Address: 0x00000000Entry Point: 0x00000000
We now have a root file system image uRamdisk that can be used with U-Boot.
JFFS2 (Journalling Flash File System version 2) was specifically designed for use on flash memory devices in embedded systems. It is a log-structured file system which means that it is robust against loss of power, crashes or other unorderly shutdowns of the system ("robust" means that data that is just being written when the system goes down may be lost, but the file system itself does not get corrupted and the system can be rebootet without need for any kind of file system check).
Some of the advantages of using JFFS2 as root file system in embedded systems are:
file system uses compression, thus making efficient use of flash memory
log-structured file system, thus robust against unorderly shutdown
writable flash file system
Disadvantages are:
long mount times (especially older versions)
slow when reading: files to be read get uncompressed on the fly which eatsCPU cycles and takes time
slow when writing: files to be written get compressed, which eatsCPU cycles and takes time, but it may even take much longer until data gets actually stored in flash if the file system becomes full and blocks must be erased first or - even worse - if garbage collection becomes necessary
The garbage collector thread may run at any time, consumingCPU cycles and blocking accesses to the file system.
Despite the aforementioned disadvantages, systems using a JFFS2 based root file system are easy to build, make efficient use of the available resources and can run pretty reliably.
To create a JFFS2 based root file system please proceed as follows:
Create a directory tree with the content of the target root filesystem. We do this by unpacking our master tarball:$ mkdir rootfs$ cd rootfs$ tar zxf /tmp/rootfs.tar.gz
We can now create a JFFS2 file system image using the mkfs.jffs2 tool:$ ROOTFS_DIR=rootfs # directory with root file system content$ ROOTFS_EBSIZE=0x20000 # erase block size of flash memory$ ROOTFS_ENDIAN=b # target system is big endian$ ROOTFS_DEVICES=rootfs_devices.tab # device description file$ ROOTFS_IMAGE=jffs2.img # generated file system image$ mkfs.jffs2 -U -d ${ROOTFS_DIR} -D ${ROOTFS_DEVICES} -${ROOTFS_ENDIAN} -e ${ROOTFS_EBSIZE} -o ${ROOTFS_IMAGE}mkfs.jffs2: skipping device_table entry '/dev': no parent directory!
Note: When you intend to write the JFFS2 file system image to a NAND flash device, you should also add the "-n" (or "--no-cleanmarkers") option, as cleanmarkers are not needed then.
When booting the Linux kernel prints the following messages showing the default partition map which is used for the flash memory on the TQM8xxL boards:
TQM flash bank 0: Using static image partition definitionCreating 7 MTD partitions on "TQM8xxL0":0x00000000-0x00040000 : "u-boot"0x00040000-0x00100000 : "kernel"0x00100000-0x00200000 : "user"0x00200000-0x00400000 : "initrd"0x00400000-0x00600000 : "cramfs"0x00600000-0x00800000 : "jffs"0x00400000-0x00800000 : "big_fs"
We use U-Boot to load and store the JFFS2 image into the last partition and set up the Linux boot arguments to use this as root device:
Erase flash:=> era 40400000 407FFFFF................. doneErased 35 sectors
Download JFFS2 image:=> tftp 100000 /tftpboot/TQM860L/jffs2.imgUsing FEC ETHERNET deviceTFTP from server 192.168.3.1; our IP address is 192.168.3.80Filename '/tftpboot/TQM860L/jffs2.img'.Load address: 0x100000Loading: ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ########doneBytes transferred = 2033888 (1f08e0 hex)
Copy image to flash:=> cp.b 100000 40400000 ${filesize}Copy to Flash... done
set up boot arguments to use flash partition 6 as root device:=> setenv mtd_args setenv bootargs root=/dev/mtdblock6 rw rootfstype=jffs2=> printenv addipaddip=setenv bootargs ${bootargs} ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}:${netdev}:off panic=1=> setenv flash_mtd 'run mtd_args addip;bootm ${kernel_addr}'=> run flash_mtdUsing FEC ETHERNET deviceTFTP from server 192.168.3.1; our IP address is 192.168.3.80Filename '/tftpboot/TQM860L/uImage'.Load address: 0x200000Loading: ################################################################# ################################################################# ###########doneBytes transferred = 719233 (af981 hex)## Booting image at 40040000 ... Image Name: Linux-2.4.25 Created: 2005-06-12 16:32:24 UTC Image Type: PowerPC Linux Kernel Image (gzip compressed) Data Size: 782219 Bytes = 763.9 kB Load Address: 00000000 Entry Point: 00000000 Verifying Checksum ... OK Uncompressing Kernel Image ... OKLinux version 2.4.25 (wd@xpert) (gcc version 3.3.3 (DENX ELDK 3.1.1 3.3.3-9)) #1 Sun Jun 12 18:32:18 MEST 2005On node 0 totalpages: 4096zone(0): 4096 pages.zone(1): 0 pages.zone(2): 0 pages.Kernel command line: root=/dev/mtdblock6 rw rootfstype=jffs2 ip=192.168.3.80:192.168.3.1::255.255.255.0:tqm860l:eth1:off panic=1Decrementer Frequency = 187500000/60Calibrating delay loop... 49.86 BogoMIPS...NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.VFS: Mounted root (jffs2 filesystem).Freeing unused kernel memory: 56k initBusyBox v0.60.5 (2005.03.07-06:54+0000) Built-in shell (msh)Enter 'help' for a list of built-in commands.# ### Application running ...# mountrootfs on / type rootfs (rw)/dev/mtdblock6 on / type jffs2 (rw)/proc on /proc type proc (rw)# df /Filesystem 1k-blocks Used Available Use% Mounted onrootfs 4096 2372 1724 58% /
cramfs is a compressed, read-only file system.
Advantages are:
file system uses compression, thus making efficient use of flash memory
Allows for quick boot times as only used files get loaded and uncompressed
Disadvantages are:
only the whole image can be replaced (not individual files)
additional storage needed for writable persistent data
mkcramfs tool does not support device table, so we need root permissions to create the required device files
To create a cramfs based root file system please proceed as follows:
Create a directory tree with the content of the target root filesystem. We do this by unpacking our master tarball:$ mkdir rootfs$ cd rootfs$ tar -zxf /tmp/rootfs.tar.gz
Create the required device files. We do this here by unpacking a special tarball which holds only the device file entries.Note: this requires root permissions!# cd rootfs# tar -zxf /tmp/devices.tar.gz
Many tools require some storage place in a filesystem, so we must provide at least one (small) writable filesystem. For all data which may be lost when the system goes down, a "tmpfs" filesystem is the optimal choice. To create such a writable tmpfs filesystem we add the following lines to the /etc/rc.sh script:# mount TMPFS because root-fs is readonly/bin/mount -t tmpfs -o size=2M tmpfs /tmpfsSome tools require write permissions on some device nodes (for example, to change ownership and permissions), or dynamically (re-) create such files (for example, /dev/log which is usually a Unix Domain socket). The files are placed in a writable filesystem; in the root filesystem symbolic links are used to point to their new locations: dev/ptyp0 → /tmpfs/dev/ptyp0     dev/ttyp0 → /tmpfs/dev/ttyp0
dev/ptyp1 → /tmpfs/dev/ptyp1     dev/ttyp1 → /tmpfs/dev/ttyp1
dev/ptyp2 → /tmpfs/dev/ptyp2     dev/ttyp2 → /tmpfs/dev/ttyp2
dev/ptyp3 → /tmpfs/dev/ptyp3     dev/ttyp3 → /tmpfs/dev/ttyp3
dev/ptyp4 → /tmpfs/dev/ptyp4     dev/ttyp4 → /tmpfs/dev/ttyp4
dev/ptyp5 → /tmpfs/dev/ptyp5     dev/ttyp5 → /tmpfs/dev/ttyp5
dev/ptyp6 → /tmpfs/dev/ptyp6     dev/ttyp6 → /tmpfs/dev/ttyp6
dev/ptyp7 → /tmpfs/dev/ptyp7     dev/ttyp7 → /tmpfs/dev/ttyp7
dev/ptyp8 → /tmpfs/dev/ptyp8     dev/ttyp8 → /tmpfs/dev/ttyp8
dev/ptyp9 → /tmpfs/dev/ptyp9     dev/ttyp9 → /tmpfs/dev/ttyp9
dev/ptypa → /tmpfs/dev/ptypa     dev/ttypa → /tmpfs/dev/ttypa
dev/ptypb → /tmpfs/dev/ptypb     dev/ttypb → /tmpfs/dev/ttypb
dev/ptypc → /tmpfs/dev/ptypc     dev/ttypc → /tmpfs/dev/ttypc
dev/ptypd → /tmpfs/dev/ptypd     dev/ttypd → /tmpfs/dev/ttypd
dev/ptype → /tmpfs/dev/ptype     dev/ttype → /tmpfs/dev/ttype
dev/ptypf → /tmpfs/dev/ptypf     dev/ttypf → /tmpfs/dev/ttypf
tmp → /tmpfs/tmp     var → /tmpfs/var
dev/log → /var/log/log
In case you use dhclient also:
etc/dhclient.conf → /tmpfs/var/lib/dhclient.conf     etc/resolv.conf → /tmpfs/var/lib/resolv.conf
To place the corresponding directories and device files in the tmpfs file system, the following code is added to the /etc/rc.sh script:mkdir -p /tmpfs/tmp /tmpfs/dev /tmpfs/var/lib/dhcp /tmpfs/var/lock /tmpfs/var/runwhile read name minordo mknod /tmpfs/dev/ptyp$name c 2 $minor mknod /tmpfs/dev/ttyp$name c 3 $minordone <<__EOD__0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 a 10 b 11 c 12 d 13 e 14 f 15 __EOD__ chmod 0666 /tmpfs/dev/*
We can now create a cramfs file system image using the mkcramfs tool:$ ROOTFS_DIR=rootfs # directory with root file system content$ ROOTFS_ENDIAN="-r" # target system has reversed (big) endianess$ ROOTFS_IMAGE=cramfs.img # generated file system imagePATH=/opt/eldk/usr/bin:$PATHmkcramfs ${ROOTFS_ENDIAN} ${DEVICES} ${ROOTFS_DIR} ${ROOTFS_IMAGE}Swapping filesystem endian-ness bin dev etc...-48.78% (-86348 bytes) in.ftpd-46.02% (-16280 bytes) in.telnetd-45.31% (-74444 bytes) xinetdEverything: 1864 kilobytesSuper block: 76 bytesCRC: c166be6dwarning: gids truncated to 8 bits. (This may be a security concern.)
We can use the same setup as before for the JFFS2 filesystem, just changing the bootargument to "rootfstype=cramfs"
When storing the root file system in on-board flash memory it seems only natural to look for special falsh filesystems like JFFS2, or for other file system types that are designed for such environments like cramfs. It seems to be a bad idea to use a standard ext2 file system because it contains neither any type of wear levelling which is needed for writable file systems in flash memory, nor is it robust against unorderly shutdowns.
The situation changes if we use an ext2 file system which we mount read-only. Such a configuration can be very useful in some situations.
Advantages:
very fast
low RAM memory footprint
Disadvantages:
high flash memory footprint because no compression
To create an ext2 image that can be used as a read-only root file system the following steps are necessary:
Create a directory tree with the content of the target root filesystem. We do this by unpacking our master tarball:$ mkdir rootfs$ cd rootfs$ tar -zxf /tmp/rootfs.tar.gz
Like with the cramfs root file system, we use "tmpfs" for cases where a writable file system is needed and add the following lines to the /etc/rc.sh script:# mount TMPFS because root-fs is readonly/bin/mount -t tmpfs -o size=2M tmpfs /tmpfsWe also create the same symbolic links for device files that must be placed in a writable filesystem: dev/ptyp0 → /tmpfs/dev/ptyp0     dev/ttyp0 → /tmpfs/dev/ttyp0
dev/ptyp1 → /tmpfs/dev/ptyp1     dev/ttyp1 → /tmpfs/dev/ttyp1
dev/ptyp2 → /tmpfs/dev/ptyp2     dev/ttyp2 → /tmpfs/dev/ttyp2
dev/ptyp3 → /tmpfs/dev/ptyp3     dev/ttyp3 → /tmpfs/dev/ttyp3
dev/ptyp4 → /tmpfs/dev/ptyp4     dev/ttyp4 → /tmpfs/dev/ttyp4
dev/ptyp5 → /tmpfs/dev/ptyp5     dev/ttyp5 → /tmpfs/dev/ttyp5
dev/ptyp6 → /tmpfs/dev/ptyp6     dev/ttyp6 → /tmpfs/dev/ttyp6
dev/ptyp7 → /tmpfs/dev/ptyp7     dev/ttyp7 → /tmpfs/dev/ttyp7
dev/ptyp8 → /tmpfs/dev/ptyp8     dev/ttyp8 → /tmpfs/dev/ttyp8
dev/ptyp9 → /tmpfs/dev/ptyp9     dev/ttyp9 → /tmpfs/dev/ttyp9
dev/ptypa → /tmpfs/dev/ptypa     dev/ttypa → /tmpfs/dev/ttypa
dev/ptypb → /tmpfs/dev/ptypb     dev/ttypb → /tmpfs/dev/ttypb
dev/ptypc → /tmpfs/dev/ptypc     dev/ttypc → /tmpfs/dev/ttypc
dev/ptypd → /tmpfs/dev/ptypd     dev/ttypd → /tmpfs/dev/ttypd
dev/ptype → /tmpfs/dev/ptype     dev/ttype → /tmpfs/dev/ttype
dev/ptypf → /tmpfs/dev/ptypf     dev/ttypf → /tmpfs/dev/ttypf
tmp → /tmpfs/tmp     var → /tmpfs/var
dev/log → /var/log/log
In case you use dhclient also:
etc/dhclient.conf → /tmpfs/var/lib/dhclient.conf     etc/resolv.conf → /tmpfs/var/lib/resolv.conf
To place the corresponding directories and device files in the tmpfs file system, the following code is added to the /etc/rc.sh script:mkdir -p /tmpfs/tmp /tmpfs/dev /tmpfs/var/lib/dhcp /tmpfs/var/lock /tmpfs/var/runwhile read name minordo mknod /tmpfs/dev/ptyp$name c 2 $minor mknod /tmpfs/dev/ttyp$name c 3 $minordone <<__EOD__0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 a 10 b 11 c 12 d 13 e 14 f 15 __EOD__ chmod 0666 /tmpfs/dev/*
Like we did for the ramdisk, we now create an ext2 file system image using the genext2fs tool:$ ROOTFS_DIR=rootfs # directory with root file system content$ ROOTFS_SIZE=3700 # size of file system image$ ROOTFS_FREE=100 # free space wanted$ ROOTFS_INODES=380 # number of inodes$ ROOTFS_DEVICES=rootfs_devices.tab # device description file$ ROOTFS_IMAGE=ext2.img # generated file system image$ genext2fs -U -d ${ROOTFS_DIR} -D ${ROOTFS_DEVICES} -b ${ROOTFS_SIZE} -r ${ROOTFS_FREE} -i ${ROOTFS_INODES} ${ROOTFS_IMAGE}
We can again use the same setup as before for the JFFS2 filesystem, just changing the bootargument to "rootfstype=ext2" (or simply omit it completely as this is the default anyway), and we must change the "rw" argument into "ro" to mount our root file system really read-only:...Linux version 2.4.25 (wd@xpert) (gcc version 3.3.3 (DENX ELDK 3.1.1 3.3.3-9)) #1 Sun Jun 12 18:32:18 MEST 2005On node 0 totalpages: 4096zone(0): 4096 pages.zone(1): 0 pages.zone(2): 0 pages.Kernel command line: root=/dev/mtdblock6 ro rootfstype=ext2 ip=192.168.3.80:192.168.3.1::255.255.255.0:tqm860l:eth1:off panic=1Decrementer Frequency = 187500000/60Calibrating delay loop... 49.86 BogoMIPS...
Using an ext2 file system on a flash memory card (like CompactFlash, SD, MMC or a USB memory stick) is standard technology. To avoid unnecessary flash wear it is a good idea to mount the root file system read-only, or at least using the "noatime" mount option.
For our test we can use the "ext2.img" file from the previous step without changes:
In this test we use a standard CompactFlash card which comes with a single partition on it. We use U-Boot to copy the ext2 file system image into this partition:=> tftp 100000 /tftpboot/TQM860L/ext2.imgUsing FEC ETHERNET deviceTFTP from server 192.168.3.1; our IP address is 192.168.3.80Filename '/tftpboot/TQM860L/ext2.img'.Load address: 0x100000Loading: ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ##########################doneBytes transferred = 3788800 (39d000 hex)=> ide partPartition Map for IDE device 0 -- Partition Type: DOSPartition Start Sector Num Sectors Type 1 32 500704 6=> ide write 100000 20 1ce8IDE write: device 0 block # 32, count 7400 ... 7400 blocks written: OKNote that the "ide write" command takes parameters as hex numbers, and the write count is in terms of disk blocks of 512 bytes each. So we have to use 0x20 for the starts sector of the first partition, and 3788800 / 512 = 7400 = 0x1CE8 for the block count.
We now prepare the Linux boot arguments to take this partition as read-only root device:=> setenv cf_args setenv bootargs root=/dev/hda1 ro=> setenv flash_cf 'run cf_args addip;bootm ${kernel_addr}'=> setenv bootcmd run flash_cf
...and boot the system:...Linux version 2.4.25 (wd@xpert) (gcc version 3.3.3 (DENX ELDK 3.1.1 3.3.3-9)) #1 Sun Jun 12 18:32:18 MEST 2005On node 0 totalpages: 4096zone(0): 4096 pages.zone(1): 0 pages.zone(2): 0 pages.Kernel command line: root=/dev/hda1 ro ip=192.168.3.80:192.168.3.1::255.255.255.0:tqm860l:eth1:off panic=1Decrementer Frequency = 187500000/60Calibrating delay loop... 49.86 BogoMIPS...
This is a more complicated example that shows that - depending on project requirements - many other alternatives for chosing a root file system for your embedded system exist.
The szenario is as follows: on your embedded device you use a cheap and popular storage medium like CompactFlash, MMC or SD cards or USB memory sticks to store both the Linux kernel and your root file system. You want to distribute software updates over the internet: your customers can download the file from your web site, or you sent the images by email. Your customers may use any flash card or memory stick they happen to find, so you have no information about brand or size of the storage device.
Unfortunately most of your customers use Windows systems. And they don't want to be bothered with long instructions how to create special partitions on the storage device or how to write binary images or things like that. A simple "copy file" operation is nearly exhausting their capabilities.
What to do? Well, if copying a file is all your customers can do we should not ask for more. Storage devices like CompactFlash cards etc. typically come with a single partition on it, which holds a FAT or VFAT file system. This cannot be used as a Linux root file system directly, so we have to use some trickery.
Here is one possible solution: Your software distribution consistes of two files: The first file is the Linux kernel with a minimal ramdisk image attached (using the multi-file image format for U-Boot); U-Boot can load and boot such files from a FAT or VFAT file system. The second file is your root file system. For convenience and speed we use again an image of an ext2 file system. When Linux boots, it will initially use the attached ramdisk as root file system. The programs in this ramdisk will mount the FAT or VFAT file system - read-only. Then we can use a loop device (see losetup(8)) to associate the root file system image with a block device which can be used as a mount point. And finally we use pivot_root(8) to change the root file system to our image on the CF card.
This sounds not so complicated, and actually it is quite simple once you understand what needs to be done. Here is a more detailed description:
The root file system image is easy: as mantioned before, we will use an ext2 file system image, and to avoid wearing the flash storage device we will use it in read-only mode - we did a read-only ext2 root file system image before, and here we can just re-use the existing image file.
The initial ramdisk image that performs the pivot_root step must be created from scratch, but we already know how to create ramdisk images, so we just have to figure out what to put in it.
The most important tool here is nash, a script interpreter that was specifically designed for such purposes (see nash(8)). We don't need any additional tools, and if we use static linking, that the nash binary plus a small script to control it is all we need for our initial ramdisk.
To be precise, we need a couple of (empty) directories (bin, dev, etc, lib, loopfs, mnt, proc, and sysroot), the bin/nash binary, the linuxrc script and a symbolic link sbin pointing to bin:drwxr-xr-x 2 wd users 4096 Apr 13 01:11 bin-rwxr-xr-x 1 wd users 469512 Apr 11 22:47 bin/nashdrwxr-xr-x 2 wd users 4096 Apr 12 00:04 devdrwxr-xr-x 2 wd users 4096 Apr 12 00:04 etcdrwxr-xr-x 2 wd users 4096 Apr 12 00:04 lib-rwxr-xr-x 1 wd users 511 Apr 13 01:28 linuxrcdrwxr-xr-x 2 wd users 4096 Apr 12 00:04 loopfsdrwxr-xr-x 2 wd users 4096 Apr 12 00:09 mntdrwxr-xr-x 2 wd users 4096 Apr 12 00:04 proclrwxrwxrwx 1 wd users 3 Jun 12 18:54 sbin -> bindrwxr-xr-x 2 wd users 4096 Apr 12 00:04 sysroot
We also need only a minimal device table for creating the initial ramdisk:# /dev d 755 0 0 - - - - -/dev/console c 640 0 0 5 1 - - -/dev/hda b 640 0 0 3 0 - - -/dev/hda b 640 0 0 3 1 1 1 8/dev/loop b 640 0 0 7 0 0 1 4/dev/null c 640 0 0 1 3 - - -/dev/ram b 640 0 0 1 0 0 1 2/dev/ram b 640 0 0 1 1 - - -/dev/tty c 640 0 0 4 0 0 1 4/dev/tty c 640 0 0 5 0 - - -/dev/ttyS c 640 0 0 4 64 0 1 4/dev/zero c 640 0 0 1 5 - - -
To create the initial ramdisk we perform the usual steps:$ INITRD_DIR=initrd$ INITRD_SIZE=490$ INITRD_FREE=0$ INITRD_INODES=54$ INITRD_DEVICES=initrd_devices.tab$ INITRD_IMAGE=initrd.img$ genext2fs -U -d ${INITRD_DIR} -D ${INITRD_DEVICES} -b ${INITRD_SIZE} -r ${INITRD_FREE} -i ${INITRD_INODES} ${INITRD_IMAGE}$ gzip -v9 ${INITRD_IMAGE}The result is a really small (233 kB) compressed ramdisk image.
Assuming you already have your Linux kernel image, you can now use mkimage to build an U-Boot multi-file image that combines the Linux kernel and the initial ramdisk:$ LINUX_KERNEL=linuxppc_2_4_devel/arch/ppc/boot/images/vmlinux.gz$ mkimage -A ppc -O Linux -T multi -C gzip > -n 'Linux with Pivot Root Helper' > -d ${LINUX_KERNEL}:${INITRD_IMAGE}.gz linux.imgImage Name: Linux with Pivot Root HelperCreated: Mon Jun 13 01:48:11 2005Image Type: PowerPC Linux Multi-File Image (gzip compressed)Data Size: 1020665 Bytes = 996.74 kB = 0.97 MBLoad Address: 0x00000000Entry Point: 0x00000000Contents: Image 0: 782219 Bytes = 763 kB = 0 MB Image 1: 238433 Bytes = 232 kB = 0 MBThe newly created file linux.img is the second image we have to copy to the CF card.
We are done.
But wait - one essential part was not mentioned yet: the linuxrc script in our initial ramdisk image which contains all the magic. This script is quite simple:
#!/bin/nashecho Mounting /proc filesystemmount -t proc /proc /procecho Creating block devicesmkdevices /devecho Creating root devicemkrootdev /dev/rootecho 0x0100 > /proc/sys/kernel/real-root-devecho Mounting flash cardmount -o noatime -t vfat /dev/hda1 /mntecho losetup for filesystem imagelosetup /dev/loop0 /mnt/rootfs.imgecho Mounting root filesystem imagemount -o defaults --ro -t ext2 /dev/loop0 /sysrootecho Running pivot_rootpivot_root /sysroot /sysroot/initrdumount /initrd/proc
Let's go though it step by step:
The first line says that it's a script file for the /bin/nash interpreter.
Note: even if this file looks like a shell script it is NOT interpreted by a shell, but by the nash interpreter. For a complete list of available nash commands and their syntax please refer to the manual page, nash(8).
The first action is to mount the /proc pseudo file system which is needed to find out some required information.
Then we create block device entries for all partitions listed in /proc/partitions (mkdevices command).
In the next step a block device for our new root file system is created (mkrootdev command).
Then we mount the CF card. We assume that there is only a single partition on it (/dev/hda1) which is of type VFAT (which also will work with FAT file systems). These assumptions work fine with basicly all memory devices used under Windows.
We further assume that the file name of the root file system image on the CF card is "rootfs.img" - this file now gets mounted using a loop device (losetup and mount commands).
Our file system image, is now mounted on the /sysroot directory. In the last step we use pivot_root to make this the new root file system.
As a final cleanup we unmount the /proc file system which is not needed any more.
There is one tiny flaw in this method: since we mount the CF card on a directory in the ramdisk to be able to access to root file system image. This means that we cannot unmount the CF card, which in turn prevents us from freeing the space for the inital ramdisk. The consequence is that you permanently lose approx. 450 kB of RAM for the ramdisk. [We could of course re-use this ramdisk space for temporary data, but such optimization is beyond the scope of this document.]
And how does this work on our target?
First we copy the two images to the CF card; we do this on the target under Linux:bash-2.05b# fdisk -l /dev/hdaDisk /dev/hda: 256 MB, 256376832 bytes16 heads, 32 sectors/track, 978 cylindersUnits = cylinders of 512 * 512 = 262144 bytes Device Boot Start End Blocks Id System/dev/hda1 * 1 978 250352 6 FAT16bash-2.05b# mkfs.vfat /dev/hda1mkfs.vfat 2.8 (28 Feb 2001)bash-2.05b# mount -t vfat /dev/hda1 /mntbash-2.05b# cp -v linux.img rootfs.img /mnt/`linux.img' -> `/mnt/linux.img'`rootfs.img' -> `/mnt/rootfs.img'bash-2.05b# ls -l /mnttotal 4700-rwxr--r-- 1 root root 1020729 Jun 14 05:36 linux.img-rwxr--r-- 1 root root 3788800 Jun 14 05:36 rootfs.imgbash-2.05b# umount /mnt
We now prepare U-Boot to load the "uMulti" file (combined Linux kernel and initial ramdisk) from the CF card and boot it:=> setenv fat_args setenv bootargs rw=> setenv fat_boot 'run fat_args addip;fatload ide 0:1 200000 linux.img;bootm'=> setenv bootcmd run fat_boot
And finally we try it out:U-Boot 1.1.3 (Jun 13 2005 - 02:24:00)CPU: XPC86xxxZPnnD4 at 50 MHz: 4 kB I-Cache 4 kB D-Cache FEC presentBoard: TQM860LDB0A3-T50.202DRAM: 16 MBFLASH: 8 MBIn: serialOut: serialErr: serialNet: SCC ETHERNET, FEC ETHERNET [PRIME]PCMCIA: 3.3V card found: Transcend 256M Fixed Disk Card IDE interface [silicon] [unique] [single] [sleep] [standby] [idle] [low power]Bus 0: OK Device 0: Model: Transcend 256M Firm: 1.1 Ser#: SSSC256M04Z27A25906T Type: Removable Hard Disk Capacity: 244.5 MB = 0.2 GB (500736 x 512)Type "run flash_nfs" to mount root filesystem over NFSHit any key to stop autoboot: 0 reading linux.img1025657 bytes read## Booting image at 00200000 ... Image Name: Linux with Pivot Root Helper Created: 2005-06-13 0:32:41 UTC Image Type: PowerPC Linux Multi-File Image (gzip compressed) Data Size: 1025593 Bytes = 1001.6 kB Load Address: 00000000 Entry Point: 00000000 Contents: Image 0: 787146 Bytes = 768.7 kB Image 1: 238433 Bytes = 232.8 kB Verifying Checksum ... OK Uncompressing Multi-File Image ... OK Loading Ramdisk to 00f3d000, end 00f77361 ... OKLinux version 2.4.25 (wd@xpert) (gcc version 3.3.3 (DENX ELDK 3.1.1 3.3.3-9)) #1 Mon Jun 13 02:32:10 MEST 2005On node 0 totalpages: 4096zone(0): 4096 pages.zone(1): 0 pages.zone(2): 0 pages.Kernel command line: rw ip=192.168.3.80:192.168.3.1::255.255.255.0:tqm860l:eth1:off panic=1Decrementer Frequency = 187500000/60Calibrating delay loop... 49.86 BogoMIPS...NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.RAMDISK: Compressed image found at block 0Freeing initrd memory: 232k freedVFS: Mounted root (ext2 filesystem).Red Hat nash version 4.1.18 startingMounting /proc filesystemCreating block devicesCreating root deviceMounting flash card hda: hda1 hda: hda1losetup for filesystem imageMounting root filesystem imageRunning pivot_rootFreeing unused kernel memory: 60k initBusyBox v0.60.5 (2005.03.07-06:54+0000) Built-in shell (msh)Enter 'help' for a list of built-in commands.# ### Application running ...
Now we know several options for file systems we can use, and know how to create the corresponding images. But how can we decide which one to chose?
For practical purposes in embedded systems the following criteria are often essential:
boot time (i. e. time needed from power on until application code is running)
flash memory footprint
RAM memory footprint
effects on software updates
The following data was measured for the different configurations. All measurements were performed on the same TQM860L board (MPC860CPU at 50 MHz, 16 MB RAM, 8 MB flash, 256 MB CompactFlash card):
File System TypeBoot TimeFree MemUpdateswhile running
ramdisk 16.3 sec 6.58 MB whole image yes
JFFS2 21.4 sec 10.3 MB per file only non-active files
cramfs 10.8 sec 10.3 MB whole image no
ext2 (ro) 9.1 sec 10.8 MB whole image no
ext2 on CF (ro) 9.3 sec 10.9 MB whole image no
File on FAT fs 11.4 sec 7.8 MB whole image yes
As you can see, the ramdisk solution is the worst of all in terms of RAM memory footprint; also it takes a pretty long time to boot. However, it is one of the few solutions that allow an in-situ update while the system is running.
JFFS2 is easy to use as it's a writable file system but it takes a long time to boot.
A read-only ext2 file system shines when boot time and RAM memory footprint are important; you pay for this with an increased flash memory footprint.
External flash memory devices like CompactFlash cards or USB memory sticks can be cheap and efficient solutions especially when lots of data need to be stored or when easy update procedures are required. -
Introduction
Overlay File Systems provide an interesting approach to several frequent problems in Embedded Systems. For example, mini_fo is a virtual kernel file system that can make read-only file systems writable. This is done by redirecting modifying operations to a writeable location called "storage directory", and leaving the original data in the "base directory" untouched. When reading, the file system merges the modifed and original data so that only the newest versions will appear. This occurs transparently to the user, who can access the data like on any other read-write file system.
What it is good for?
In embedded systems the main use of mini_fo is to overlay the root file system. This means it is mounted on top of the regular root file system, thereby allowing applications or users to transparently make modifications to it but redirecting these to a different location.
Some examples of why this is usefull are explained in the following sections.
Making a read-only root filesystem writeable
Root file systems stored in flash are often read only, such ascramfs orread only ext2. While this offers major advantages in terms of speed and flash memory footprint, it nevertheless is often desireable to be able to modify the root file system, for example to
apply (small) software updates without having to burn a whole new root file system image to flash
make modifications during developement when frequent changes to the root file system occur.
This can be achieved by mounting mini_fo on top of the root file system and using a (probably small) writeable partition as the storage file system. This could be either a JFFS2 flash file system, or during development even an external hard disk. This has the following advantages:
read-only file systems (fast, small memory footprint) can be used like persistent writable file systems (in contrast to a ramdisk)
slow flash journalling file systems with large flash memory footprint can be avoided.
Non persistant changes
Ramdisks are often used when the root file system needs to be modified non-persistantly. This works well, but downsides are the large RAM memory footprint and the time costly operation of copying the ramdisk into RAM during startup. These can be avoided by overlaying the root file system as in the previous example but with the difference that thetmpfs file system is used as storage. Thus only modified files are stored in RAM, and can even be swapped out if neccessary. This saves boot time and RAM!
Resetable changes
Mini_fo can be easily used to implement a "reset to factory defaults" function by overlaying the default root file system. When configuration changes are made, these are automatically directed to the storage file system and take precedence over the original files. Now, to restore the system to factory defaults, all that needs to be done is delete the contents of the storage directory. This will remove all changes made to the root file system and return it to the original state.
Note: Deleting the contents of the storage directory should only be done when the overlay file system is unmounted.
Examples
Generally, there are two different ways of overlaying the root file system, which both make sense in different scenarios.
Starting a single application in a chrooted overlayed environment
This is easy. Let's assume "/" is the read-only root file system and /dev/mtdblock5 contains a small JFFS2 flash partition that shall be used to store modifications made by application "/usr/bin/autoPilot":
# mount -t jffs2 /dev/mtdblock5 /tmp/sto# insmod mini_fo.o# mount -t mini_fo -o base=/,sto=/tmp/sto/ / /mnt/mini_fo/# cd /mnt/mini_fo/# chroot . /usr/bin/autoPilot
The mini_fo file system is mounted with "/" as base directory, "/tmp/sto/" as storage directory to the mount point "/mnt/mini_fo". After that, chroot(1) is used to start the application with the new file system root "/mnt/mini_fo". All modifications made by the application will be stored to the JFFS2 file system in /tmp/sto.
Starting the whole system system in chrooted overlayed environment
This is more interesting, and a bit trickier, as mounting needs to be done during system startup after the root file system has been mounted, but before init is started. The best way to do this is to have a script that mounts the mini_fo file system on top of root and then starts init in the chrooted overlayed environment. For example assume the following script "overlay_init", stored in /sbin/:
#!/bin/bash## mount mini_fo overlay file system and execute init## make sure these exist in the read-only file systemSTORAGE=/tmp/stoMOUNT_POINT=/mnt/mini_fo/# mount tmpfs as storage file system with a maximum size of 32MBmount -t tmpfs -o rw,size=32M none $STORAGE/sbin/modprobe mini_fomount -t mini_fo -o base=/,sto=$STORAGE / $MOUNT_POINTexec /usr/sbin/chroot $MOUNT_POINT /sbin/initecho "exec chroot failed, bad!"exec /bin/shexit 1
Now its easy to choose between a mini_fo overlayed and the regular non overlayed system just by setting the "init" kernel parameter in the boot loader to "init=/sbin/overlay_init".
Tips
pivot_root(1) can be used with chroot if there is need to access the original non overlayed root file system from the chrooted overlayed environment.
Performance overhead
The mini_fo file system is inserted as an additional layer between the VFS and the native file system, and thus creates some overhead that varies strongly depending of the operation performed.
modifying a regular file for the first time
This results in a copy of the original file beeing created in the storage directory, that is then modified. Overhead depends on the size of the modified file.
Reading from files, creating new files, modifying already modified files
These operations are passed directly through to the lower native layer, and only impose an overhead of 1-2%.
Further information
This section discusses how the mini_fo overlay file system can be used in embedded systems. More general information is available at the mini_fo project page:http://www.denx.de/wiki/Know/MiniFOHome.
The pramfs file system supports persistent memory devices such as SRAM. Instead of having a block emulation layer over such a memory area and using a normal file system on top of that, pramfs seeks to induce minimal overhead in this situation. Most important in this respect is that the normal block layer caching of the Linux kernel is circumvented in pramfs.
The most important parameters for normal usage are
physaddr: The physical address of the static memory.
init: When given, it will initialize the file system to that size.
We will show a sample usage of pramfs in this section using normal DRAM on a board with at least 256MB of memory. For pramfs we reserve the upper 32MB by appending mem=224M to the kernel command line.
First off we generate some testdata on a persistent file system (/tmp) to demonstrate that pramfs survives a reboot (of course with power always applied to keep the DRAM refreshed):
bash-3.00# dd if=/dev/urandom bs=1M count=8 of=/tmp/testdata8+0 records in8+0 records outbash-3.00#
Next we mount the 32MB that we reserved and initialize it to be 32MB in size and copy the testfile. A final compare shows that the copy was indeed successful so we can reboot:
bash-3.00# mount -t pramfs -o physaddr=0xe000000,init=0x2000000 none /mntbash-3.00# cp /tmp/testdata /mntbash-3.00# cmp /tmp/testdata /mnt/testdatabash-3.00# reboot
Having rebooted (using mem=224M on the kernel command line again of course) we mount the file system but this time without the init parameter because it is preinitialized. We then check the contents again:
bash-3.00# mount -t pramfs -o physaddr=0xe000000 none /mntbash-3.00# ls /mnttestdatabash-3.00# cmp /tmp/testdata /mnt/testdatabash-3.00# 您可能會有興趣的文章
浴室夢幻逸品:Just Rain
茫茫磚海
磁磚挑選心得-part I
3.1.0 PatchNote(英文版)
welkinchen 发表在痞客邦 PIXNET回响(1)引用(0) 人气(331)

全站分类:未分类
个人分类:Embedded System
此分类上一篇:The DENX U-Boot and Linux Guide (DULG) for TQM8xxL (3)
此分类下一篇:The DENX U-Boot and Linux Guide (DULG) for TQM8xxL (5)
历史上的今天
2010:benchmark 在 mplayer 中分析收集播放的數據
2010:libmad 分析
2010:Mplayer source code trace (2)
2010:Mplayer source code trace (1)
2010:Mplayer 播放時,顯示狀態行上的數字所代表的意義
2010:FFmpeg 使用筆記
2010:FFMpeg MPEG2 TS 串流解碼的流程分析
2010:使用 mplayer & ffmpeg 分析多媒體檔案訊息
2010:mplayer & ffmpeg 指令
2010:mplayer 直接導到背景執行
2010:Mplayer A/V Sync 音視頻同步原理
2010:C 變數、函式可視範圍 static 與 extern
2010:如何同步視頻
2010:Video Clock & Time Reference
2010:Timing Model
2010:From 1 billion light-years to 0.1 fermis
2010:微秒 時間 轉換
2010:小蘇打-居家清潔的好幫手
2010:U-boot 初探
2010:U-boot 啟動內容及基礎指令使用介紹
2010:The DENX U-Boot and Linux Guide (DULG) for TQM8xxL (6)
2010:The DENX U-Boot and Linux Guide (DULG) for TQM8xxL (5)
2010:The DENX U-Boot and Linux Guide (DULG) for TQM8xxL (3)
2010:The DENX U-Boot and Linux Guide (DULG) for TQM8xxL (2)
2010:The DENX U-Boot and Linux Guide (DULG) for TQM8xxL (1)
2010:建立 Linux 檔案系統 (使用 Busybox )
2010:ARM9 s3c2410 移植 linux-2.6.14.1 實作攻略
2010:利用RTC時間設定linux系統時間(With ARM)
2010:U-boot 相關指令
2010:Before BootLoader