从发行版定制可以从USB移动硬盘上引导的Portable Linux (再次修正版)

这个过程我自己做了好几次了,原先用的Redhat 9.0 也换成了现在在用的FC 5。相应的内核也从2.4.20换成了现在用的2.6.21。

中间借用的工具也从开始用的VMWare换成了现在的qemu。

当然,不排除有优良的发行版本和更新的内核源码和工具可以不再用自己DIY,以下只是讲讲我自己动手的经历:

首先,要有一个可分区安装linux的USB移动硬盘,理论上FLASH U盘也可以,SD/XD等闪存卡+读卡器也可以,不过FLASH芯片的速度相对还是慢了些,实用程度远没有用移动硬盘高。这里还要提到移动硬盘最好是支持USB 2.0的,用的主板最好也如此,USB1.0和1.1的速度上,实用程度也很低。理论上用IEEE 1394火线接口的移动硬盘更快,只是我没有条件试过。

再首先,移动硬盘的USB/IDE转换板也有点讲究,我先后试过的几种移动硬盘转接板中,以那种标有IBM的小板子的移动硬盘盒最差,就算是在Windows下,也经常有硬盘离线的情况发生,一般用那种整块垫着硬盘的底板的移动硬盘盒不错,最好就是单口就能供电启动。

其次,准备一套发行版的Linux安装光盘,当然,ISO文件也成,这里假设的当然是我们从Windows环境下开始,如果当前用的是linux,可能还不用那么麻烦。

第三、准备一套可用的虚拟机环境,如果不在乎盗版或是你己经为之合法地付费,那么首选VMWare,这几乎是X86平台下虚拟X86平台的性能取好的虚拟机软件了,虚拟速度几乎达到1:1,如果一定要合法地使用软件,那么就用qemu吧,去哪里下载,请自己找。

