OS Lab 1 - Linux And Hello World

11 minute read

The first lab of the Operating System course in USTC. This passage also serves as the lab report.

0. Contents

  1. Compile Linux Kernel, use the kernel and qemu to start busybox
  2. Build grub bootable disk
  3. Run Linux Kernel Using grub
  4. Use gdb and qemu to debug Linux Kernel

1. Part 1: Run Hello World

1.1 Compile Linux Kernel

First of all, we need tools to build Linux Kernel:

yay -S base-devel

Then, we need to download the Linux Kernel source code from kernel.org:

git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

Note: You may need to use proxychains connect through proxy (in China)

When you’ve finished the download, we can start to config the kernel.

cd linux                        # if not currently in the kernel source tree
make i386_defconfig             # Use the default i386 kernel config which is 32 bit
make                            # Build the kernel

The kernel image is in $(KERNEL_SOURCE)/arch/i386/boot/bzImage

Note 1: The kernel is a 32-bit kernel which does NOT support 64 bit binaries!

Note 2: The default config may cause errors, refer to Trouble Shooting Guide to find how to solve them.

1.2 Build a Hello World Program

Write a C program to print “Hello, World!”

#include <stdio.h>

int main(void) {
    while(1) {
        printf("Hello, World!\n");

Note: You can try another version of “Hello, World” which does not contain a infinite loop.

Compile the program using the command:

gcc -static -o init hello.c -m32

# We need a 32-bit init as the kernel is 32 bit.
# The program should be statically linked
# The program is called init

1.3 Build a rootfs

We are going to build a rootfs which contains an init file which will be executed by kernel.

First, use command dd to build a small image file:

dd if=/dev/zero of=myinitrdLarge.img bs=4096 count=1024

Note: The image file we create is 4M large named myinitrdLarge.img

Then mount the image file:

mkdir rootfs                                    # mount point
mount -o loop myinitrdLarge.img rootfs

Copy the init file we build in 1.2 into rootfs:

sudo cp init rootfs/

Then we are going to add some devices to the rootfs (No idea if it is actually needed).

sudo mkdir -p rootfs/dev
sudo mknod rootfs/dev/ram0 b 1 0
sudo mknod rootfs/dev/console c 5 1

1.4 Try to run the Hello World

OK, we are now at the final step of part 1! In Arch Linux, we are going to use qemu-system-i386. Try the following command:

qemu-system-x86_64 -kernel $(KERNEL_SOURCE)/arch/i386/boot/bzImage -initrd myinitrdLarge.img -append "console=ttyS0 root=/dev/ram0 rw init=/init debug" -serial stdio

Note: This command will try to redirect the output to the terminal so that if you have kernel panic, you can check the full debug info.

If ok, the output will be a lot of Hello World!.

If you encounter KERNEL PANIC, I do have some solutions to some of the KERNEL PANICs. See Troubleshooting in the final part.

1.5 Behind the scene

When Linux starts up, it mounts initrd into /dev/initrd, but it will soon free the space and use /dev/ram* instead.

So the myinitrdLarge.img will serve as the initrd file and will be finally mounted to /dev/ram0 (if kernel is configged correctly)

So the image will be shown as /dev/ram0, and we set it as root. So the kernel will mount the /dev/ram0 as root. Then the kernel will search for init in the many places (if not spacified). In our case, we set the init path to /init, telling the kernel the init path is /init, so the kernel will execute /init, which is the helloworld program.

Leave a comment