Linux CD-ROM Game System |
||
| YAMAMORI Takenori <yamamori@kt.rim.or.jp> | ||
The CD-ROM game system boots by using initrd skillfully as shown in the flow chart. So I explain a making method of initrd-game.img (an initrd for the game system) to the following.
In boot of the system, initrd-game is mounted as a temporary root filesystem first. In the inside of the initrd, there are very few commands including /bin/sh but even a ls command doesn't exist (using "echo *" command instead of ls is a usual practice). And then we must do a mount of CD-ROM under this environment, but there is no mount command in the initrd.
We cannot copy a mount command from a usual Linux system because the mount command is dynamically linked with libc that is too big to make a boot floppy disk.
So we make a special, simple, and statically linked mount command with C language as follows. I name it cdmount.c.
#include <sys/mount.h>
main(int argc, char **argv)
{
int data = 0;
return mount(argv[1], argv[2], argv[3], MS_RDONLY|MS_MGC_VAL, &data);
}
|
We must compile cdmount.c with the following option. It's a key to make a statically linked binary and to strip unnecessary symbol table.
gcc -O2 -static -s -o /tmp/cdmount cdmount.c
In cdmount.c, unnecessary processing is omitted entirely except that it returns a return value of whether mount() was successful.
Here, we can execute the following command for trial.
# /tmp/cdmount /dev/cdrom /mnt/cdrom iso9660
If a CD-ROM is mounted normally, it is OK.
In Linux, a shell script /sbin/mkinitrd to make initrd is prepared. This is a command needed by a system using a SCSI root filesystem to load a SCSI module in boot by an initrd.
The initrd is an ext2 filesystem image compressed by gzip, and it is read in boot.
We make initrd-game by using initrd which mkinitrd makes as a template.
The concrete procedure is the following:
(making a template of initrd) ---- # /sbin/mkinitrd -v -f /boot/initrd-game.img 2.2.14-1vl6 # zcat /boot/initrd-game.img > /tmp/initrd-game # Expand it with gzip and put it on tmp ----
(modifying initrd)
----
# mkdir /mnt/tmp
# mount -o loop /tmp/initrd-game /mnt/tmp # loop-back mount as ext2
# cd /mnt/tmp # go into the inside of initrd-game
# mkdir -p mnt/cdrom
# mv bin dev etc lib mnt/cdrom
# ln -s mnt/cdrom/* . # symbolic links for bin, dev, etc,lib,
# ln -s mnt/cdrom/usr mnt/cdrom/sbin mnt/cdrom/var mnt/cdrom/root .
# Note: each symbolic link destination doesn't exist now
# touch fastboot # avoid fsck in boot
# mkdir proc
# mkdir tmp
# chmod 1777 tmp
# cp -a /dev/hd[abcd]* /dev/scd0 /dev/sda* mnt/cdrom/dev
# cp -p /tmp/cdmount . # copy the cdmount we created
# vi linuxrc
# ... see below about linuxrc ...
# cd / # get out of initrd-game
# umount /mnt/tmp # umount the loop-back mount
# /sbin/losetup -d /dev/loop0
# losetup is needed because /etc/mtab has been modified
# gzip -9 < /tmp/initrd-game > /boot/initrd-game.img
# save it with gzip compressed
----
We add commands in linuxrc as follows. In linuxrc, there are a few lines described already by mkinitrd, but we just leave those.
#!/bin/sh # already described
echo "Loading aic7xxx module" # described for a SCSI system
insmod /lib/aic7xxx.o # described for a SCSI system
/cdmount /dev/hdc /mnt/cdrom iso9660 ||
/cdmount /dev/hdd /mnt/cdrom iso9660 ||
/cdmount /dev/hdb /mnt/cdrom iso9660 ||
/cdmount /dev/scd0 /mnt/cdrom iso9660 ||
(
echo 'cannot mount CD-ROM, invoke /bin/sh'
/bin/sh
)
mount -t proc none /proc
echo 0x100 > /proc/sys/kernel/real-root-dev
umount /proc
|
It's somewhat complexed, but you have to understand because it is a key of this system.
As a result, the directory tree of the inside of the initrd-game should be like the following:
/sbin -> mnt/cdrom/sbin
/bin -> mnt/cdrom/bin
/usr -> mnt/cdrom/usr
/lib -> mnt/cdrom/lib
/etc -> mnt/cdrom/etc
/var -> mnt/cdrom/var
/dev -> mnt/cdrom/dev
/root -> mnt/cdrom/root
/
/tmp/
/proc/
/
/linuxrc
/cdmount
/fastboot
/
/mnt/cdrom/bin/sh
/ /insmod
/
/lib/aic7xxx.o # a SCSI module (there is none in case of IDE)
/
/etc/
/dev/console
/null
/hdc
/scd0
/hda1
:
|
The directories like /bin made by mkinitrd are moved under /mnt/cdrom with symbolic links. Under /mnt/cdrom, there are minimum files that are needed even before mounting the CD-ROM. For example, the substance of /bin/sh exists in /mnt/cdrom/bin/sh.
In linuxrc, the cdmount command that we have made is executed, and CD-ROM is mounted. You will see that cdmount is executed a few times with changing a CD-ROM device in order of /dev/hdc,hdd,hdb,scd0. A shell systax "||" is used here. In other words, it tries to mount IDE or SCSI CD-ROM with each possible device file until an error code does not return. It is this purpose that we have made cdmount so as to return a return value of mount().
CD-ROM is mounted to cover whole /mnt/cdrom directory. Then each directory like /bin, /dev under /mnt/cdrom gets unable to be seen and each /bin, /dev on the CD-ROM can be seen instead of it.
By the way, if it cannot mount CD-ROM from every device,
it invokes a shell with a message:
'cannot mount CD-ROM, invoke /bin/sh'
We can use this shell for testing with a hard drive before
creating a CD-ROM.
After a mount of CD-ROM, linuxrc mounts a /proc filesystem by using a genuine mount command that is in the CD-ROM. And it writes 0x100, which is a device number of initrd, into real-root-dev in /proc so as to specify the initrd itself as a real root filesystem.
In addition, you will see that an empty file /fastboot is created in the inside of the initrd to prevent fsck in boot. If you forget it, the system won't start when it boots with just a CD-ROM because fsck complains about a hard drive corresponding to an old description of /etc/fstab.
When the modification of the initrd-game is finished, after unmounting it we compress the initrd with gzip and save it as /boot/initrd-game.img.
Now, there should be a complete initrd-game.img. At first, we test the initrd-game.img for booting with LILO on a hard drive.
Here, /etc/lilo.conf on a hard drive may be as follows:
boot=/dev/hda
map=/boot/map
install=/boot/boot.b
prompt
timeout=50
append="apm=on"
default=linux
image=/boot/vmlinuz-2.2.14-1vl6
label=linux
read-only
root=/dev/hda1
|
We add the following description next to the above:
image=/boot/vmlinuz-2.2.14-1vl6
label=game
initrd=/boot/initrd-game.img
root=0x101 # This must not be root=0x100, but actual value is ignored
|
Then we install the LILO.
# /sbin/lilo Added linux * Added game
By this state, we have a booting test with a hard drive. We don't insert any CD-ROM now.
Rebooting the machine, we type game just after the prompt of "LILO boot:". Then, after loading vmlinuz and initrd, a shell will be invoked from the linuxrc in the initrd-game as a result that it couldn't mount any CD-ROM. So we mount a hard drive by the cdmount command as follows:
# /cdmount /dev/hda1 /mnt/cdrom ext2
=========
|
+--- change it with your actual hard drive partition.
Mounting the hard drive as read-only, we check that it can be a CD-ROM.
After executing the cdmount command, usual UNIX commands like ls should be available.
Exiting the shell, linuxrc is finished and /sbin/init gains control and the system starts. And the game should start as before.