You need to have a few tools installed, specifically a cross compiler, QEMU, and GRUB. You'll also need Flex, Bison, make, and OpenSSL. To install a cross compiler, go to https://wiki.osdev.org/GCC_Cross-Compiler#External_Links and download one for the target i686-elf. I recommend installing into a directory such as /usr/cross and adding those paths to the PATH variable. You'll also need to create some symlinks:
ln -sf /usr/cross/bin/i686-elf-gcc /usr/cross/bin/x86-gcc # or wherever the cross compiler is
ln -sf /usr/cross/bin/i686-elf-as /usr/cross/bin/x86-as
ln -sf /usr/cross/bin/i686-elf-ld /usr/cross/bin/x86-ld
First, we need to build the Linux kernel from source. You could just use /boot/vmlinuz but I will show you how to build it from source so that we have full control over the build. First, download it, and extract the tarball:
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.7.tar.xz
tar -xf linux-5.10.7.tar.xz
cd linux-5.10.7
Now we need to create the configuration for the i386 architecture:
make ARCH=x86- i386_defconfig
And now, we build the compressed linux kernel:
make bzImage
Now, wait for it to finish building. Once it's finished building, copy the resulting kernel:
cp arch/i386/boot/bzImage ../vmlinuz
And exit the directory:
cd ..
You can test the kernel with:
qemu-system-i386 -kernel vmlinuz
The kernel will print a lot of messages, then it'll panic about not being able to find a VFS. This is because we haven't created a initial ramdisk yet!
Creating the initial RAM filesystem
When a linux computer boots, a bootloader loads a linux kernel, and something which is known as an initial ramdisk. The initial ramdisk usually contains a filesystem. The Linux kernel tries to run the init script in that filesystem /init, and when it fails, it panics.
We could theoretically compile glibc and every GNU coreutils. But for simplicity, we'll use busybox, which puts many of these programs into one executable. We can download a busybox binary with:
We need to create the /init script, which is the executable that will be run on startup. Put this into ./initramfs/init. I'll explain every part of this in the comments:
#!/bin/sh
/bin/busybox --install -s # tell busybox to install itself with symlinks
# mount system directories
mount -t proc proc /proc
mount -t sys /sys
# disable kernel messages
echo 0 > /proc/sys/kernel/printk
# create device nodes
mknod -m 666 /dev/null c 1 3
mknod -m 666 /dev/tty c 5 0
mdev -s
# clear the screen
clear
# run the shell with cttyhack (see https://busybox.net/FAQ.html#job_control)
setsid cttyhack sh
Now we need to create the cpio archive and gzip it (credits go to this tutorial):
This is great, but how do we run this on real hardware? The answer is that we need to create a CD image. We can use grub-mkrescue for this. First, create the CD root directory:
mkdir -p iso_dir/boot/grub
Then, we need to create a grub configuration. Put this into ./iso_dir/boot/grub/grub.cfg
menuentry "My Linux Distro" {
linux /boot/vmlinuz
initrd /boot/initramfs.gz
}
Now copy the files into the ./iso_dir/boot directory:
Creating a Simple Linux System
Prerequisites
You need to have a few tools installed, specifically a cross compiler, QEMU, and GRUB. You'll also need Flex, Bison,
make
, and OpenSSL.To install a cross compiler, go to https://wiki.osdev.org/GCC_Cross-Compiler#External_Links and download one for the target
i686-elf
.I recommend installing into a directory such as
/usr/cross
and adding those paths to thePATH
variable.You'll also need to create some symlinks:
To install the other packages on Arch Linux:
For Ubuntu or Debian:
For Fedora:
( @firefish help)
Building the Linux kernel from source
First, we need to build the Linux kernel from source. You could just use
/boot/vmlinuz
but I will show you how to build it from source so that we have full control over the build.First, download it, and extract the tarball:
Now we need to create the configuration for the
i386
architecture:And now, we build the compressed linux kernel:
Now, wait for it to finish building.
Once it's finished building, copy the resulting kernel:
And exit the directory:
You can test the kernel with:
The kernel will print a lot of messages, then it'll panic about not being able to find a VFS. This is because we haven't created a initial ramdisk yet!
Creating the initial RAM filesystem
When a linux computer boots, a bootloader loads a linux kernel, and something which is known as an initial ramdisk. The initial ramdisk usually contains a filesystem. The Linux kernel tries to run the init script in that filesystem
/init
, and when it fails, it panics.Creating the filesystem hiearchy
First, we need to create the filesystem hiearchy:
Using busybox
We could theoretically compile glibc and every GNU coreutils. But for simplicity, we'll use busybox, which puts many of these programs into one executable.
We can download a busybox binary with:
And to create a symlink to busybox for the shell:
Creating the init script
We need to create the
/init
script, which is the executable that will be run on startup.Put this into
./initramfs/init
. I'll explain every part of this in the comments:Now we need to create the cpio archive and gzip it (credits go to this tutorial):
Finally, we can test this in QEMU with:
You should be dropped into an interactive shell!
Creating a CD image
This is great, but how do we run this on real hardware? The answer is that we need to create a CD image.
We can use
grub-mkrescue
for this.First, create the CD root directory:
Then, we need to create a grub configuration. Put this into
./iso_dir/boot/grub/grub.cfg
Now copy the files into the
./iso_dir/boot
directory:And create the CD image:
To test this in QEMU:
And you're done!
pog