Writing an OS Kernel from Scratch – Part 2: Hello World Analysis

“You think ‘Hello World’ is just printing a line? In an OS kernel, it hides the secrets of boot flow, memory layout, and hardware protocols.”

In the previous post, we successfully had our kernel output “Hello from the kernel!” on QEMU. Looks simple, right? But have you ever wondered:

  • Why does the code need to be placed at the 1MB address?
  • Why is a strange linker.ld file needed?
  • What does BIOS (or GRUB) actually do?
  • Why can’t we just use printf?

Today, we dissect this “Hello World” kernel and uncover the underlying logic of x86 bare-metal boot.


BIOS: The First Step in PC Boot

In the x86 PC world, everything starts with BIOS (Basic Input/Output System).

When the power button is pressed:

  1. CPU starts execution at address 0xFFFFFFF0 (the reset vector)
  2. BIOS code (burned into motherboard ROM) is loaded and executed
  3. BIOS performs hardware self-test (memory, disk, keyboard, etc.)
  4. BIOS loads the boot sector (512 bytes) into memory at 0x7C00 and jumps to it

Modern systems rarely boot custom kernels directly with BIOS — it’s too cumbersome! So we use GRUB (a more powerful bootloader) that supports the Multiboot protocol and can directly load ELF-format kernels.

GRUB’s role: Parse the kernel ELF file, place code/data segments at specified memory locations, set up CPU state (already in protected mode), and jump to the _start entry point.


Linker Script: The Kernel’s “Floor Plan”

Compiled code doesn’t know where to go on its own. The Linker is responsible for assembling .text (code), .data (initialized data), .bss (uninitialized data) and other segments together.

The linker.ld file tells the linker: “Please layout memory the way I specify.”

Key points:

  • . = 1M; sets the load address (VMA) to start at 1MB (0x100000)
  • .text BLOCK(4K) : ALIGN(4K) aligns code to 4KB boundaries for paging
  • .multiboot section contains the Multiboot header for GRUB recognition
  • .rodata, .data, .bss are arranged sequentially

Why Can’t We Use printf?

Because there’s no C standard library (libc). printf depends on:

  • A file system or device driver to output characters
  • Memory management (heap allocation for buffers)
  • Typically, a system call interface

At the kernel’s earliest stage, none of these exist. We have to write directly to VGA memory (0xB8000) or serial ports.

Last modified: 2025年9月14日

Author

Comments

Write a Reply or Comment

Your email address will not be published.