Skip to content

Latest commit

 

History

History
288 lines (205 loc) · 7.8 KB

building.rst

File metadata and controls

288 lines (205 loc) · 7.8 KB

Building yggdrasil

Building yggdrasil is pretty straightforward and similar to how you build a Linux distribution. To build a full OS, you'll need:

  1. GCC and binutils toolchain.
  2. The kernel itself.
  3. C library (newlib at the moment of writing).
  4. A set of userspace applications (at least some kind of /init).

1. Preparation

Build dependencies:

  • GNU binutils and gcc (for host programs), any non-ancient version should suffice, I guess.
  • git
  • make
  • autotools (autoconf + automake)

Optional: * sphinx (for building HTML documentation)

Get the kernel sources:

git clone https://git.alnyan.me/yggdrasil/kernel
cd yggdrasil
# This is recommended
git checkout dev

Get the userspace sources:

git clone https://git.alnyan.me/yggdrasil/userspace
cd ygg-userspace
# This is recommended
git checkout dev

Get GNU binutils sources:

git clone git://sourceware.org/git/binutils-gdb.git
cd binutils-gdb
git checkout binutils-2_33_1

# OR

curl -O https://ftp.gnu.org/gnu/binutils/binutils-2.33.1.tar.xz
tar xf binutils-2.33.1.tar.xz

Get yggdrasil-newlib sources:

git clone https://git.alnyan.me/yggdrasil/newlib
cd newlib-yggdrasil
# Make sure to check out "yggdrasil" branch
git checkout yggdrasil

Additionally, newlib uses legacy autotools features, so you'll need to install autoconf v2.65 and automake v1.11 into some location, say, <old autotools>:

curl -O https://ftp.gnu.org/gnu/automake/automake-1.11.tar.gz
curl -O https://ftp.gnu.org/gnu/autoconf/autoconf-2.65.tar.gz
tar xf automake-1.11.tar.gz
tar xf autoconf-2.65.tar.gz
mkdir automake-build autoconf-build

# Build old automake
cd automake-build
../automake-1.11/configure --prefix=<old autotools>
make && make install

# Build old autotools
cd autoconf-build
../autoconf-2.64/configure --prefix=<old autotools>
make && make install

2. The toolchain

First, you'll need to set up a proper cross-compiler environment for yggdrasil. While it's possible to just follow instructions on osdev wiki page to build bare kernel, building a full yggdrasil OS-specific toolchain is required for compiling userspace applications making use of libc (newlib at the moment of writing) and kernel headers.

Current patches are based on:

  • binutils 2.33.1
  • gcc 9.3.0

After getting all the sources, you should apply yggdrasil patches to binutils and GCC:

cd <binutils sources>
git apply <yggdrasil sources>/etc/patches/binutils/0001-*.patch
cd <gcc sources>
git apply <yggdrasil sources>/etc/patches/gcc/0001-*.patch
# This is required!
cd <gcc directory>/libstdc++-v3 && autoconf

Configure, build and install binutils:

mkdir binutils-build
cd binutils-build
<binutils sources>/configure \
    --target=x86_64-elf-yggdrasil \
    --disable-nls \
    --with-sysroot \
    --prefix=<toolchain prefix>
make && make install

Full GCC installation cannot be performed right now because there's no libc in place and kernel headers were not yet installed. Just run similar commands to install "stage 1" GCC:

mkdir gcc-build
cd gcc-build
<gcc sources>/configure \
    --target=x86_64-elf-yggdrasil \
    --disable-nls \
    --without-headers \
    --enable-languages=c,c++
    --prefix=<toolchain prefix>
make all-gcc && make all-target-libgcc && \
    make install-gcc && make install-target-libgcc

I'd suggest a coffebreak now, these commands are going to take much time.

3. Building the kernel

I recommend creating some kind of "env" file for easier environment setup when working with the toolchain:

export ARCH=amd64
export KERNEL_DIR=<yggdrasil sources>
export PATH="<toolchain prefix>/bin:$PATH"
export INSTALL_HDR=<toolchain prefix>/x86_64-elf-yggdrasil/include

The kernel is then built using make command, but first you'll need to provide a config file for it (just copy defconfig):

cd <kernel sources>
cp defconfig config
make

Now that the kernel itself is built, you can try and test it. For that you'll need to make an ISO image with grub:

mkdir -p image/boot/grub
cat >image/boot/grub/grub.cfg <<EOF
menuentry "yggdrasil" {
    multiboot2 /boot/kernel
}
EOF
cp <kernel sources>/build/kernel.elf image/boot/kernel
grub-mkrescue -o image.iso image

Then, you can boot the image using qemu:

qemu-system-x86_64 -cdrom image.iso -serial stdio

Don't panic when you see "fatal error", that happens because we haven't yet built any initial ramdisk for kernel to run /init from:

# This is absolutely okay:
[00000002 user_init_func] Starting user init
[00000002 user_init_func] ram0: No such file or directory
[00000003 panicf] --- Panic ---
[user_init_func] Fail
[00000003 panicf] --- Panic ---

Once the kernel is built and verified to boot, you should install headers into your toolchain prefix so libc can be built:

cd <kernel sources>
./install-hdr.sh

4. Building newlib

Before starting with building newlib, I recommend making an "environment" file for further use here, too:

# For x86_64-elf-yggdrasil- toolchain
export PATH="<toolchain prefix>/bin:$PATH"
# For old autotools
export PATH="<old autotools>/bin:$PATH"

A separate environment file is recommended, because it has older autotools which may conflict with autotools used for building other parts (non-newlib).

After setting up the environment, run:

mkdir newlib-build
cd newlib-build
<newlib sources>/configure \
    --prefix=<toolchain prefix> \
    --target=x86_64-elf-yggdrasil
make && make install

Once this is completed, you're ready to build userspace binaries for yggdrasil.

5. Building the userspace

The userspace is built by simply running make in "userspace" source directory:

cd <userspace sources>
make

The result of these commands is <userspace sources>/build/initrd.img file, which is used as initial ramdisk for the operating system.

6. Making the final image and testing

The final OS image is built by combining all the userspace+kernel parts and is similar to how the bare kernel was tested first:

mkdir -p image/boot/grub
cat >image/boot/grub/grub.cfg <<EOF
menuentry "yggdrasil" {
    multiboot /boot/loader
    module /boot/kernel kernel
    module /boot/initrd.img initrd
}
EOF
cp <kernel sources>/build/loader.elf image/boot/loader
cp <kernel sources>/build/kernel.elf image/boot/kernel
cp <userspace sources>/build/initrd.img image/boot/initrd.img
grub-mkrescue -o image.iso image

Finally, the resulting image can be booted using qemu (or you can try running it on your PC, I'd appreciate the feedback from running it on actual hardware):

qemu-system-x86_64 -cdrom image.iso -serial stdio

Once the system boots up, you should see the login prompt, where you can type the combination of root and toor to enter the shell as root.

Congratulations! You've successfully completed the quest of manually building yggdrasil OS.