IN3000: Operating Systems
Advanced OS coursework in C and x86 Assembly: process management, memory management, synchronization, interrupt handling, and building core OS components close to hardware with Bochs and GDB.
IN3000 - Operating Systems at UiO. The most demanding course in the CS programme: you build core OS components yourself, in C and x86 assembly, running on a real x86 emulator.
Course structure
The course proceeds from hardware up through the kernel to user-space interfaces. Each assignment targets a specific OS subsystem.
Topics and assignments
Bootloader and protected mode
- Writing a bootloader in x86 assembly that runs in real mode, sets up the A20 line, loads the GDT, and switches to 32-bit protected mode
- Disk I/O via BIOS INT 13h before any OS support is available
- Loading the kernel from disk into memory at a specific address
Interrupt handling
- Interrupt Descriptor Table (IDT) setup, registering handler functions for hardware and software interrupts
- Implementing the 8259 PIC (Programmable Interrupt Controller): enabling/disabling IRQs, EOI signalling
- Timer interrupt (IRQ0) as the driver for preemptive scheduling
- Exception handlers: page faults, general protection faults, divide-by-zero
Process management
- Process Control Block (PCB): data structure holding state (registers, stack pointer, program counter, process ID, status)
- Context switching: saving and restoring register state in assembly, switching stacks
- Round-robin scheduler and priority scheduling implementations
- Process states: running, ready, blocked, terminated
Memory management
- Segmentation: GDT entries for code/data segments with privilege levels (ring 0 and ring 3)
- Paging: page directory, page tables, CR3 register, TLB management
- Virtual memory: each process gets its own address space; kernel maps at high addresses
- Demand paging and page fault handling
Synchronization
- Spinlocks: busy-wait with atomic test-and-set
- Semaphores: blocking synchronization with wait queues
- Classic concurrency problems: producer-consumer, readers-writers, dining philosophers
System calls
- Software interrupt (INT 0x80): user-to-kernel transition with privilege elevation
- Implementing syscall dispatch table
- Writing
write(),read(),fork(),exec(),exit()syscall implementations
IPC
- Shared memory: two processes communicating through a common memory region
- Message queues: sending and receiving kernel-mediated messages
- Pipes: producer-consumer with a circular buffer in kernel space
File systems (conceptual + partial implementation)
- inode model: metadata separated from data blocks
- Directory entries, hard links vs symbolic links
- Block allocation strategies: contiguous, linked, indexed (inode with direct + indirect blocks)
Tools used
- Bochs: x86 PC emulator that simulates hardware faithfully; allows pausing mid-boot and inspecting registers
- GDB with Bochs stub: setting breakpoints inside the bootloader and kernel, stepping through assembly
- NASM: assembler for x86 assembly code
- GCC cross-compiler: compiling C without a runtime for bare-metal targets
What this course is really about
Most programmers never think about what happens when their code calls malloc() or writes to a file. The OS just handles it. This course removes that abstraction. Understanding virtual memory, the privilege model, and how context switching works makes you a fundamentally better programmer, even if you never write another line of kernel code.