Files
Exams/AdvOpsys/notes/work-summary-2026-04-15.md
2026-05-31 14:05:22 +02:00

6.3 KiB
Raw Blame History

Assignment 4 Part 2: Programmable Interval Timer

Overview

In this part of the assignment, work was done on adding a basic driver for the Programmable Interval Timer (PIT) to the OSDev_18 kernel. The goal was to initialize the PIT, count timer ticks using IRQ0, and use those ticks to support both busy-wait sleeping and interrupt-based sleeping.

The PIT was configured to use channel 0 and generate regular timer interrupts at 1000 Hz. This gives a simple timing model where one timer tick is approximately equal to one millisecond.


Implemented Features

PIT Header and Constants

  • Added:
    include/kernel/pit.h
    
  • Defined constants for:
    • PIT command port
    • PIT channel 0 port
    • PIT base frequency
    • target frequency
    • calculated divider
    • ticks-per-millisecond conversion

This provides a single place for PIT-related configuration and function declarations.


PIT Initialization

  • Implemented:
    void PitInitialize(void);
    
  • Configures the PIT using:
    OutPortByte(PIT_CMD_PORT, 0x36);
    
  • Loads the PIT divisor into channel 0:
    • low byte first
    • high byte second
  • Registers the PIT interrupt handler on:
    IRQ0
    

This allows the kernel to start receiving regular timer interrupts from the PIT.


Tick Counter

  • Added a global tick counter:
    static volatile uint32_t pit_ticks = 0;
    
  • Implemented a helper function:
    uint32_t GetCurrentTick(void);
    

The tick counter is incremented every time IRQ0 is triggered. Since the PIT is configured to 1000 Hz, this gives a simple way to measure elapsed time in milliseconds.


PIT IRQ Handler

  • Implemented:
    static void PitIrqHandler(struct Registers* regs);
    
  • The handler:
    • ignores the register argument
    • increments pit_ticks

This keeps the timer interrupt path minimal and lets the rest of the kernel measure time by reading the current tick count.


Busy-Wait Sleep

  • Implemented:
    void SleepBusy(uint32_t milliseconds);
    
  • Uses the current tick count to wait until enough time has passed
  • Continuously checks the tick counter in a loop

This version works by actively spinning on the CPU, so it is simple but inefficient.


Interrupt-Based Sleep

  • Implemented:
    void SleepInterrupt(uint32_t ticks);
    
  • Uses:
    __asm__ volatile ("sti; hlt");
    
    inside a loop
  • Re-checks the current tick count after each wake-up

This version is more efficient than busy waiting because the CPU is halted between interrupts instead of constantly polling in a tight loop.


Kernel Integration

  • Added:
    #include <kernel/pit.h>
    
    to kernel.c
  • Added:
    PitInitialize();
    
    during kernel startup
  • Added:
    SleepTest();
    
    during the PIT verification stage. In the final application-oriented kernel flow, this standalone test loop is no longer called from main().

This connects the PIT driver to the boot flow so the timer logic is available after interrupt setup is complete.


Build System Update

  • Added:
    src/pit.c
    
    to CMakeLists.txt

This ensures the PIT implementation is compiled and linked into the kernel binary together with the rest of the source files.


Terminal Output Fix

  • Added the missing declaration for:
    void TerminalWriteHex(uint32_t num);
    
    to terminal.h

This was necessary because TerminalWriteHex() was already implemented in terminal.c and used in several source files, but it was not exposed through the header.


Testing & Verification

Build Issues Resolved

During integration, several issues were found and corrected:

  • incorrect inline assembly syntax:
    __asm__volatile
    
    was corrected to:
    __asm__ volatile
    
  • printf() calls were removed from PIT test code and replaced with terminal output functions
  • the missing TerminalWriteHex() declaration in terminal.h was added

These changes allowed the kernel to build again with the PIT source included.


Boot Image Verification

  • Verified that rebuilding only:
    uiaos-kernel
    
    updates kernel.bin, but does not update the bootable ISO image
  • Confirmed that:
    • the new kernel.bin contained the new PIT- and memory-related strings
    • the older kernel.iso still contained Hello, World!
  • Rebuilt the image using:
    uiaos-create-image
    
    so QEMU would boot the updated kernel

This explained why old output was still appearing even after the source code had changed.


Runtime Result

After rebuilding the bootable image, the kernel successfully booted into the updated code and displayed:

  • paging setup output
  • heap and allocation debug output
  • the memory1, memory2, memory3, and memory4 address prints

This confirms that the updated kernel binary is now being booted correctly.

The PIT sleep test loop was also verified at runtime. The kernel repeatedly prints the expected sleep messages for both:

  • busy-wait sleeping
  • interrupt-based sleeping

This shows that the PIT tick counter is advancing and that both sleep functions return as expected during execution.

During this test, one remaining issue was observed in the terminal output: once the VGA text buffer wraps back to the top of the screen, new text overwrites old text directly. The later menu and game flow reduces this by clearing the screen before redrawing, but the terminal still does not implement proper scrolling.


Conclusion

  • Added a PIT driver skeleton to the kernel
  • Configured PIT channel 0 for periodic timer interrupts
  • Registered an IRQ0 handler and added a global tick counter
  • Implemented both busy-wait and interrupt-based sleep functions
  • Integrated PIT support into kernel.c
  • Added pit.c to the build system
  • Fixed the missing TerminalWriteHex() declaration
  • Verified that the updated kernel is now booting from the rebuilt ISO image
  • Verified that the PIT sleep test loop runs at runtime

This means the code structure for Part 2 is present in the kernel and has been tested at runtime. The remaining terminal limitation is that continuous logs still wrap instead of scrolling.


Later Integration Note

The final application framework clears the screen before menu and game redraws, so the wraparound problem is less visible during normal use. Proper terminal scrolling would still be a useful future improvement for debug output.