Linux CD-ROM Game System |
||
YAMAMORI Takenori <yamamori> |
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.