This repository mainly serves as playground for bare metal x86 experiments, testing different assembly flavors and learning bare metal zig.
One can just execute make run in each sub-directory to build and run the given
experiment. This assumes that all required tools are installed locally.
For convenience, the flake.nix provides a development environment,
which also documents the required tools.
# Drop into interactive shell.
nix develop
# Run the multiboot experiment for example.
nix develop --command make -C multiboot run
# Drop into a pure interactive development shell.
nix develop -i -k USER -k HOME -k DISPLAYThe sub-folders of the experiments follow a naming scheme with the following meanings.
mbr: Build a master boot record (MBR) boot sector which can be booted from legacy bios.rm: The experiment runs fully in 16-bit real mode.pm: The experiment enters 32-bit protected mode. This requires at least to setup a global descriptor table (GDT).lm: The experiment enters 64-bit long mode. This requires at least to setup a GDT as well as paging.
Keypoints of each experiment:
multiboot/: Build a kernel with multiboot 1 header and boot into it using grub as bootloader.mbr-rm-com-serial/: Implement an 8250 compatible uart driver and write to COM1 serial port purely in real mode.mbr-rm-e820-asm/: Retrieve the system memory map using the E820 bios call and format write it to the screen. This example is purely done in asm.mbr-rm-e820/: Retrieve the system memory map using the E820 bios call and format write it to the screen.mbr-rm-textmode/: Use bios calls (interrupts) to write characters to the screen (vdeo text mode) and scroll up once last line is reached.mbr-pm-textmode/: Enter 32-bit protected mode and write to VGA mmio area (text video mode) to write character to the screen.mbr-pm-palette/: Switch to VGA graphics video mode and enter 32-bit protected mode, then print the color palette of the selected graphics mode to the screen.mbr-pm-videomode-vga/: Switch to VGA graphics video mode and enter 32-bit protected mode, then draw and animate some 2d and 3d shapes.mbr-pm-videomode-vbe/: Enumerate available VESA VBE video modes and switch to a hard-coded mode in case it is available. Draw and animate some shapes on the higher resolution video mode.mbr-pm-cpuid/: Collect cpu features with thecpuidinstruction.mbr-lm-enter-asm/: Enter 64-bit long mode by setting up an idendity mapped page table. This example is purely done in asm.mbr-pm-idt/: Enter 32-bit protected mode and setup an interrupt description table (IDT). Then trigger software interrupts using theintinstruction.mbr-lm-idt/: Enter 64-bit long mode and setup an interrupt description table (IDT). Then trigger software interrupts using theintinstruction.mbr-pm-disk-lba/: Use the extended read bios call to read an additional sector from the disk into memory and access it afterwards.mbr-pm-bios-call/: Implement a function which switches from 32-bit protected mode into 16-bit real mode to issue a bios call and then return back to protected mode. This can be used to make bios calls from protected mode.mbr-pm-2nd-stage/: Load a second stage bootloader through bios calls made from protected mode.mbr-pm-2nd-stage-acpi/: Load a second stage bootloader which parses the acpi root table and dumps the MADT and MCFG tables if available.mbr-pm-smp-boot-asm/: Implement minimal example to boot multiple processors by sending INIT-SIPI inter processor interrupts (IPI) to the application processors (AP) from the bootstrap processor (BSP).mbr-pm-enter-user/: Implement minimal example to transition between kernel (ring 0) and user (ring 3) privilege level in 32-bit protected mode.mbr-lm-enter-user/: Implement minimal example to transition between kernel (ring 0) and user (ring 3) privilege level in 64-bit long mode.mbr-pm-pmem/: Implement basic physical memory manager (PMM) which allows to allocate physical memory. Initialize from free memory reported by the e820 bios call.mbr-lm-page-table/: Implement example which shows how to mondify a page table and map physical memory into virtual address space.
The master boot record (MBR) is the first sector (512 byte) on a disk which
requires the following file magic at offset 510:0x55 and 511:0xaa.
od -j510 -A d -t x1 build/mbr-pm-smp-boot-asm/boot-32.bin
# 0000510 55 aaWith legacy boot, the bios scans the boot medium for the MBR file magic and if
it matches, the MBR boot sector is loaded at address 0x7c00-0x7dff and control
is transfered to it. At that point the processor is in 16-bit real mode.
Be aware that different bios implementations may transfer control to 0x7c00 differently as real mode uses segmented memory that could be for example
07c0:0000or0000:7c000.
The 16-bit real mode uses segmented memory where memory locations are often
denoted as segment:offset (in some specs also SegOff or logical address).
The logical address is turned into a linear address in real mode as follows.
(segment << 4) + offset
A segment resides in one of the segment selector register ds, es, ss, fs, gs, cs.
Note that this is completely different to how segmentation works in protected mode, where segment selectors references an entry in the GDT.
Some projects start qemu with graphical display and some without. The following give some useful key maps when interacting with qemu.
# graphical: release mouse & keyboard grabbing from qemu ui
C-M-g
# terminal: terminate qemu
C-a x