第四、把移动硬盘连接到Windows 宿主机上来,正确地认出来,这里假设当前宿主机只有一块内部硬盘,移动硬盘是唯一连接的一个移动存储设备。正确地配置虚拟机,把移动硬盘(在Windows下,第二块硬盘的设备文件是//./PhysicalDrive1)完全交给虚拟机作为主要硬盘,VMWare下,通过向导你可以建立一个vmdk文件,但是仅仅是指明,这个虚拟硬盘就是宿主机上的移动硬盘,这都可以在GUI下实现。在Qemu下,指明将移动硬盘作为虚拟机的命令是:

qemu.exe -boot d -L . -m 256 -hda //./PhysicalDrive1 -cdrom d:/CDIMGS/FC-i386-CD1.ISO -localtime

这里我不想太多去讨论虚拟机的使用,否则就变成虚拟机操作的经验之谈了,这里最后只提一个小提示,使用qemu的话,安装kqemu可以得到相当程度的性能提高。

总而言之,我们建立一台使用USB硬盘作为主硬盘的虚拟机,并从光盘上引导或是从光盘镜像文件上引导它,顺利地安装了一套运行在虚拟机上的发行版本的Linux,这里又仅以FC 5 Linux为实例了,其实发行版本其实也大同小异。

第五、确保安装后运行在虚拟机中的Linux系统有完整的内核开发环境和内核源代码。这里又要扯到虚拟机的使用上去了,不管用什么办法,可能你需要安装开发环境、下载内核源代码的最近版本,可以正确地配置虚拟机直接上网下载、也可能利用宿主机下载后用FTP、Samba共享的办法甚至做成光盘镜像来让虚拟机终于可以配置和编译内核。

第六、开始配置新的内核,其中,重要的是要让这个内核支持USB移动存储驱动,而且还不能是内置在内核中,而是编译成内核驱动模块,由于存储驱动模块化,而又是引导时段需要的,因此,这个内核还必须支持引导过程的内存镜像盘(initrd)。于是,需要配置的内核部分包括:

至少必须的文件系统支持:ext3、ext2,反正都有initrd了,就配成模块方式。
至少必须支持的SCSI驱动:scsi、scsi-sd,这两个被VMWare 的虚拟Buslogic SCSI控制器和USB Storage驱动所依赖,配置成模块方式:
到少必须支持的USB驱动:usb支持、usb-storage即usb存储驱动。还有必须的uhci_hcd(基于intel系列芯片及VIA系列的的USB 1.0/1.1总线控制器)、ohci_hcd(基于AMD、nForce、ALI等兼容芯片的USB 1.0/1.1总线控制器)、ehci_hcd(扩展的USB 2.0总线控制器)。都配置模块方式。
至少必须支持的块设备:LoopBack Device Support,模块方式/内核方式都可以,2.4版本的内核使用Loop设备的方式来存放initrd镜像。 Ram disk支持,这个是必须,并且要编译在内核里。还有最重要的是Initrd的支持,需要编译到内核中,2.6的内核配置中,intitrd - Initial RAM filesystem and RAM disk (initramfs/initrd) support放在内核的General setup之下。

其它的部分,都可以按需定制。配置了内核之后,不外就是编译内核与内核模块、安装复制内核模块、安装新的内核。这些和通常的定制linux内核大同小异。把新的内核安装到当前系统上,并且加入到GRUB的选项中(这里又是假设了,假设当前使用的是GRUB作为Boot loader,至于LILO、syslinux这些,也是大同小异)。

中间提到一个有用的工具:BusyBox,如果有整个定制过程中出现麻烦,反复地修正和重启是个麻烦事,而把Bash整到启动过程中,依赖的各种库文件很是占用空间,先在虚拟系统内下载一个BusyBox编译安装绝对有益于后面定制过程中的手工调试。

当然,对于最终结果来说,BusyBox不是必须的。

到这里,虚拟机里己经安装了一个新的内核,如果你愿意,不妨用它在虚拟机里引导一下,看看它是否工作良好。

第七才开始进入正题,动手对付这个新内核的initrd镜像,让它能正确地联接在主机上从USB盘上启动起来,而不是在虚拟机里启动。先把/boot/initrd-2.6.21.img 复制到你的工作目录下来,并把它更名成.gz文件,解开到一个定制的目录中,这里我是这么做的:

#cd
(原来这里写错成3cp了,打上去的时候没按shift,请各位转载的哥们自己改吧)
#cp /boot/initrd-2.6.21.1.img hd.gz
#mkdir newinitrd
#gunzip hd.gz
#cd newinitrd
#cpio -i --make-directories < ../hd

这个时候,newinitrd目录下就是整个initrd文件内被打包压缩了的文件。
这里扯一下:发行版内的mkinitrd工具,来自于mkinitrd软件包,你可以用mkinitrd --version查一下,编译核心的最后一步make install这个过程的最后一步就是mkinitrd,这是一个shell脚本,有耐心和兴趣的可以仔细读一下,在我用的5.0.32版本的mkinitrd工具中,linux的开发者也己经试图加入了生成从usb盘引导linux的功能,只可惜,似乎生成的initrd并不能正常从USB移动硬盘上引导,最后还是得我们自己定制。

第八:把需要用的内核模块从/lib/modules/当前版本/kernel/drivers....等目录中复制到当前initrd解开后的目录的lib目录下。在这之前,先看看里面有什么,不同的情况下,还是有一些差别的。
接着上面的shell环境:
#cd lib
#ls -l
-rw-r--r-- 1 root root  69348 07-24 05:13 BusLogic.ko
-rw-r--r-- 1 root root 144796 07-24 05:13 ext3.ko
-rw-r--r-- 1 root root  75736 07-24 05:13 jbd.ko
-rw-r--r-- 1 root root  24564 07-24 05:13 ub.ko
-rw-r--r-- 1 root root 148040 07-24 05:13 usbcore.ko
-rw-r--r-- 1 root root 102960 07-24 05:13 usb-storage.ko
哦?己经帮我把usb等模块都复制上去了,还带了一个BusLogic的SCSI驱动。仔细比较这些ko文件,有不少还是被strip过的,比/lib/modules下的缩水小了很多。但是......
少了总线驱动,它以为我把usb总线控制器编译到内核中了?没办法,这里只好老老实实地先把总线驱动文件先复制过来。
接着上面的shell环境:
#cp /lib/modules/2.6.21.1/kernel/drivers/usb/host/ehci-hcd.ko .
#cp /lib/modules/2.6.21.1/kernel/drivers/usb/host/uhci-hcd.ko .
它们可以去掉内部的一些符号以缩小体积:
#strip ehci-hcd.ko
#strip uhci-hcd.ko
还少了必须的scsi disk 支持模块:
#cp /lib/modules/2.6.21.1/kernel/drivers/scsi/sd_mod.ko .
这个不就必strip了,似乎strip它的话,会加载不上。

除此之外,我们还得准备一个sleep,取代linux引导时用的nash中的sleep内部命令,那个不能有效地进行延时,于是到再到bin目录下:
这里还是得保留在我们的newinitrd目录下:
#cd ../bin
#cp /bin/sleep .
除此之外,还得也准备好sleep所依赖的库文件:
#ldd ./sleep
        linux-gate.so.1 =>  (0xffffe000)
        libc.so.6 => /lib/libc.so.6 (0x00c44000)
        /lib/ld-linux.so.2 (0x003b7000)
它需要lib目录下要有libc.so.6和ld-linux.so.2,找到它们,复制到lib目录下
#cd ../lib
#cp /lib/ld-linux.so.2 .
#cp /lib/libc.so.6 .
到这里,必须的文件就准备好了。

以上也有补充:sleep也可以由BusyBox取代,虽说下载一个BusyBox再编译多一些功夫,可是我还是很开心地编译了BusyBox并把它复制到newinitrd 的 bin目录下,并给它建了几个有用的链接,以下是用BusyBox的可选过程,就不用上面的sleep了:

(先进到newinitrd/bin下)
//#cp /root/busybox-1.6.0/busybox . (这里是我下载的busybux,并编译了支持ash,一个小型的shell)

修正上面这行:打错了,应该是
#cp /root/busybox-1.6.0/busybox . (这里是我下载的busyb ox,并编译了支持ash,一个小型的shell)

#ln -s busybox ash
#ln -s busybox sleep
可以试一下整个newinitrd目录作为根的效果了:
#cd (回到用户目录下)
#chroot newinitrd /bin/ash

BusyBox v1.6.0 (2007-06-12 22:55:20 CST) Built-in shell (ash)
Enter 'help' for a list of built-in commands.

# exit
退出回到原来的bash和原来的根上面。(busybox同样依赖于ld-linux.so.2和libc.so.6,请参考上面的方法把依赖的库文件复制到lib目录下)

第九:修改newinitrd目录下的init脚本,让它启动运行时正确依次加载文件系统支持模块、scsi支持模块、scsi-disk支持模块、usb支持模块、usb-storage支持模块、USB1.0/1.1总线驱动、USB2.0总线驱动,并在总线驱动的加载之间延时等待设备连入总线、发现与就序。由于usb驱动需要使用proc文件系统,还要确保先向根挂载了proc文件系统。

#cd ..(回到newinitrd目录下)
#vi init 开始修改:
以下是我的init文件,请不要直抄而是按你的init的当前情况修改:

#!/bin/nash

mount -t proc /proc /proc   (这里是第一个关键,有可能有些版本的mkinitrd会把这个mount放在后面,这样usb模块的加载有可能就不能正常工作)
setquiet
echo Mounting proc filesystem
echo Mounting sysfs filesystem
mount -t sysfs /sys /sys
echo Creating /dev
mount -o mode=0755 -t tmpfs /dev /dev
mkdir /dev/pts
mount -t devpts -o gid=5,mode=620 /dev/pts /dev/pts
mkdir /dev/shm
mkdir /dev/mapper
echo Creating initial device nodes
mknod /dev/null c 1 3
mknod /dev/zero c 1 5
mknod /dev/systty c 4 0
mknod /dev/tty c 5 0
mknod /dev/console c 5 1
mknod /dev/ptmx c 5 2
mknod /dev/rtc c 10 135
mknod /dev/tty0 c 4 0
mknod /dev/tty1 c 4 1
mknod /dev/tty2 c 4 2
mknod /dev/tty3 c 4 3
mknod /dev/tty4 c 4 4
mknod /dev/tty5 c 4 5
mknod /dev/tty6 c 4 6
mknod /dev/tty7 c 4 7
mknod /dev/tty8 c 4 8
mknod /dev/tty9 c 4 9
mknod /dev/tty10 c 4 10
mknod /dev/tty11 c 4 11
mknod /dev/tty12 c 4 12
mknod /dev/ttyS0 c 4 64
mknod /dev/ttyS1 c 4 65
mknod /dev/ttyS2 c 4 66
mknod /dev/ttyS3 c 4 67
echo Setting up hotplug.
hotplug
echo Creating block device nodes.
mkblkdevs
echo "Loading jbd.ko module"   (从这里开始,依次先加载jdb和ext3,文件系统支持)
insmod /lib/jbd.ko
echo "Loading ext3.ko module"
insmod /lib/ext3.ko
echo "Loading scsi_mod.ko module" (再加载scsi支持,其实前面我漏了一个,scsi_mod.ko的复制,要真完只是抄,估计不一定能做成功)
insmod /lib/scsi_mod.ko
echo "Loading sd_mod.ko module"
insmod /lib/sd_mod.ko
echo "Loading BusLogic.ko module" (这是VMWare虚拟机要用的BusLogic驱动,如果不是为了同一个内核也启动在VMWare里,那这个删了或没有或省去都不重要)
insmod /lib/BusLogic.ko
insmod /lib/usbcore.ko   (从这里依次加载usb核心模块、1.1总线支持、2.0总线支持、最后加载usb-storage)
echo "Loading USB 1.1 Host Driver"
insmod /lib/uhci-hcd.ko
echo "Waiting for Device Ready"
echo "Loading USB 2.0 Host Driver"
insmod /lib/ehci-hcd.ko
echo "Waiting for Device Ready"
echo "Loading USB-Storage Driver"
insmod /lib/usb-storage.ko
(关键在这里,加载完usb-storage后不能马上继续引导,要等数秒钟让设备就序)
sleep 10
insmod /lib/ub.ko
(我这里是启动了一个ash来等着调试,实际使用完全不需要)
busybox ash
mkblkdevs
resume LABEL=SWAP-sda6
echo Creating root device.
mkrootdev -t ext3 -o defaults,ro sda5
echo Mounting root filesystem.
mount /sysroot
echo Setting up other filesystems.
setuproot
echo Switching to new root and running init.
switchroot

这里是2.6核心的,相对来说,2.6带的usb驱动适应能力也比2.4的强了一些,在2.4版下,我试过需要先加载usbcore,再加载usb-storage(己经支持存储设备而没有发现设备),再加载uhci-hcd,让设备进入1.0总线,并等待10秒,再加载ehci-hcd,让设备离开1.0总线进入2.0总线,并等待10秒,最后才加载scsi-sd,得到scsi硬盘设备,还得再用sfdisk -R /dev/sda强制重新读取硬盘分区。

第十步也是最后一步,把整个newinitrd目录重新新成initrd.img文件并放回boot目录下,向grub.conf增加一个2.6.21从usb引导的选择项。并重启测试其正常情况:

保持在newinitrd目录下:
#findall . | cpio --quiet -c -o > ../usbboot
#cd ..
#gzip -9 usbboot
#cp usbboot.gz /boot/initrd-2.6.21.1-usb.img

这个时候,/boot下就有一个可用于从USB硬盘上引导的initrd镜像了。
最后就是修改grub.conf了:
cat /etc/grub.conf
title Fedora Core (2.6.21.1)
        root (hd0,0)
        kernel /vmlinuz-2.6.21.1 ro root=LABEL=/
        initrd /initrd-2.6.21.1.img
title Fedora Core USB Boot(2.6.21.1)
        root (hd0,0)
        kernel /vmlinuz-2.6.21.1 ro root=LABEL=/
        initrd /initrd-2.6.21.1-usb.img
我只是复制了原来的一个引导项,相应地把initrd这一行改成了新的文件名,把title加上了USB Boot字样,其它的原样照搬。

到这里就可以shutdown虚拟机里的操作系统,关闭虚拟机,重启电脑,选择从移动硬盘上启动,顺利的话,你的移动硬盘上的linux就引导起来了。


后话:
其实我认为完全可以通过修补mkinitrd就能做直接编译完内核后make install生成支持从USB移动硬盘上引导的内核来,估计已经有linux爱好者和开发者完成了这项工作,不过玩和用linux的其中一个乐趣就是通过动手来了解系统的原理,因此我也没有动手去改mkinitrd。

如果成功地从移动硬盘上引导了Linux后,再装上VMWare For Linux或是再用qemu,又可以从虚拟机里引导出宿主机盘上的windws来了,只不过,我的本本上装的是OEM版的XP,引导后由于硬件环境改变,该死的M$要求我激活它(想想我也没有违反最终用户许可协议吧,在不同时使用的情况下有权在另一台机器上安装同样的副本以作备用,而且....我用的是同一台机器呀。)怀念使用盗版Windows 2K的时候。

在Linux下的虚拟机中引导出原来宿主机上的Windows来的时候,这样的系统,什么时候谁是谁的宿主,谁是谁的寄生虚拟?

你可能感兴趣的:(vmware,windows,linux,虚拟机,shell,Module)