QUICKSTART: Run "make" to get a kernel image file "Image". This file is in fact a bootable floppy image. The other file hd_oldlinux.img is the root device (/) hardcoded at IDE0-master. ABOUT IDE/ATA: See http://www.osdev.org/wiki/ATA, the oldlinux book, and linux/Documentation/ide.txt for programming info. Basically, 0x1f0-0x1f7 (see include/linux/hdreg.h) is reserved for the ATA0 channel. On one channel, two devices (primary/secondary, or master/slave) can be connected. Both devices are controlled the same way, except for when data is transferred. When transferring data, there's one bit to select the device. (0xA0 or 0xB0, see hd_out) There's one bug in the function controller_ready. When the computer first starts up, 0 is a good status value, but Linus only assumed 0x50. To test if the controller is ready, we only need to test the READY bit (the highest bit). A value of 0xff indicates a disabled channel. HOWTO mount the images under modern linux: 1. If you ever tried "mount -t minix Image /mnt -o loop", you'll get a FS type error. The failed command also wastes a loop device /dev/loopN, until you release it by "losetup -d". You may use "losetup -a" to see all the loop devices used. 2. Image cannot be mounted because it's a raw floppy image. hd_oldlinux.img cannot be mounted because it's a virtual disk containing partitions. To mount the partitions in the disk, we must retrieve them from the virtual disk. 3. First we mount the whole disk to read its partition table: losetup /dev/loop0 hd_oldlinux.img fdisk -lu /dev/loop0 Suppose it starts at sector 20 (1 sector has 512 bytes). 4. Now we can mount the specific partition with the right offset: losetup -d /dev/loop0 losetup -o 10240 /dev/loop0 hd_oldlinux.img mount /dev/loop0 /mnt/ That's it! HOWTO compile userland programs 1. The provider of the patched kernel did a great job of supporting ELF (but a.out support is dropped!), see fs/exec.c 2. You have to use the headers and lib provided by linux-0.01: gcc -Wl,-Ttext,0x100 -nostdinc -nostdlib -e main -static a.c lib/lib.a -I include/ -o a 3. Since now the entry point is plain main(), you shouldn't let it return! Instead you need to call _exit() explicitly. Here is a sample program: int main() { _exit(0); } 4. "-Wl,-Ttext,0x100" tells the linker to load the .text section at 0x100. The default address on a modern system is above 0x08000000, beyond the address space supported on Linux-0.01. Therefore, bochs throws out a "write beyond limit" error, and causes Linux to trap the error in general_protection. (The control flow of loading an ELF binary is do_execve -> load_elf_binary -> copy_section -> cp_block, all in fs/exec.c). Interestingly, an ELF with a modern layout runs fine under qemu, is it because that qemu wraps the out-of-bound addresses? Debugging tips: main() starts with a "lea ..." instruction, and we cannot break at that address. However, we can set a breakpoint at the third instruction ("push ..."). CHANGES: 1. Made a bochsrc file to enable debugging w/ bochs, coz qemu doesn't have strong debugging support. For the disk's parameters, refer to draconux's page on how the disk was created. 2. Changed the Makefiles to add debugging symbols. Removed "-fomit-frame-pointer". Removed "-O" in lib/ and mm/ Dropping "-O" in kernel/ causes insufficient registers for inline assembly. Dropping "-O" in fs/ causes extern functions defined in .h not inlined in .c and thus link errors, Dropping "-O" in / causes the fork() call not inlined and so process 0 corrupts the stack of process 1. This corruption somehow make process 0 (the idle process) always get scheduled, resulting in an infinite loop. (Also see the comment in init/main.c) 3. Created a patch "gdbstub.cc.patch" against bochs (version CVS 20080110) Bochs always tries to find out the reason of an exception, so that it can generate the right signal for gdb. If it fails to find a reason, bochs assigns a value GDBSTUB_STOP_NO_REASON (see bochs.h), which causes debug_loop() (see gdbstub.cc) to generate a signal of number 0. Signal 0 is problematic to gdb, as gdb doesn't allow us to ignore it. Somehow when we simulate linux, we get tons of signal 0's that seem to be caused by page faults. This patch makes bochs send SIGSEGV instead of signal 0, so that we can ignore it in gdb. 4. Created a .gdbinit file for the regular setup. 5. Changed the init/main.c so that process 1 (init) never exits. Instead it does a while loop and spawns a new child. 6. Fixed the strange behavior of hitting one symbol key but getting a different symbol (on a US keyboard): It's because Linus was programming on a Finnish keyboard (http://www.kernel.org/pub/linux/kernel/Historic/old-versions/RELNOTES-0.01). The change made to kernel/keyboard.s was based on /path_to_linux_0.11/kernel/chr_drv/keyboard.S (basically in the tables *_map). 7. Fixed a bug in the ELF loader, in particular the cp_block function in fs/exec.c The kernel reads the contents of the sections into memory, and then copies them to the user space at the right addresses. Copying is done wordwise, and may truncate the last few unaligned bytes. The fix is quick and dirty, and therefore may break some programs. See the comment in the file. NOTE that the sections are loaded at once; demand paging is not implemented to save memory. If you want demand paging, get linux-0.11. REFERNCES: [Linux-0.01] http://draconux.free.fr/os_dev/linux0.01.html http://kerneltrap.org/Linux/Dusting_Off_the_0.01_Kernel http://draconux.free.fr/download/os-dev/linux0.01/doc/LINUX_0.01_GCC_4.x http://draconux.free.fr/download/os-dev/linux0.01/doc/LINUX_0.01_GCC_1.40 [Using bochs] http://bochs.sourceforge.net/doc/docbook/user/internal-debugger.html http://bochs.sourceforge.net/doc/docbook/user/debugging-with-gdb.html [Understanding linux-0.11] http://oldlinux.org/index_cn.html [Tracking history] http://www.kernel.org/pub/linux/kernel/Historic/old-versions/