使用ramdisk和cramfs
早年写的笔记,压箱底了,翻出来晒晒
目录
实验环境
u IXP425DP(P720 板) 266Mhz 64M ram16M flash
u FC4: kernel 2.6.11-1.1369_FC4smp(FC6 也行),安装在虚拟机上
u arm-linux-tools-20051123.tar.gz: gcc 3.4.4编译器
u snapgear-3.5.0.tar.gz: snapgear 发布的uClinux 包
u snapgear-modules-20071004.sh: snapgear 发布的uClinux 包
u Kernel files in /home/linuxuser/snapgear
在ramdisk中使用busybox作为init
在前面讲到过,使用默认的配置已经可以启动uclinux2.4了。在此讲解如何在ramdisk中使用busybox作为init,代替系统的init。这对于进一步采用cramfs有帮助。
Busybox的init配置编译完成之后,会在ramdisk根目录下形成linuxrc的链接,并且生成/bin/init,实际上也是个链接。
Kernel command保持为
console=ttyS1,115200root=/dev/ram0 initrd=0x00800000,8Mmem=64M@0x00000000
启动的时候,linuxrc会被先执行。Busybox的initab格式很规矩,并且在/busybox/example下有样例.
配置uClinux内核和busybox
2.6的配置和2.4的一模一样,因为实际上配置的都是busybox,而不是内核.
在前面讲解一直uClinux2.4的基础上,要加入以下改动。
1. make menuconfig之后再主菜单中选择Kernel/Library/DefaultsSelection-->Customize Vendor/User Settings。保存退出,会出现Customize Vendor/User Settings的菜单。
2. 在Customize Vendor/User Settings的菜单中,选择BusyBox-->init。选中之后,会出现
init: use inittab
init: /linuxrc
init: core dumps
init: support running init from within aninitrd?
除了init: coredumps是debug用的以外一起选上.
选完之后保存,使用makedep, make编译。
配置启动文件
使用直接的busybox init,这个就需要修改inittab. Rc. Busy box的init和系统提供的不一样。
1,修改/etc/inittab
将uclinux生成的ramdisk解压mount之后,假设mount在/tmp文件夹。删除系统原有的/tmp/etc/inittab,可以参考/home/linuxuser/snapgear/user/busybox/examples/inittab。这个文件的内容如下:
::sysinit:/etc/init.d/rcS
::askfirst:/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/sbin/swapoff-a
::shutdown:/bin/umount-a -r
::restart:/sbin/init
现在ramdisk里实际上没有/etc/init.d/rcS,用/etc/rc代替。同时修改inittab,将
::sysinit:/etc/init.d/rcS
修改为
::sysinit:/etc/rc
那么新的inittab内容如下:
::sysinit:/etc/rc
::askfirst:/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/sbin/swapoff-a
::shutdown:/bin/umount-a -r
::restart:/sbin/init
2. 修改/etc/rc文件
rc原文如下:
hostname IXDP425
mount -t proc proc /proc
mount -o remount,rw /dev/root /
ifconfig lo 127.0.0.1
#insmod ixp400.o
#cat /etc/IxNpeMicrocode.dat > /dev/ixNpe
#insmod ixp400_eth.o
#ifconfig ixp0 192.168.0.1 broadcast 192.168.0.255netmask 255.255.255.0
route add -net 127.0.0.0 netmask 255.255.255.0 lo
#dhcpcd &
cat /etc/motd
必须在文件开始加上#!/bin/sh,否则会报错:Could not run '/etc/rc': Exec format error
修改之后rc如下:
#!/bin/sh
hostname IXDP425
mount -t proc proc /proc
mount -o remount,rw /dev/root /
ifconfig lo 127.0.0.1
#insmod ixp400.o
#cat /etc/IxNpeMicrocode.dat > /dev/ixNpe
#insmod ixp400_eth.o
#ifconfig ixp0 192.168.0.1 broadcast 192.168.0.255netmask 255.255.255.0
route add -net 127.0.0.0 netmask 255.255.255.0 lo
#dhcpcd &
cat /etc/motd
将umountramdisk之后用gzip压缩,通zImage一起下载到板子上,这样系统就能顺利启动。
在uclinux中使用Cramfs
配置uclinux内核
2.6的配置和2.4的一模一样,只不过菜单的位置不同。可以通过打开linux2.4.x或者linux2.6.x下的.config文件搜索来快速确定这些选项在menuconfig中的位置。
选中选项
在MemoryTechnology Devices (MTD)选项中进行配置:
Memory Technology Device (MTD) support[Y/m/n/?]Y 内存技术设备支持
MTD partitioning support [Y/m/n/?] Y 支持MTD分区
Direct char device access to MTDdevices[Y/m/n/?] Y MTD字符设备直接访问
Caching block device access to MTDdevices[Y/m/n/?] Y MTD块设备缓冲访问
在File Systems选项中进行配置:
Compressed ROM file system support[Y/m/n/?] Y ROM文件系统的支持
修改kernnelcommand line为
console=ttyS1,115200 root=/dev/mtdblock2init=/linuxrc mem=64M@0x0
其中root=/dev/mtdblock2是指制作完成之后的cramfs烧录到flash的第二个分区上。如果是别的分区,需要相应修改。在redboot下查看分区可以使用fis list命令。按照起始地址的大小顺序数,mtdblock从0开始计数,通常redboot分区是mtdblock0。在当前的IXDP425板上,准备烧录的分区的起始位置第三大,所以应该是mtdblock2 。
完成上述修改并编译后,完成uCliunx内核对CramFS文件系统的支持。
Cramfs使用Busybox中的init
在实际的使用中cramfs也是经常采用的一种文件格式。相对特殊的地方是cramfs是只读的。而init的过程中使用的几个重要文件/etc/inittab, /etc/rc等必须在调用busybox linuxrc之前存在。如果存在,那么Cramfs的操作和ramdisk是一样。但是如果不是,则必须先利用里一个脚本准备。
假设有一个系统,因为只读文件的原因。etc只是一个链接到/var/etc,真正的内容是启动的时候复制/usr/etc到/var/etc,那么这个操作必须提前。
删除busybox生成的linuxrc,建立脚本如下。
#!/bin/sh
#
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export PATH
/bin/mount -n none /proc -t proc
/bin/mount -n tmpfs /var -t tmpfs-o size=18000000
/bin/mkdir -p /var/run /var/tmp/var/etc /var/log
/bin/mkdir -p /var/empty ##for sshd
cd /dev && /bin/tar cf /tmp/dev.tar .;cd /
/bin/mount -n tmpfs /dev -t tmpfs -osize=100000
cd /dev && /bin/tar xf /tmp/dev.tar&& rm -f /tmp/dev.tar; cd /
cp /usr/etc /var -rf
bin/busybox linuxrc
其中前面的步骤是挂载文件系统,准备好文件,其中准备etc的为下面几句
/bin/mount -n tmpfs /var -t tmpfs-o size=18000000
/bin/mkdir -p /var/run /var/tmp/var/etc /var/log
cp /usr/etc /var –rf
先挂载/var, 建立/var/etc,然后复制/usr/etc。这样,在根目录下的etc就能包含内容了。最后一句实际上就代替了busybox原来的linuxrc。如果想查看busybox的这种用法,可以在系统启动之后,输入busybox就可以。
# busybox
BusyBox v1.00(2009.04.15-07:30+0000) multi-call binary
Usage: busybox [function][arguments]...
or: [function] [arguments]...
BusyBox is a multi-call binary thatcombines many common Unix
utilities into a singleexecutable. Most people will create a
link to busybox for each function theywish to use, and BusyBox
will act like whatever it was invokedas.
Currently definedfunctions:
[, adjtimex, ar, basename, busybox,cat, chgrp, chmod, chown,
chroot, clear, cmp, cp, cut, date, dc,dd, df, dirname, dmesg,
du, echo, env, expr, false, find, free,freeramdisk, getopt, grep,
gunzip, gzip, halt, head, hostname, id,init, insmod, kill, killall,
klogd, length, linuxrc, ln, logger,logname, ls, lsmod, makedevs,
md5sum, mkdir, mknod, mktemp, modprobe,more, mount, mv, nc, nslookup,
pidof, printf, ps, pwd, rdate,readlink, reboot, renice, reset,
rm, rmdir, rmmod, sed, sleep, sort, stty,sync, syslogd, tail,
tar, tee, telnet, test, tftp, touch,tr, true, tty, umount, uname,
uniq, uptime, usleep, vi, wget, which,whoami, xargs, yes, zcat
制作ramfs
将根文件系统准备好之后,下载cramfs-1.1.tar.gz,在PC下编译。生成两个文件cramfsck和mkcramfs。
假设根文件系统的文件夹为cramroot.用以下命令制作cramfs映像。
Mkcramfs ./cramroot cram.img
得到cram.img,将其烧到板子上就行了。
摸索过程
启动kernel
按照文中的方法编译好内核之后,每次启动到kernel就没有任何信息。
RedBoot> exec
Using base address 0x01600000 and length 0x00100000
就没有反应了.
说明kernel根本没有起来。
使用console=ttyS1,115200root=/dev/ram0 initrd=0x00800000,8Mmem=64M@0x00000000就完全没有问题。
所以肯定是kernelcommand line出了问题。后来经过提示,发现
Console =ttyS1,115200 root=/dev/mtdblock2init=/linuxrc mem=64M@0x0
发现是console和等号之间的空格问题导致command line不能解析。
修改完可以打印许多kernel启动的信息,但是出现错误如下:
NET: Registered protocol family 17
Time: OSTS clocksource has been installed.
VFS: Mounted root (cramfs filesystem)readonly.
Freeing init memory: 108K
Warning: unable to open an initial console.
说明已经kernel正常启动, initial出了点问题.
一个问题: /dev/没有console这个文件。
#mknod -m 600 /dev/console c 5 1
#mknod -m 666 /dev/null c 1 3
检查dev的问题,发现G8000flashdisk文件夹下面有两个文件可以生成/dev下的节点,这就完全解释了dev的现象。
Fis可以放在boot script里面
因为测试cramfs,需要每次都重新烧flash。
Fis 可以放在boot script里面,并且没有覆盖提示
Enter script, terminate with empty line
>> load -r -v -b 0x0080000026cram.img
>> fis create -b 0x00800000 -l0x240000 -f 0x50180000 -e 0x00800000 -r 0x00800000 ramdisk
>> load -r -v -b 0x01600000 zImage
>> exec
>>
这样可以方便的调试cramfs.
Inittab的问题
经过以上的调试之后,可以看到kernel已经成功的执行linuxrc下的指令,但是始终不出现登录提示符。因为登录提示符在Inittab。如果在linuxrc里面加上/bin/sh,是可以出现提示符的,但是Inittab里面的syslogd等都不执行了。仔细检查Inittab,发现和网上讲解的格式不一样。这个是系统自带的Inittab,而不是busybox样本的。原文如下:
inet:unknown:/bin/inetd
boa:unknown:/bin/boa
slog:unknown:/sbin/syslogd -n
klog:unknown:/sbin/klogd -n
并没有4个部分如id,runlevel等。多次尝试使用uclinux自带的init始终无法成功。于是决定全部采用busybox的init方法。
查看busybox的Inittab样本说明如下:
# Format for each entry:<id>:<runlevels>:<action>:<process>
#
# <id>: WARNING: This field has anon-traditional meaning for BusyBox init!
#
# The id fieldis used by BusyBox init to specify the controlling tty for
# thespecified process to run on. Thecontents of this field are
# appended to"/dev/" and used as-is. Thereis no need for this field to
# be unique,although if it isn't you may have strange results. If this
# field isleft blank, it is completely ignored. Also note that if
# BusyBoxdetects that a serial console is in use, then all entries
# containingnon-empty id fields will _not_ be run. BusyBox init does
# nothing withutmp. We don't need no stinkin' utmp.
#
# <runlevels>: The runlevels field iscompletely ignored.
#
# <action>: Valid actions include: sysinit,respawn, askfirst, wait, once,
# restart,ctrlaltdel, and shutdown.
#
# Note:askfirst acts just like respawn, but before running the specified
# processit displays the line "Please press Enter to activate this
# console." and then waits for the user to press enter beforestarting
# thespecified process.
#
# Note:unrecognised actions (like initdefault) will cause init to emit
# anerror message, and then go along with its business.
#
# <process>: Specifies the process to beexecuted and it's command line.
尝试修改G8000
想让G8000使用ramdisk,修改完command line为如下
console=ttyS1,115200 root=/dev/ram0 init=/linuxrcmem=64M@0x0
启动发现如下错误
Bridge firewalling registered
802.1Q VLAN Support v1.8 Ben Greear<greearb@candelatech.com>
Other stuff added by David S. Miller<davem@redhat.com>
NetWinder Floating Point Emulator V0.97 (doubleprecision)
VFS: Cannot open root device "ram0" or01:00
Please append a correct "root=" boot option
Kernel panic: VFS: Unable to mount root fs on 01:00
还是启动失败。应该和kernel的支持有关。
configure kernel with
- ramdisk support
- ramdisk support as boot device
- extended fs 2 support
重新编译内核之后还是不行,但是错误信息已经变了。
cramfs: wrongmagic
Kernel panic:VFS: Unable to mount root fs on 01:00
也许是0x00800000的启动位置问题。
修改commandline为console=ttyS1,115200root=/dev/ram0 init=/linuxrc initrd=0x00800000 mem=64M@0x0 reboot=h
还是出现问题。
RAMDISK: Compressed image found at block 0
Freeing initrd memory: 8192K
VFS: Mounted root (ext2 filesystem) readonly.
Freeing init memory: 64K
attempt to access beyond end of device
01:00: rw=0, want=8297, limit=8291
EXT2-fs error (device ramdisk(1,0)): ext2_read_inode:unable to read inode block - inode=1602, block=8296
Warning: unable to open an initial console.
attempt to access beyond end of device
01:00: rw=0, want=8348, limit=8291
EXT2-fs error (device ramdisk(1,0)): ext2_read_inode:unable to read inode block - inode=2016, block=8347
attempt to access beyond end of device
01:00: rw=0, want=16388, limit=8291
EXT2-fs error (device ramdisk(1,0)): ext2_read_inode:unable to read inode block - inode=3201, block=16387
Kernel panic: No init found. Try passing init= option to kernel
这个似乎是说ramdisk超过的限度。
修改ramdisk size= 26624以及
console=ttyS1,115200 root=/dev/ram0initrd=0x00800000,26Mmem=64M@0x00000000
EXT2-fs error错误消失。说明确实是这个问题。
修改完之后还是有错误
VFS: Mounted root (ext2 filesystem) readonly.
Freeing init memory: 64K
Warning: unable to open an initial console.
Kernel panic: No init found. Try passing init= option to kernel.
那应该是init的位置不对。
网上找到的信息。
很显然是你的init不对,现在你的文件系统是被挂载上去了,因为z在kernel的source里面的init/main.c 里面的init函数调用了/sbin/init或者是/etc/init ,详细你可以看一下init/main.c,另外你要挂载ramdisk ,/dev/下只需要ram,ram0什么的就可以了。
不过到此为止,说明kernnel已经完全可以用了。剩下的的就是init之类的事情。