6.3 KiB
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:
inside a loop
__asm__ volatile ("sti; hlt"); - 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:
to
#include <kernel/pit.h>kernel.c - Added:
during kernel startup
PitInitialize(); - Added:
during the PIT verification stage. In the final application-oriented kernel flow, this standalone test loop is no longer called from
SleepTest();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:
to
src/pit.cCMakeLists.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:
to
void TerminalWriteHex(uint32_t num);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:
was corrected to:
__asm__volatile__asm__ volatile printf()calls were removed from PIT test code and replaced with terminal output functions- the missing
TerminalWriteHex()declaration interminal.hwas added
These changes allowed the kernel to build again with the PIT source included.
Boot Image Verification
- Verified that rebuilding only:
updates
uiaos-kernelkernel.bin, but does not update the bootable ISO image - Confirmed that:
- the new
kernel.bincontained the new PIT- and memory-related strings - the older
kernel.isostill containedHello, World!
- the new
- Rebuilt the image using:
so QEMU would boot the updated kernel
uiaos-create-image
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, andmemory4address 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.cto 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.