107 lines
5.1 KiB
TeX
107 lines
5.1 KiB
TeX
%% SCRAP: architecture/03-architecture/hal/platform-implementations
|
|
%% SOURCE: docs/working/architecture/03-architecture/hal/platform-implementations.md
|
|
%% STATUS: WORKING
|
|
%% FITS: dev-guide/ch-platform
|
|
%% EDITORIAL: lifted — prose rewritten to press voice
|
|
|
|
\section{HAL Platform Implementation Guide}
|
|
|
|
This section explains how to implement the Hardware Abstraction Layer for a new
|
|
target. It walks through the hosted Linux reference and the freestanding
|
|
StarKernel implementation, then sets out a testing strategy and the pitfalls
|
|
that most often defeat a new platform.
|
|
|
|
\subsection{Directory Layout and Build Integration}
|
|
|
|
Each platform lives under its own directory and supplies one source file per
|
|
subsystem --- time, interrupt, memory, console, CPU, and panic --- plus an
|
|
optional initialization file. The build selects a platform and compiles only its
|
|
sources. The freestanding kernel target additionally adds the flags that strip
|
|
the hosted runtime.
|
|
|
|
\begin{lstlisting}[language=bash]
|
|
PLATFORM ?= linux # linux | l4re | kernel
|
|
|
|
PLATFORM_SOURCES = \
|
|
src/platform/$(PLATFORM)/hal_time.c \
|
|
src/platform/$(PLATFORM)/hal_interrupt.c \
|
|
src/platform/$(PLATFORM)/hal_memory.c \
|
|
src/platform/$(PLATFORM)/hal_console.c \
|
|
src/platform/$(PLATFORM)/hal_cpu.c \
|
|
src/platform/$(PLATFORM)/hal_panic.c
|
|
|
|
ifeq ($(PLATFORM),kernel)
|
|
CFLAGS += -ffreestanding -nostdlib -mno-red-zone
|
|
LDFLAGS += -nostdlib -static
|
|
endif
|
|
\end{lstlisting}
|
|
|
|
\subsection{The Linux Reference Platform}
|
|
|
|
Linux is the reference platform, chosen for its rich debugging environment. Its
|
|
implementation is thin. Time maps onto \texttt{clock\_gettime(CLOCK\_MONOTONIC)},
|
|
with the periodic timer built from a POSIX timer and a real-time signal whose
|
|
handler dispatches the registered callback. Memory wraps \texttt{malloc} and
|
|
\texttt{free}, zero-initializing every allocation to satisfy the contract, and
|
|
treats page allocation as a heap allocation under an identity-mapping
|
|
assumption. The console wraps standard I/O, flushing after each write and polling
|
|
standard input for the non-blocking check. Interrupts are emulated: enable and
|
|
disable are no-ops because signals cannot be masked through this path, and
|
|
interrupt context is reported through a thread-local flag set inside the signal
|
|
handler. CPU identity is fixed at zero for the single-threaded case, relax calls
|
|
\texttt{sched\_yield()}, and panic prints to standard error and aborts.
|
|
|
|
\begin{lstlisting}[language=C]
|
|
uint64_t hal_time_now_ns(void) {
|
|
struct timespec ts;
|
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
return (uint64_t)ts.tv_sec * 1000000000ULL + ts.tv_nsec;
|
|
}
|
|
\end{lstlisting}
|
|
|
|
\subsection{The StarKernel Freestanding Platform}
|
|
|
|
The kernel platform is freestanding: no C library, no operating system, direct
|
|
hardware access. Time reads the TSC, calibrated against the HPET at
|
|
initialization, validates monotonicity, and panics if calibration fails; the
|
|
periodic timer programs the local APIC timer, and its ISR invokes the callback
|
|
and issues an end-of-interrupt. Interrupts are real: enable and disable issue
|
|
\texttt{sti} and \texttt{cli}, the disable path captures and returns the flags
|
|
register for later restoration, ISR registration writes the dispatch table and
|
|
routes the IRQ through the IOAPIC, and interrupt context is tracked by a nesting
|
|
counter incremented and decremented around each dispatch. Memory binds to the
|
|
physical memory manager, the virtual memory manager, and the \texttt{kmalloc}
|
|
heap, translating the HAL mapping flags into page-table flags. The console drives
|
|
a 16550 UART and a UEFI GOP framebuffer in parallel. CPU identity comes from the
|
|
local APIC, relax issues \texttt{pause}, and halt issues \texttt{hlt}.
|
|
|
|
\begin{lstlisting}[language=C]
|
|
uint64_t hal_time_now_ns(void) {
|
|
uint64_t tsc = rdtsc();
|
|
return tsc_to_ns(tsc) - tsc_offset_ns;
|
|
}
|
|
\end{lstlisting}
|
|
|
|
\subsection{Testing Strategy}
|
|
|
|
A new platform is validated at three levels. First, per-platform unit tests
|
|
exercise each HAL function in isolation --- confirming, for example, that
|
|
\texttt{hal\_time\_now\_ns()} is monotonic and that a requested delay elapses.
|
|
Second, the cross-platform VM test suite must pass identically on every target.
|
|
Third, determinism is validated by running the design-of-experiments harness on
|
|
each platform and confirming that the output is identical across them, which
|
|
demonstrates zero algorithmic variance.
|
|
|
|
\subsection{Common Pitfalls}
|
|
|
|
Four failure modes recur. \emph{Non-monotonic time}: a TSC that runs backward
|
|
under multi-core scheduling or frequency scaling corrupts the rolling window;
|
|
the remedy is \texttt{rdtscp}, cross-core synchronization, or an HPET fallback.
|
|
\emph{Timer jitter}: signal latency on Linux or interrupt latency on a kernel
|
|
widens heartbeat intervals and inflates metric variance; minimize ISR work, use
|
|
a high-priority interrupt, and disable frequency scaling. \emph{Memory leaks}:
|
|
allocations without matching frees, often in error paths; track them with
|
|
Valgrind on Linux and by hand on the kernel. \emph{Interrupt-context
|
|
violations}: calling a blocking HAL function from an ISR; guard blocking
|
|
functions with an assertion that the caller is not in interrupt context.
|