### Install OS Development Tools with apt-get Source: https://littleosbook.github.io/index Installs essential packages for OS development on Ubuntu using the apt-get package manager. These tools include a C compiler, assembler, and utilities for creating bootable media. ```bash sudo apt-get install build-essential nasm genisoimage bochs bochs-sdl ``` -------------------------------- ### Stack Setup for User Mode Entry (Assembly) Source: https://littleosbook.github.io/index Illustrates the required stack layout for executing the IRET instruction to enter user mode. The stack must contain the segment selectors (ss, cs), instruction pointer (eip), stack pointer (esp), and control flags (eflags) for the user mode environment. This setup is crucial for the processor to correctly transition privilege levels. ```assembly [esp + 16] ss ; the stack segment selector we want for user mode [esp + 12] esp ; the user mode stack pointer [esp + 8] eflags ; the control flags we want to use in user mode [esp + 4] cs ; the code segment selector [esp + 0] eip ; the instruction pointer of user mode code to execute ``` -------------------------------- ### Linker Script for Flat Binaries (Linker Script) Source: https://littleosbook.github.io/index This linker script configures the output format to be a flat binary and sets the starting address to 0. It explicitly includes the `.text` section from `start.o` first, followed by other `.text`, `.data`, and `.rodata` sections. This script is essential for creating predictable flat binary executables. ```linker script OUTPUT_FORMAT("binary") /* output flat binary */ SECTIONS { . = 0; /* relocate to address 0 */ .text ALIGN(4): { start.o(.text) /* include the .text section of start.o */ *(.text) /* include all other .text sections */ } .data ALIGN(4): { *(.data) } .rodata ALIGN(4): { *(.rodata*) } } ``` -------------------------------- ### Run Bochs Emulator (Shell) Source: https://littleosbook.github.io/index Launches the Bochs emulator with a specified configuration file and in quiet mode. The `-f` flag points to the configuration file (`bochsrc.txt`), and `-q` skips the interactive menu, starting the emulation directly. ```shell bochs -f bochsrc.txt -q ``` -------------------------------- ### Memory-Mapped I/O Example for Framebuffer Source: https://littleosbook.github.io/index Illustrates memory-mapped I/O for interacting with hardware, specifically the framebuffer. Writing to a specific memory address updates the display. ```c /* Writing 0x410F to address 0x000B8000 displays 'A' in white on black */ volatile unsigned short *framebuffer = (volatile unsigned short *)0xB8000; framebuffer[0] = (0x0F << 8) | 'A'; ``` -------------------------------- ### I/O Port Interaction Example (Conceptual) Source: https://littleosbook.github.io/index Describes the use of assembly instructions `in` and `out` for I/O port communication with hardware. This is distinct from memory-mapped I/O. ```assembly /* Example of writing to an I/O port */ /* out , */ mov dx, 0x3F8 /* I/O port address */ mov al, 'H' /* Data to send */ out dx, al /* Example of reading from an I/O port */ /* in , */ mov dx, 0x3F8 /* I/O port address */ in al, dx /* Read data into AL */ ``` -------------------------------- ### Call C Function from Assembly (cdecl convention) Source: https://littleosbook.github.io/index This example demonstrates calling a C function (`sum_of_three`) from assembly code using the cdecl calling convention. Arguments are pushed onto the stack in right-to-left order, and the function's return value is expected in the `eax` register. ```c /* The C function */ int sum_of_three(int arg1, int arg2, int arg3) { return arg1 + arg2 + arg3; } ``` ```assembly ; The assembly code external sum_of_three ; the function sum_of_three is defined elsewhere push dword 3 ; arg3 push dword 2 ; arg2 push dword 1 ; arg1 call sum_of_three ; call the function, the result will be in eax ``` -------------------------------- ### Define Kernel Memory Boundaries with Linker Script Source: https://littleosbook.github.io/index This linker script defines the virtual and physical start and end addresses for the kernel. It specifies alignment for text, read-only data, data, and BSS sections, and calculates physical addresses relative to a base offset. These labels are crucial for the kernel to understand its own memory footprint. ```linker script ENTRY(loader) /* the name of the entry symbol */ . = 0xC0100000 /* the code should be relocated to 3 GB + 1 MB */ /* these labels get exported to the code files */ kernel_virtual_start = .; kernel_physical_start = . - 0xC0000000; /* align at 4 KB and load at 1 MB */ .text ALIGN (0x1000) : AT(ADDR(.text)-0xC0000000) { *(.text) /* all text sections from all files */ } /* align at 4 KB and load at 1 MB + . */ .rodata ALIGN (0x1000) : AT(ADDR(.rodata)-0xC0000000) { *(.rodata*) /* all read-only data sections from all files */ } /* align at 4 KB and load at 1 MB + . */ .data ALIGN (0x1000) : AT(ADDR(.data)-0xC0000000) { *(.data) /* all data sections from all files */ } /* align at 4 KB and load at 1 MB + . */ .bss ALIGN (0x1000) : AT(ADDR(.bss)-0xC0000000) { *(COMMON) /* all COMMON sections from all files */ *(.bss) /* all bss sections from all files */ } kernel_virtual_end = .; kernel_physical_end = . - 0xC0000000; ``` -------------------------------- ### Create ISO Folder Structure and Copy Files (Shell) Source: https://littleosbook.github.io/index Creates the directory structure for the ISO image and copies the GRUB bootloader and kernel executable into their respective locations. This is a prerequisite for building the ISO. ```shell mkdir -p iso/boot/grub # create the folder structure cp stage2_eltorito iso/boot/grub/ # copy the bootloader cp kernel.elf iso/boot/ # copy the kernel ``` -------------------------------- ### Assembly for Higher-half Kernel Entry and Paging Source: https://littleosbook.github.io/index This assembly code demonstrates the critical steps to transition to the higher half of virtual memory. It involves setting up page tables, creating an identity mapping for the first 4MB, and mapping the higher-half kernel address. Finally, it performs an indirect jump to the higher-half entry point, after which the kernel can continue execution in the new address space. ```assembly ; assembly code executing at around 0x00100000 ; enable paging for both actual location of kernel ; and its higher-half virtual location lea ebx, [higher_half] ; load the address of the label in ebx jmp ebx ; jump to the label higher_half: ; code here executes in the higher half kernel ; eip is larger than 0xC0000000 ; can continue kernel initialisation, calling C code, etc. ``` -------------------------------- ### Set up Multiboot Header for Module Loading (Assembly) Source: https://littleosbook.github.io/index This assembly code snippet defines the multiboot header required by GRUB to load modules. It sets a magic number, an instruction to align modules on page boundaries, and calculates a checksum. This code should be placed at the beginning of the kernel file (`loader.s`). ```assembly ; in file `loader.s` MAGIC_NUMBER equ 0x1BADB002 ; define the magic number constant ALIGN_MODULES equ 0x00000001 ; tell GRUB to align modules ; calculate the checksum (all options + checksum should equal 0) CHECKSUM equ -(MAGIC_NUMBER + ALIGN_MODULES) section .text: ; start of the text (code) section align 4 ; the code must be 4 byte aligned dd MAGIC_NUMBER ; write the magic number dd ALIGN_MODULES ; write the align modules instruction dd CHECKSUM ; write the checksum ``` -------------------------------- ### Bochs Emulator Configuration File (bochsrc.txt) Source: https://littleosbook.github.io/index A sample Bochs emulator configuration file. It sets up essential parameters such as memory, display library, ROM images, CD-ROM drive with the `os.iso` image, boot order, and CPU settings. This file is used to run the LittleOS in the emulator. ```bochs megs: 32 display_library: sdl romimage: file=/usr/share/bochs/BIOS-bochs-latest vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latest ata0-master: type=cdrom, path=os.iso, status=inserted boot: cdrom log: bochslog.txt clock: sync=realtime, time0=local cpu: count=1, ips=1000000 ``` -------------------------------- ### Invalidate TLB Entry in x86 Assembly Source: https://littleosbook.github.io/index This x86 assembly snippet shows how to invalidate a Translation Lookaside Buffer (TLB) entry for a specific virtual address. The `invlpg` instruction is used to clear cached address translations, which is necessary when page table entries are modified. This example invalidates the entry for virtual address 0. ```assembly ; invalidate any TLB references to virtual address 0 invlpg [0] ``` -------------------------------- ### GRUB Configuration File (menu.lst) Source: https://littleosbook.github.io/index Defines the GRUB bootloader configuration, specifying the default boot option, timeout, and the location of the kernel executable. This file is essential for GRUB to load the operating system. ```grub default=0 timeout=0 title os kernel /boot/kernel.elf ``` -------------------------------- ### Explicit Segment Register Usage in Assembly Source: https://littleosbook.github.io/index This assembly code snippet shows explicit usage of segment registers for memory access. It achieves the same functionality as the implicit example but specifies the 'ss' and 'ds' registers for stack and data operations, respectively. This highlights how segment selectors must be loaded into the correct registers for implicit addressing to work. ```assembly func: mov eax, [ss:esp+4] mov ebx, [ds:eax] add ebx, 8 mov [ds:eax], ebx ret ``` -------------------------------- ### Assembly Entry Point for C Programs (Assembly) Source: https://littleosbook.github.io/index This assembly code serves as the entry point for C user mode programs. It pushes arguments onto the stack, calls the C `main` function, and then enters an infinite loop after `main` returns. This is typically saved in a file like `start.s`. ```assembly extern main section .text ; push argv ; push argc call main ; main has returned, eax is return value jmp $ ; loop forever ``` -------------------------------- ### Configure GRUB to Load External Program Module Source: https://littleosbook.github.io/index This snippet shows how to configure GRUB to load an external program as a module. It involves adding a 'module' line to the GRUB configuration file (`iso/boot/grub/menu.lst`) and creating the directory for modules. ```shell module /modules/program mkdir -p iso/modules ``` -------------------------------- ### Simple Test Program for Execution (Assembly) Source: https://littleosbook.github.io/index This is a very basic assembly program designed to test program execution. It sets the `eax` register to a specific value (`0xDEADBEEF`) for verification and then enters an infinite loop. This program is compiled into a flat binary. ```assembly ; set eax to some distinguishable number, to read from the log afterwards mov eax, 0xDEADBEEF ; enter infinite loop, nothing more to do ; $ means "beginning of line", ie. the same instruction jmp $ ``` -------------------------------- ### Compile Program to Flat Binary (NASM) Source: https://littleosbook.github.io/index This command uses the NASM assembler with the `-f bin` flag to compile an assembly source file (`program.s`) into a raw, flat binary executable (`program`). This format is required because the kernel cannot parse advanced executable formats. ```shell nasm -f bin program.s -o program ``` -------------------------------- ### Higher-half Linker Script Configuration Source: https://littleosbook.github.io/index This linker script configures the kernel to be loaded at a higher virtual address (0xC0100000). It specifies the entry point, sets the base address for code and data sections, and aligns them to 4KB boundaries. The AT directive is used to calculate the physical load address relative to the virtual address. ```linker script ENTRY(loader) /* the name of the entry symbol */ . = 0xC0100000 /* the code should be relocated to 3GB + 1MB */ /* align at 4 KB and load at 1 MB */ .text ALIGN (0x1000) : AT(ADDR(.text)-0xC0000000) { *(.text) /* all text sections from all files */ } /* align at 4 KB and load at 1 MB + . */ .rodata ALIGN (0x1000) : AT(ADDR(.text)-0xC0000000) { *(.rodata*) /* all read-only data sections from all files */ } /* align at 4 KB and load at 1 MB + . */ .data ALIGN (0x1000) : AT(ADDR(.text)-0xC0000000) { *(.data) /* all data sections from all files */ } /* align at 4 KB and load at 1 MB + . */ .bss ALIGN (0x1000) : AT(ADDR(.text)-0xC0000000) { *(COMMON) /* all COMMON sections from all files */ *(.bss) /* all bss sections from all files */ } ``` -------------------------------- ### Generate ISO Image with genisoimage (Shell) Source: https://littleosbook.github.io/index Generates the bootable ISO image using the `genisoimage` command. It specifies the bootloader, input directory, and various other options to create a functional ISO file named `os.iso`. ```shell genisoimage -R \ -b boot/grub/stage2_eltorito \ -no-emul-boot \ -boot-load-size 4 \ -A os \ -input-charset utf8 \ -quiet \ -boot-info-table \ -o os.iso \ iso ``` -------------------------------- ### Populating IDT Array with Handler Addresses (C) Source: https://littleosbook.github.io/index Demonstrates how to assign the hexadecimal values representing an IDT entry to an array of unsigned integers in C. This assumes an `idt` array is already declared. ```c idt[0] = 0xDEAD8E00 idt[1] = 0x0008BEEF ``` -------------------------------- ### Execute Loaded Module in C Source: https://littleosbook.github.io/index This C code snippet demonstrates how to call a loaded module from GRUB. It defines a function pointer type `call_module_t` and casts a memory address `address_of_module` to this type to execute the module's code. This method is convenient for parsing the multiboot structure compared to assembly. ```c typedef void (*call_module_t)(void); /* ... */ call_module_t start_program = (call_module_t) address_of_module; start_program(); /* we'll never get here, unless the module code returns */ ``` -------------------------------- ### Bochs configuration for serial port output to file Source: https://littleosbook.github.io/index This configuration snippet for the Bochs emulator (`bochsrc.txt`) sets up the first serial port (`com1`) to be enabled and direct its output to a file named `com1.out`. This is useful for capturing serial output during debugging or development. ```text com1: enabled=1, mode=file, dev=com1.out ``` -------------------------------- ### Link 32-bit ELF Object File into Kernel Executable (GNU LD) Source: https://littleosbook.github.io/index This command uses the GNU LD linker to combine the `loader.o` object file with the `link.ld` linker script to produce the final kernel executable, `kernel.elf`. The `-melf_i386` flag specifies the target architecture. ```bash ld -T link.ld -melf_i386 loader.o -o kernel.elf ``` -------------------------------- ### Framebuffer Cursor Movement with Assembly Source: https://littleosbook.github.io/index Demonstrates the assembly instructions to move the framebuffer cursor by sending high and low bytes of the position to specific I/O ports (0x3D4 and 0x3D5). ```assembly out 0x3D4, 14 ; 14 tells the framebuffer to expect the highest 8 bits of the position out 0x3D5, 0x00 ; sending the highest 8 bits of 0x0050 out 0x3D4, 15 ; 15 tells the framebuffer to expect the lowest 8 bits of the position out 0x3D5, 0x50 ; sending the lowest 8 bits of 0x0050 ``` -------------------------------- ### Linker Script for Kernel Memory Layout (GNU LD) Source: https://littleosbook.github.io/index This linker script specifies how the kernel's sections (.text, .rodata, .data, .bss) should be arranged in memory. It ensures the code is loaded at or above 1MB and aligns sections to 4KB boundaries. This script is used by the GNU LD linker. ```linker-script ENTRY(loader) /* the name of the entry label */ SECTIONS { . = 0x00100000; /* the code should be loaded at 1 MB */ .text ALIGN (0x1000) : /* align at 4 KB */ { *(.text) /* all text sections from all files */ } .rodata ALIGN (0x1000) : /* align at 4 KB */ { *(.rodata*) /* all read-only data sections from all files */ } .data ALIGN (0x1000) : /* align at 4 KB */ { *(.data) /* all data sections from all files */ } .bss ALIGN (0x1000) : /* align at 4 KB */ { *(COMMON) /* all COMMON sections from all files */ *(.bss) /* all bss sections from all files */ } } ``` -------------------------------- ### Access Multiboot Information for Module Address (C) Source: https://littleosbook.github.io/index This C code snippet demonstrates how to access the multiboot information structure passed to the kernel. It casts the `ebx` register content (which points to the multiboot structure) to a `multiboot_info_t` pointer and retrieves the address of the loaded modules using the `mods_addr` field. It also highlights the importance of checking `flags` and `mods_count` for successful module loading. ```c int kmain(/* additional arguments */ unsigned int ebx) { multiboot_info_t *mbinfo = (multiboot_info_t *) ebx; unsigned int address_of_module = mbinfo->mods_addr; } ``` -------------------------------- ### Makefile for LittleOS Build Automation Source: https://littleosbook.github.io/index A Makefile to automate the compilation, linking, ISO image creation, and execution of the LittleOS kernel. It defines variables for compiler, flags, and build targets. ```makefile OBJECTS = loader.o kmain.o CC = gcc CFLAGS = -m32 -nostdlib -nostdinc -fno-builtin -fno-stack-protector \ -nostartfiles -nodefaultlibs -Wall -Wextra -Werror -c LDFLAGS = -T link.ld -melf_i386 AS = nasm ASFLAGS = -f elf all: kernel.elf kernel.elf: $(OBJECTS) ld $(LDFLAGS) $(OBJECTS) -o kernel.elf os.iso: kernel.elf cp kernel.elf iso/boot/kernel.elf genisoimage -R \ -b boot/grub/stage2_eltorito \ -no-emul-boot \ -boot-load-size 4 \ -A os \ -input-charset utf8 \ -quiet \ -boot-info-table \ -o os.iso \ iso run: os.iso bochs -f bochsrc.txt -q %.o: %.c $(CC) $(CFLAGS) $< -o $@ %.o: %.s $(AS) $(ASFLAGS) $< -o $@ clean: rm -rf *.o kernel.elf os.iso ``` -------------------------------- ### Display Bochs Log File (Shell) Source: https://littleosbook.github.io/index Displays the contents of the Bochs emulator's log file (`bochslog.txt`). This log can contain valuable information about the emulation process, including CPU register states, which can be used for debugging. ```shell cat bochslog.txt ``` -------------------------------- ### Compile Assembly to 32-bit ELF Object File (NASM) Source: https://littleosbook.github.io/index This command uses the NASM assembler to compile the `loader.s` assembly file into a 32-bit ELF object file named `loader.o`. This is a necessary step before linking the kernel. ```bash nasm -f elf32 loader.s ``` -------------------------------- ### Assembly Code for Minimal OS Loader (NASM) Source: https://littleosbook.github.io/index This assembly code defines the Multiboot header and the entry point for a minimal operating system. It sets a magic number, flags, and checksum, then places a specific value into the EAX register before entering an infinite loop. This code is intended to be compiled with NASM. ```assembly global loader ; the entry symbol for ELF MAGIC_NUMBER equ 0x1BADB002 ; define the magic number constant FLAGS equ 0x0 ; multiboot flags CHECKSUM equ -MAGIC_NUMBER ; calculate the checksum ; (magic number + checksum + flags should equal 0) section .text: ; start of the text (code) section align 4 ; the code must be 4 byte aligned dd MAGIC_NUMBER ; write the magic number to the machine code, dd FLAGS ; the flags, dd CHECKSUM ; and the checksum loader: ; the loader label (defined as entry point in linker script) mov eax, 0xCAFEBABE ; place the number 0xCAFEBABE in the register eax .loop: jmp .loop ; loop forever ``` -------------------------------- ### Enable Paging in x86 Assembly Source: https://littleosbook.github.io/index This assembly code demonstrates how to enable paging in an x86 system. It involves setting the Page Size Extensions (PSE) bit in CR4 and the Paging (PG) bit in CR0, after loading the page directory's physical address into CR3. Ensure the page directory address in EAX is a physical address. ```assembly ; eax has the address of the page directory mov cr3, eax mov ebx, cr4 ; read current cr4 or ebx, 0x00000010 ; set PSE mov cr4, ebx ; update cr4 mov ebx, cr0 ; read current cr0 or ebx, 0x80000000 ; set PG mov cr0, ebx ; update cr0 ; now paging is enabled ``` -------------------------------- ### Linker Flags for Flat Binary Output (Shell) Source: https://littleosbook.github.io/index These flags are used with the linker (`ld`) to produce a flat binary executable. The `-T link.ld` option specifies the linker script to use, and `-melf_i386` emulates a 32-bit ELF format, although the final output is dictated by the linker script to be a binary. ```shell -T link.ld -melf_i386 # emulate 32 bits ELF, the binary output is specified # in the linker script ``` -------------------------------- ### C Header for I/O Port Write Function Source: https://littleosbook.github.io/index A C header file `io.h` declaring the `outb` function, which is implemented in assembly. It provides a safe way to interact with I/O ports from C code. ```c #ifndef INCLUDE_IO_H #define INCLUDE_IO_H /** outb: * Sends the given data to the given I/O port. Defined in io.s * * @param port The I/O port to send the data to * @param data The data to send to the I/O port */ void outb(unsigned short port, unsigned char data); #endif /* INCLUDE_IO_H */ ``` -------------------------------- ### Write Character to Framebuffer (C) Source: https://littleosbook.github.io/index Demonstrates writing a character to the framebuffer in C by treating the memory address as a char pointer. This method involves writing the character and its color attributes to consecutive memory locations. ```c char *fb = (char *) 0x000B8000; fb[0] = 'A'; fb[1] = 0x28; ``` -------------------------------- ### Creating an IDT Entry for a Handler (Assembly) Source: https://littleosbook.github.io/index Illustrates how to represent an interrupt handler's address and privilege level using hexadecimal values for an IDT entry. This is a low-level representation before using structures. ```assembly 0xDEAD8E00 0x0008BEEF ```