1

Initial commit

This commit is contained in:
2023-02-26 21:12:51 +01:00
commit d2ec37332f
69 changed files with 58831 additions and 0 deletions

49
chap/appendix_figures.tex Normal file
View File

@ -0,0 +1,49 @@
\chapter{Figures}
\label{ch:figures}
\clearpage
\begin{figure}[h]
\centering
\begin{subfigure}[b]{1.0\textwidth}
\includesvg[width=1.0\linewidth]{img/mp_spec_discrete_apic_configuration.svg}
\end{subfigure}
\caption{The discrete APIC architecture~\cite[sec.~5.1]{mpspec}.}
\label{fig:discreteapic}
\end{figure}
\begin{figure}[h]
\centering
\begin{subfigure}[b]{1.0\textwidth}
\includesvg[width=1.0\linewidth]{img/mp_spec_integrated_apic_configuration.svg}
\end{subfigure}
\caption{The integrated APIC architecture~\cite[sec.~5.2]{mpspec}.}
\label{fig:integratedapic}
\end{figure}
\begin{figure}[h]
\centering
\begin{subfigure}[b]{0.7\textwidth}
\includesvg[width=1.0\linewidth]{img/ia32_manual_system_vs_apic_bus.svg}
\end{subfigure}
\caption{System vs APIC bus~\cite[sec.~3.11.1]{ia32}.}
\label{fig:systemvsapicbus}
\end{figure}
\begin{figure}[h]
\centering
\begin{subfigure}[b]{1.0\textwidth}
\includesvg[width=1.0\linewidth]{img/ia32_manual_local_apic_blockdiagram.svg}
\end{subfigure}
\caption{The local APIC block diagram~\cite[sec.~3.11.4.1]{ia32}.}
\label{fig:localapicblock}
\end{figure}
\begin{figure}[h]
\centering
\begin{subfigure}[b]{1.0\textwidth}
\includesvg[width=1.0\linewidth]{img/ia32_lvt.svg}
\end{subfigure}
\caption{The Local Vector Table~\cite[sec.~3.11.5.1]{ia32}.}
\label{fig:localapiclvt}
\end{figure}

360
chap/appendix_listings.tex Normal file
View File

@ -0,0 +1,360 @@
\chapter{Listings}
\label{ch:listings}
This chapter contains concrete implementation examples for concepts mentioned in
\autoref{ch:implementation}, demonstrated on the example of hhuOS\@.
\clearpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Accessing Local APIC Registers in xApic Mode}
\label{sec:apxxapicregacc}
The xApic register access requires a single page of strong uncachable memory, but since this
requires setting attributes in the ``Page Attribute Table''\footnote{See
\url{https://docs.kernel.org/x86/pat.html} (visited on 12/02/2023).}, this implementation only uses
hhuOS' \code{mapIO} function\cite[MemoryService.cpp]{hhuos}, which maps a physical address to the
kernel heap, with hhuOS' ``CACHE\textunderscore{}DISABLE'' flag set in the kernel page table:
\begin{codeblock}{Allocating the Local APIC's MMIO Region (LocalApic.cpp)}{C++}
\cppfile{code/lapic_mmio_alloc.cpp}
\end{codeblock}
A register can now be written as follows:
\begin{codeblock}[label=lst:lapicmmiowrite]{Writing a Local APIC MMIO Register (LocalApic.cpp)}{C++}
\cppfile{code/lapic_mmio_write.cpp}
\end{codeblock}
To reduce the usage of manual bit-shifting and -masking, this implementation provides structures
for some commonly used registers, that implement conversion operators to the register format:
\begin{codeblock}[label=lst:msrentry]{The MSREntry Structure (LocalApicRegisters.h)}{C++}
\cppfile{code/lapic_msr_entry.cpp}
\end{codeblock}
\begin{codeblock}[label=lst:svrentry]{The SVREntry Structure (LocalApicRegisters.h)}{C++}
\cppfile{code/lapic_svr_entry.cpp}
\end{codeblock}
\begin{codeblock}[label=lst:lvtentry]{The LVTEntry Structure (LocalApicRegisters.h)}{C++}
\cppfile{code/lapic_lvt_entry.cpp}
\end{codeblock}
\begin{codeblock}[label=lst:icrentry]{The ICREntry Structure (LocalApicRegisters.h)}{C++}
\cppfile{code/lapic_icr_entry.cpp}
\end{codeblock}
These can be used in combination with some convenience functions:
\begin{codeblock}{Writing the IA32\textunderscore{}APIC\textunderscore{}BASE MSR (LocalApic.cpp)}{C++}
\cppfile{code/lapic_write_msr.cpp}
\end{codeblock}
\begin{codeblock}{Writing the SVR (LocalApic.cpp)}{C++}
\cppfile{code/lapic_write_svr.cpp}
\end{codeblock}
\begin{codeblock}{Writing the LVT (LocalApic.cpp)}{C++}
\cppfile{code/lapic_write_lvt.cpp}
\end{codeblock}
\begin{codeblock}{Writing the ICR (LocalApic.cpp)}{C++}
\cppfile{code/lapic_write_icr.cpp}
\end{codeblock}
% \clearpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Disabling PIC-Mode}
\label{sec:apxdisablepic}
Setting the IMCR\footnote{Writing the IMCR is detailed in the MultiProcessor
specification~\cite[sec. 3.6.2.1]{mpspec}.} using hhuOS' \code{IoPort} class:
\begin{codeblock}{Disabling PIC-Mode (LocalApic.cpp)}{C++}
\cppfile{code/lapic_imcr.cpp}
\end{codeblock}
% \clearpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Initializing the LVT}
\label{sec:apxlvtinit}
The interrupt vectors are set as defined by the \code{InterruptVector} enum. This implementation
configures the LVT by using the \code{LVTEntry} struct (see \autoref{lst:lvtentry}):
\begin{codeblock}{Configuring the LINT0 Local Interrupt (LocalApic.cpp)}{C++}
\cppfile{code/lapic_lvt_example.cpp}
\end{codeblock}
This process is repeated for each local interrupt.
% \clearpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Handling the Spurious Interrupt}
\label{sec:apxsvr}
This implementation sets the SVR by using the \code{SVREntry} struct (see \autoref{lst:svrentry}):
\begin{codeblock}{Setting the Spurious Interrupt Vector (LocalApic.cpp)}{C++}
\cppfile{code/lapic_svr_example.cpp}
\end{codeblock}
Because hhuOS uses a two-stage interrupt handling approach (described in
\autoref{sec:currenthhuos}), the spurious interrupt does not receive its own interrupt handler.
Instead, it is ignored in the \code{dispatch} function, hhuOS' ``first-stage'' interrupt handler:
\begin{codeblock}{Checking for Spurious Interrupts (InterruptDispatcher.cpp)}{C++}
\cppfile{code/interruptdispatcher_check_spurious.cpp}
\end{codeblock}
\begin{codeblock}{Ignoring Spurious Interrupts (InterruptDispatcher.cpp)}{C++}
\cppfile{code/interruptdispatcher_ignore_spurious.cpp}
\end{codeblock}
% \clearpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Using the APIC Timer}
\label{sec:apxapictimer}
The timer frequency is determined by counting the ticks in one millisecond, using the PIT as
calibration source:
\begin{codeblock}{Calibrating the APIC Timer (ApicTimer.cpp)}{C++}
\cppfile{code/apictimer_calibrate.cpp}
\end{codeblock}
This calibration is performed before the interrupts get enabled, so it is not possible to use
hhuOS' \code{TimeService} for the delay. Instead, the \code{PIT::earlyDelay} function is used,
which configures the PIT for mode 0 on channel 0 and polls the channel's output status~\cite{pit}].
Furthermore, the calibration is only performed once, even if multiple APIC timers are used. This
removes the possibility of using multiple timers with different dividers.
To handle the APIC timer interrupt on multiple cores, \(n\) \code{ApicTimer} instances are
registered to the appropriate interrupt vector, where \(n\) is the number of CPUs. Because this
means, that each APIC timer interrupt on any CPU core triggers all \(n\) interrupt handlers, the
handler has to determine if it belongs to the calling CPU:
\begin{codeblock}{Handling the APIC Timer Interrupt (ApicTimer.cpp)}{C++}
\cppfile{code/apictimer_trigger.cpp}
\end{codeblock}
% \clearpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Handling local APIC Errors}
\label{sec:apxhandlingerror}
The error interrupt handler obtains the ESR's contents by writing to it first:
\begin{codeblock}{The local APIC Error Interrupt Handler (ApicErrorHandler.cpp)}{C++}
\cppfile{code/apicerror_trigger.cpp}
\end{codeblock}
Because every CPU core can only access its own local APIC's registers, a single instance of this
interrupt handler can be used for each AP in the system.
\clearpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Accessing I/O APIC Registers}
\label{sec:iolistings}
The I/O APIC's indirect register access requires two MMIO registers, that can be written similar to
the local APIC's registers:
\begin{codeblock}{Writing an I/O APIC MMIO Register (IoApic.h)}{C++}
\cppfile{code/ioapic_write_mmio.cpp}
\end{codeblock}
Using the ``Index'' and ``Data'' registers to access the I/O APIC's indirect registers:
\begin{codeblock}{Writing an I/O APIC indirect Register (IoApic.cpp)}{C++}
\cppfile{code/ioapic_write_indirect.cpp}
\end{codeblock}
To reduce the manual bit-shifting and -masking, the same approach is used as for the local APIC:
\begin{codeblock}[label=lst:redtblentry]{The REDTBLEntry Structure (IoApicRegisters.h)}{C++}
\cppfile{code/ioapic_redtbl_entry.cpp}
\end{codeblock}
\begin{codeblock}[label=lst:writeredtbl]{Writing the REDTBL (IoApic.cpp)}{C++}
\cppfile{code/ioapic_write_redtbl.cpp}
\end{codeblock}
% \clearpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{I/O APIC Interrupt Overrides}
\label{sec:apxirqoverrides}
This implementation represents an interrupt override using the following structure:
\begin{codeblock}{The External Interrupt Override Structure (IoApic.h)}{C++}
\cppfile{code/ioapic_irqoverride.cpp}
\end{codeblock}
During initialization, they are used to set the correct interrupt vectors, polarities and trigger
modes for each REDTBL entry. The \code{REDTBLEntry} struct (see \autoref{lst:redtblentry}) is used
to write the REDTBL:
\begin{codeblock}{Initializing the REDTBL (IoApic.cpp)}{C++}
\cppfile{code/ioapic_redtbl_example.cpp}
\end{codeblock}
During regular OS operation, they are used to determine the correct REDTBL entries for e.g.\
unmasking an interrupt:
\begin{codeblock}{Unmasking an IRQ (Apic.cpp)}{C++}
\cppfile{code/apic_allow.cpp}
\end{codeblock}
To convey this deviation between GSIs and PC/AT compatible IRQs very clearly, the internal
\code{IoApic::allow} function only accepts a \code{GlobalSystemInterrupt} as argument, while the
public \code{Apic::allow} function accepts an \code{InterruptRequest}, that allows addressing the
interrupt by name.
\clearpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Issuing Inter-Processor Interrupts}
\label{sec:apxipis}
To issue an IPI, the ICR is written by using the \code{ICREntry} struct (see
\autoref{lst:icrentry}):
\begin{codeblock}{Issuing an INIT IPI (LocalApic.cpp)}{C++}
\cppfile{code/lapic_initipi_example.cpp}
\end{codeblock}
\begin{codeblock}{Issuing a SIPI (LocalApic.cpp)}{C++}
\cppfile{code/lapic_sipi_example.cpp}
\end{codeblock}
% \clearpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Preparing Symmetric Multiprocessing Startup}
\label{sec:apxpreparesmp}
Before executing the ``Universal Startup Algorithm'', the boot code has to be relocated to physical
lower memory. The memory region used for this copy has to be identity mapped to the virtual kernel
address space, so the effective addresses don't change after enabling paging in protected mode. To
keep required variables available to the startup code, these are located in the routines ``TEXT''
section and initialized during runtime. This approach was taken from~\cite[APIC.cpp]{serenity}:
\begin{codeblock}{Preparing the Boot Routine's Variables (ApicSmp.cpp)}{C++}
\cppfile{code/ap_boot_variables.cpp}
\end{codeblock}
Now, the initialized startup routine can be copied to \code{0x8000}:
\begin{codeblock}{Relocating the Boot Routine (ApicSmp.cpp)}{C++}
\cppfile{code/ap_boot_copy.cpp}
\end{codeblock}
The \code{boot\textunderscore{}ap} function is the entry of the startup routine, it is described
further in \autoref{sec:apxapboot}.
% \clearpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Universal Startup Algorithm}
\label{sec:apxmpusa}
The ``INIT-SIPI-SIPI'' sequence, or ``Universal Startup Algorithm'' is performed by issuing IPIs as
described in \autoref{sec:apxipis} and using the PIT as time source (see
\autoref{sec:apxapictimer}):
\begin{codeblock}{The Universal Startup Algorithm (ApicSmp.cpp)}{C++}
\cppfile{code/ap_boot_usa.cpp}
\end{codeblock}
Boot completion is signaled in the AP's entry function:
\begin{codeblock}{Signaling AP Boot Completion (smp\textunderscore{}entry.cpp)}{C++}
\cppfile{code/smp_entry.cpp}
\end{codeblock}
% \clearpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Application Processor Boot Routine}
\label{sec:apxapboot}
Because like the BSP, every AP is initialized in real mode, it has to be switched to protected mode
first:
\begin{codeblock}{Preparing the Switch to Protected Mode (smp\textunderscore{}boot.asm)}{nasm}
\nasmfile{code/ap_boot_real_prepare.asm}
\end{codeblock}
Then, by enabling protected mode, setting the segment registers and far-jumping to the 32-bit code
segment, the switch is performed:
\begin{codeblock}{Switching from Real Mode to Protected Mode (smp\textunderscore{}boot.asm)}{nasm}
\nasmfile{code/ap_boot_real.asm}
\end{codeblock}
In 32-bit protected mode, paging is enabled and interrupt processing is prepared by reusing the
control register values and the IDT from the BSP:
\begin{codeblock}{Loading Registers from the BSP (smp\textunderscore{}boot.asm)}{nasm}
\nasmfile{code/ap_boot_protected_bsp.asm}
\end{codeblock}
Finally, to call the AP entry function, the AP requires its own GDT and stack:
\begin{codeblock}{Calling the Entry Function (smp\textunderscore{}boot.asm)}{nasm}
\nasmfile{code/ap_boot_protected_ap.asm}
\end{codeblock}
The rest of the AP's initialization is performed from the entry function.
% \clearpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Application Processor Post-Boot Routine}
\label{sec:apxappostboot}
When the AP has booted, it initializes its own APIC, including the APIC timer and error handler:
\begin{codeblock}{Initializing the Core's Local APIC (LocalApic.cpp)}{C++}
\cppfile{code/ap_boot_post.cpp}
\end{codeblock}
Because this added another possible recipient to internal APIC messages, the arbitration IDs are
synchronized by issuing an ``INIT-level-deassert IPI'' using the \code{ICREntry} struct (see
\autoref{lst:icrentry}):
\begin{codeblock}{Synchronizing the Arbitration IDs (LocalApic.cpp)}{C++}
\cppfile{code/lapic_apr_example.cpp}
\end{codeblock}
Because hhuOS' paging is not designed for multiple processors, the booted AP remains in a busy loop
and does not enable its interrupts.
\clearpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Integration into hhuOS}
\label{sec:hhuosintegration}
To integrate the APIC implementation into hhuOS, some preexisting components of its interrupt
infrastructure (described in \autoref{sec:currenthhuos}) have to be modified:
\begin{enumerate}
\item The \code{InterruptService} has to forward calls to allow or forbid a hardware interrupt to the
\code{Apic} class instead of the \code{Pic} class, depending on if the APIC system is enabled - to
keep the option of running the OS on hardware that does not support the APIC (see
\autoref{lst:interruptserviceafter}).
\item The \code{Pit} interrupt handler may no longer trigger the scheduler preemption if the APIC timer
is enabled (see \autoref{lst:pithandlerafter}).
\item The \code{System::initializeSystem} function needs to enable the APIC system if it is available
(see \autoref{lst:systemafter}).
\end{enumerate}
\begin{codeblock}[label=lst:interruptserviceafter]{Using the correct interrupt controller (InterruptService.cpp)}{C++}
\cppfile{code/interruptservice_after.cpp}
\end{codeblock}
\begin{codeblock}[label=lst:pithandlerafter]{Disable preemption if necessary (Pit.cpp)}{C++}
\cppfile{code/pit_after.cpp}
\end{codeblock}
\begin{codeblock}[label=lst:systemafter]{Enabling the APIC system (System.cpp)}{C++}
\cppfile{code/system_after.cpp}
\end{codeblock}
\cleardoublepage

440
chap/appendix_tables.tex Normal file
View File

@ -0,0 +1,440 @@
\chapter{Tables}
\label{ch:tables}
This section lists all the registers and structures required to follow \autoref{ch:implementation}.
\clearpage
\renewcommand{\arraystretch}{1.2}
\section{Local APIC Registers}
\label{sec:localapicregisters}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Register Name} & \textbf{Memory Offset} \\ \hline\hline
Local APIC ID Register & 0x20 \\ \hline
Local APIC Version Register & 0x30 \\ \hline
Task Priority Register & 0x80 \\ \hline
EOI Register & 0xB0 \\ \hline
Spurious Interrupt Vector Register & 0xF0 \\ \hline
Error Status Register & 0x280 \\ \hline
Interrupt Command Register[0:31] & 0x300 \\ \hline
Interrupt Command Register[32:63] & 0x310 \\ \hline
LVT Timer Register & 0x320 \\ \hline
LVT LINT1 Register & 0x360 \\ \hline
LVT Error Register & 0x370 \\ \hline
Timer Initial Count Register & 0x380 \\ \hline
Timer Divide Configuration Register & 0x3E0 \\ \hline
\end{tabularx}
\caption{Local APIC Registers used in this Implementation~\cite[sec.~3.11.4.1]{ia32}.}
\label{tab:lapicregs}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Bit Number} & \textbf{Description} \\ \hline\hline
0:23 & Reserved \\ \hline
24:31 & Local APIC ID \\ \hline
\end{tabularx}
\caption{Local APIC ID Register (xApic since Pentium 4)~\cite[sec.~3.11.4.6]{ia32}.}
\label{tab:lapicregsid}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Bit Number} & \textbf{Description} \\ \hline\hline
0:7 & Local APIC Version \\ \hline
8:15 & Reserved \\ \hline
16:23 & Max LVT Entry \\ \hline
24 & EOI Broadcast Suppression Support \\ \hline
25:31 & Reserved \\ \hline
\end{tabularx}
\caption{Local APIC Version Register~\cite[sec.~3.11.4.8]{ia32}.}
\label{tab:lapicregsver}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Bit Number} & \textbf{Description} \\ \hline\hline
0:3 & Task-Priority Subclass \\ \hline
4:7 & Task-Priority Class \\ \hline
8:31 & Reserved \\ \hline
\end{tabularx}
\caption{Task Priority Register~\cite[sec.~3.11.8.3.1]{ia32}.}
\label{tab:lapicregstpr}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Bit Number} & \textbf{Description} \\ \hline\hline
0:31 & Send EOI Signal \\ \hline
\end{tabularx}
\caption{Local APIC EOI Register~\cite[sec.~3.11.8.5]{ia32}.}
\label{tab:lapicregseoi}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Bit Number} & \textbf{Description} \\ \hline\hline
0:7 & Spurious Interrupt Vector \\ \hline
8 & APIC Software Enable/Disable \\ \hline
9 & Focus Processor Checking \\ \hline
10:11 & Reserved \\ \hline
12 & EOI Broadcast Suppression \\ \hline
13:31 & Reserved \\ \hline
\end{tabularx}
\caption{Spurious Interrupt Vector Register~\cite[sec.~3.11.9]{ia32}.}
\label{tab:lapicregssvr}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Bit Number} & \textbf{Description} \\ \hline\hline
0:4 & Reserved \\ \hline
5 & Send Illegal Vector \\ \hline
6 & Receive Illegal Vector \\ \hline
7 & Illegal Register Access \\ \hline
8:31 & Reserved \\ \hline
\end{tabularx}
\caption{Error Status Register (Pentium 4)~\cite[sec.~3.11.5.3]{ia32}.}
\label{tab:lapicregsesr}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Bit Number} & \textbf{Description} \\ \hline\hline
0:7 & Interrupt Vector \\ \hline
8:10 & Delivery Mode \\ \hline
11 & Destination Mode \\ \hline
12 & Delivery Status \\ \hline
13 & Reserved \\ \hline
14 & Level \\ \hline
15 & Trigger Mode \\ \hline
16:17 & Reserved \\ \hline
18:19 & Destination Shorthand \\ \hline
20:55 & Reserved \\ \hline
56:63 & Destination Field \\ \hline
\end{tabularx}
\caption{Interrupt Command Register~\cite[sec.~3.11.6.1]{ia32}.}
\label{tab:lapicregsicr}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Bit Number} & \textbf{Description} \\ \hline\hline
0:7 & Interrupt Vector \\ \hline
8:11 & Reserved \\ \hline
12 & Delivery Status \\ \hline
13:15 & Reserved \\ \hline
16 & Masked \\ \hline
17:18 & Timer Mode \\ \hline
19:31 & Reserved \\ \hline
\end{tabularx}
\caption{LVT Timer Register~\cite[sec.~3.11.5.1]{ia32}.}
\label{tab:lapicregslvtt}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Bit Number} & \textbf{Description} \\ \hline\hline
0:7 & Interrupt Vector \\ \hline
8:11 & Reserved \\ \hline
12 & Delivery Status \\ \hline
13:15 & Reserved \\ \hline
16 & Masked \\ \hline
17:31 & Reserved \\ \hline
\end{tabularx}
\caption{LVT Error Register~\cite[sec.~3.11.5.1]{ia32}.}
\label{tab:lapicregslvterr}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Bit Number} & \textbf{Description} \\ \hline\hline
0:7 & Interrupt Vector \\ \hline
8:10 & Delivery Mode \\ \hline
11 & Reserved \\ \hline
12 & Delivery Status \\ \hline
13 & Pin Polarity \\ \hline
14 & Remote IRR \\ \hline
15 & Pin Polarity \\ \hline
16 & Masked \\ \hline
17:31 & Reserved \\ \hline
\end{tabularx}
\caption{LVT LINT1 Register~\cite[sec.~3.11.5.1]{ia32}.}
\label{tab:lapicregslvtlint}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Bit Number} & \textbf{Description} \\ \hline\hline
0:31 & Initial Count \\ \hline
\end{tabularx}
\caption{Timer Initial Count Register~\cite[sec.~3.11.5.4]{ia32}.}
\label{tab:lapicregstimerinit}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Bit Number} & \textbf{Description} \\ \hline\hline
0:1 & Divider \\ \hline
2 & Reserved \\ \hline
3 & Divider \\ \hline
4:31 & Reserved \\ \hline
\end{tabularx}
\caption{Timer Divide Configuration Register~\cite[sec.~3.11.5.4]{ia32}.}
\label{tab:lapicregstimerdiv}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Bit Number} & \textbf{Description} \\ \hline\hline
0:7 & Reserved \\ \hline
8 & BSP Flag \\ \hline
9 & Reserved \\ \hline
10 & Enable x2Apic \\ \hline
11 & Enable xApic \\ \hline
12:35 & APIC Base Address \\ \hline
36:63 & Reserved \\ \hline
\end{tabularx}
\caption{IA32\textunderscore{}APIC\textunderscore{}BASE MSR~\cite[sec.~3.11.12.1]{ia32}.}
\label{tab:lapicregsmsr}
\end{table}
\clearpage
\section{I/O APIC Registers}
\label{sec:ioapicregs}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Register Name} & \textbf{Memory Offset} \\ \hline\hline
Index Register & 0x00 \\ \hline
Data Register & 0x10 \\ \hline\hline
\textbf{Register Name} & \textbf{Index Offset} \\ \hline\hline
I/O APIC ID Register & 0x00 \\ \hline
I/O APIC Version Register & 0x01 \\ \hline
Redirection Table & 0x10:0x3F \\ \hline
\end{tabularx}
\caption{I/O APIC Registers used in this Implementation~\cite[sec.~9.5]{ich5}.}
\label{tab:ioapicregs}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Bit Number} & \textbf{Description} \\ \hline\hline
0:7 & Indirect Register Index \\ \hline
\end{tabularx}
\caption{I/O APIC Index Register~\cite[sec.~9.5.2]{ich5}.}
\label{tab:ioapicregsidx}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Bit Number} & \textbf{Description} \\ \hline\hline
0:31 & Indirect Register Data \\ \hline
\end{tabularx}
\caption{I/O APIC Data Register~\cite[sec.~9.5.3]{ich5}.}
\label{tab:ioapicregsdat}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Bit Number} & \textbf{Description} \\ \hline\hline
0:14 & Reserved \\ \hline
15 & Scratchpad Bit \\ \hline
16:23 & Reserved \\ \hline
24:27 & I/O APIC ID \\ \hline
28:31 & Reserved \\ \hline
\end{tabularx}
\caption{I/O APIC ID Register~\cite[sec.~9.5.6]{ich5}.}
\label{tab:ioapicregsid}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Bit Number} & \textbf{Description} \\ \hline\hline
0:7 & I/O APIC Version \\ \hline
8:14 & Reserved \\ \hline
15 & PRQ \\ \hline
16:23 & Maximum Redirection Entries \\ \hline
24:31 & Reserved \\ \hline
\end{tabularx}
\caption{I/O APIC Version Register~\cite[sec.~9.5.7]{ich5}.}
\label{tab:ioapicregsver}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Bit Number} & \textbf{Description} \\ \hline\hline
0:7 & Interrupt Vector \\ \hline
8:10 & Delivery Mode \\ \hline
11 & Destination Mode \\ \hline
12 & Delivery Status \\ \hline
13 & Pin Polarity \\ \hline
14 & Remote IRR \\ \hline
15 & Trigger Mode \\ \hline
16 & Masked \\ \hline
17:47 & Reserved \\ \hline
48:55 & Extended Destination ID \\ \hline
56:63 & Destination \\ \hline
\end{tabularx}
\caption{I/O APIC REDTBL Register~\cite[sec.~9.5.8]{ich5}.}
\label{tab:ioapicregsredtbl}
\end{table}
\clearpage
\section{System Description Tables}
\label{sec:sdts}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Byte Number} & \textbf{Description} \\ \hline\hline
0:35 & MADT Header \\ \hline
36:39 & Local APIC Base Address \\ \hline
40:43 & Local APIC Flags \\ \hline
44: & List of APIC Structures \\ \hline
\end{tabularx}
\caption{ACPI MADT~\cite[sec.~5.2.8]{acpi1}.}
\label{tab:madt}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Byte Number} & \textbf{Description} \\ \hline\hline
0:1 & APIC Structure Header \\ \hline
2 & ACPI Processor ID \\ \hline
3 & APIC ID \\ \hline
4:7 & Local APIC Flags (see \autoref{tab:madtlapicflags}) \\ \hline
\end{tabularx}
\caption{MADT Processor Local APIC Structure~\cite[sec.~5.2.8.1]{acpi1}.}
\label{tab:madtlapic}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Bit Number} & \textbf{Description} \\ \hline\hline
0 & Enabled \\ \hline
1:31 & Reserved \\ \hline
\end{tabularx}
\caption{Local APIC Flags~\cite[sec.~5.2.8.1]{acpi1}.}
\label{tab:madtlapicflags}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Byte Number} & \textbf{Description} \\ \hline\hline
0:1 & APIC Structure Header \\ \hline
2 & I/O APIC ID \\ \hline
3 & Reserved \\ \hline
4:7 & I/O APIC Base Address \\ \hline
8:11 & I/O APIC GSI Base \\ \hline
\end{tabularx}
\caption{MADT I/O APIC Structure~\cite[sec.~5.2.8.2]{acpi1}.}
\label{tab:madtioapic}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Byte Number} & \textbf{Description} \\ \hline\hline
0:1 & APIC Structure Header \\ \hline
2 & Bus \\ \hline
3 & Source \\ \hline
4:7 & GSI \\ \hline
8:9 & Interrupt Input Flags (see \autoref{tab:madtintiflags}) \\ \hline
\end{tabularx}
\caption{MADT Interrupt Source Override Structure~\cite[sec.~5.2.8.3.1]{acpi1}.}
\label{tab:madtirqoverride}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Bit Number} & \textbf{Description} \\ \hline\hline
0:1 & Pin Polarity \\ \hline
2:3 & Trigger Mode \\ \hline
4:11 & Reserved \\ \hline
\end{tabularx}
\caption{Interrupt Input Flags~\cite[sec.~5.2.8.3.1]{acpi1}.}
\label{tab:madtintiflags}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Byte Number} & \textbf{Description} \\ \hline\hline
0:1 & APIC Structure Header \\ \hline
2:3 & Interrupt Input Flags (see \autoref{tab:madtintiflags}) \\ \hline
4:7 & GSI
\end{tabularx}
\caption{MADT I/O APIC NMI Source~\cite[sec.~5.2.8.3.2]{acpi1}.}
\label{tab:madtionmi}
\end{table}
\begin{table}[H]
\centering
\begin{tabularx}{1.0\textwidth}{| X | X |}
\hline
\textbf{Byte Number} & \textbf{Description} \\ \hline\hline
0:1 & APIC Structure Header \\ \hline
2 & ACPI Processor ID \\ \hline
3:4 & Interrupt Input Flags (see \autoref{tab:madtintiflags}) \\ \hline
5 & Local APIC Interrupt Input \\ \hline
\end{tabularx}
\caption{MADT Local APIC NMI Source~\cite[sec.~5.2.8.3.3]{acpi1}.}
\label{tab:madtlnmi}
\end{table}

427
chap/background.tex Normal file
View File

@ -0,0 +1,427 @@
\chapter{Background}
\label{ch:background}
In this section, important domain specific concepts will be explained, to create the necessary
foundation to follow \autoref{ch:implementation}. Important terms that are present in the glossary
are marked in \textbf{bold} on their first occurrence.
\clearpage
\section{Handling of External Events}
\label{sec:eventhandling}
There are two different strategies to ``listen'' for external events: ``Polling'' and
``Interrupts''.
The first strategy works by periodically \textit{polling} a device to check for changes. This could
mean reading a register of the keyboard every 50 ms to determine if a key was pressed, or reading a
sensor output even when the value remains unchanged. Because every device would have to be polled
constantly, no matter if any change actually occurred, this method is computationally inefficient
(although easy to implement without extra hardware).
The second strategy are \textbf{\glspl{interrupt}}. Instead of the CPU actively ``looking'' for
changes, the devices signal the events to the CPU themselves. Every time the CPU is notified of an
external event, it pauses the current code execution and calls a function designated to handle this
specific event.
This approach is much more efficient than the polling strategy, because the CPU does not have to
waste its processing power to check for events when none are occurring.
\section{Fundamental Concepts}
\label{sec:fundamentals}
\subsection{Interrupt}
\label{subsec:interrupt}
When a device signals an external event to the CPU, the current code execution gets
\textit{interrupted}, to handle the event. Thus, the process of signaling and handling an external
event is called ``interrupt''.
Interrupts can be caused by all sorts of events, like key presses on a keyboard or packets received
via a network card. These interrupts from external hardware devices are called
\textbf{\glspl{external interrupt}}.
Other types of interrupts mentioned in this thesis are \textbf{\glspl{ipi}}, \textbf{\glspl{msi}}
and \textbf{\glspl{local interrupt}}:
\begin{itemize}
\item IPIs: Interrupts sent between different processor cores in multiprocessor systems, for example to
initialize different cores on system startup.
\item MSIs: Interrupts sent in-band\footnote{In in-band signaling some control information (like an IRQ)
is sent over the same channel as the data. This stands in contrast to out-of-band signaling, which
uses a dedicated control line (like an interrupt line).}, for example over a PCI-bus\footnote{PCI
supports MSIs since PCI 2.2~\cite[sec.~6.8]{pci22}.}.
\item Local Interrupts: Some specific CPU-internal interrupts.
\end{itemize}
Some interrupts are essential for continuous CPU operation. These \textbf{\glspl{nmi}} always have
to be handled and cannot be ignored (usually\footnote{An example where NMIs should be disabled is
the startup of additional processors in multiprocessor systems.}). Hardware error interrupts are a
typical example for NMIs.
The existence of NMIs hints that it is possible to ignore regular interrupts. Marking an interrupt
as ``ignored'' is called \textbf{\gls{masking}} an interrupt.
\subsection{Interrupt Controller}
\label{subsec:controller}
A computer system has to process interrupts from many sources, so it is practical to have a
designated \textbf{\gls{interrupt controller}}, that receives interrupts from different devices and
forwards them to the CPU. The masking functionality is integrated into the interrupt controller, so
masked interrupts don't reach the CPU at all.
The interrupt controller receives interrupts through signals over physical connections (interrupt
lines) to different devices. These signals can be represented in multiple ways through the level on
the interrupt lines:
\textbf{\Gls{trigger mode}}:
\begin{itemize}
\item Edge-triggered signal: A signal is received when the interrupt line level changes
\item Level-triggered signal: A signal is received when the interrupt line reaches a certain level
\end{itemize}
\textbf{\Gls{pin polarity}}:
\begin{itemize}
\item High: A signal is received when the interrupt line level changes from either low to high (in
edge-triggered mode) or reaches a level above a threshold (in level-triggered mode)
\item Low: A signal is received when the interrupt line level changes from either high to low (in
edge-triggered mode) or reaches a level below a threshold (in level-triggered mode)
\end{itemize}
A signal is represented through a combination of trigger mode and pin polarity, so there are a
total of 4 combinations.
When the interrupt controller receives an interrupt signal, it requests the CPU to handle the
specific event: The interrupt controller sends an \textbf{\gls{irq}} to the CPU. Because there are
multiple devices that can signal interrupts, an IRQ is usually indexed by its hardware pin on the
interrupt controller: If a keyboard is connected to the interrupt controller on pin 1, the CPU
receives an IRQ1.
To signal that an interrupt has been handled by the software, the interrupt controller receives an
\textbf{\gls{eoi}} notice from the OS\@.
Information on specific interrupt controllers follows in \autoref{sec:intelcontrollers}.
\subsection{Interrupt Handler}
\label{subsec:handler}
When the CPU receives an IRQ, it pauses its current code execution to handle the interrupt. This is
done by executing the \textbf{\gls{interrupt handler}} function, that is registered to the specific
interrupt.
During interrupt servicing (execution of the interrupt handler), other interrupts can occur. When
the execution of an interrupt handler is paused to handle another interrupt, this is called a
\textbf{\gls{cascaded interrupt}}.
Interrupt handlers have to be registered to different IRQs, so the CPU can locate and execute the
specific code that is designated to handle a certain interrupt. The interrupt handler addresses are
stored in an \textit{interrupt vector table}: Each address corresponds to an \textbf{\gls{interrupt
vector}} number, interrupt vectors 0 to 31 are reserved for the CPU, interrupt vectors 32 to 255
are usable for IRQs. In Intel's 32 bit IA-32 CPU architecture, this table is called the
\textbf{\gls{idt}}. The \textbf{\gls{idtr}} keeps the location of the IDT, it is written by the
\code{lidt}~\cite{x86isa} instruction.
\subsection{Interrupt Trigger Mode}
\label{subsec:triggermode}
When an edge-triggered IRQ is received, its interrupt handler is called a single time, serviced,
and marked as completed in the interrupt controller (completion does not require interacting with
the device the interrupt originated from). The handler of an edge-triggered IRQ is called every
time the interrupt line changes its level. This could lead to problems if ``glitches'' occur on the
interrupt line.
An alternative is the level-triggered IRQ: When the interrupt line is above/below a certain level,
the interrupt is signaled continuously. Servicing the interrupt thus requires not only signaling
completion to the interrupt controller, but also to the device the interrupt originated from, to
de-assert the interrupt line. Otherwise, the interrupt handler would be called again after
completion.
\subsection{Spurious Interrupt}
\label{subsec:spurious}
When an interrupt disappears while the interrupt controller is issuing the IRQ to the CPU, the
interrupt controller sends a \textbf{\gls{spurious interrupt}}. The reason for this could be
electrical noise on the interrupt line, masking of an interrupt through software at the same moment
this interrupt was received, or incorrectly sent EOIs. Thus, before an interrupt handler is called,
the OS has to check the validity of the occurred interrupt and ignore it, if it is deemed spurious.
\section{Used Technologies}
\label{sec:technologies}
\subsection{Advanced Configuration and Power Interface}
\label{subsec:acpi}
\textbf{\gls{acpi}} allows the kernel to gather information about the system hardware during
runtime. It also provides interactive functionality for power management, plug and play,
hot-swapping or status monitoring. To interact with ACPI, the
\textbf{\gls{aml}}~\cite[sec.~16]{acpi1}, a small language interpreted by the kernel, has to be
used\footnote{In this thesis, information from ACPI is only read, so AML is not required.}.
ACPI defines abstractions for different types of hardware, that are organized in multiple
\textit{system description tables}. In this thesis, ACPI 1.0~\cite{acpi1} is used to read
information about the system's interrupt hardware configuration, located in the ACPI
\textbf{\gls{madt}}~\cite[sec.~5.2.8]{acpi1}. The MADT contains information on used interrupt
controllers (version, physical memory addresses to access registers, etc.), available CPU cores in
multiprocessor systems and specific interrupt configuration (trigger mode and pin polarity).
To allow compatibility to different interrupt controllers, ACPI abstracts external interrupts
through \textbf{\glspl{gsi}}~\cite[sec.~5.2.9]{acpi1}. Different interrupt controllers may have the
same devices connected to different interrupt lines, maintaining a mapping between actual hardware
interrupt lines and GSIs allows the OS to operate on different interrupt
controllers\footnote{Additional information in \autoref{subsec:ioapicpcat}.}.
\subsection{CPU Identification}
\label{subsec:cpuid}
\textbf{\gls{cpuid}} is used to gather information about a system's CPU. The x86 architecture
provides the \code{cpuid}~\cite{x86isa} instruction, which allows the software to identify present
CPU features at runtime, e.g.\ what instruction set extensions a processor implements\footnote{This
thesis uses CPUID to determine what APIC feature set is supported, see ``APIC'' and ``x2APIC''
features in the CPUID application note~\cite[sec.~5.1.2]{cpuid}.}.
\subsection{Symmetric Multiprocessing}
\label{subsec:smp}
\textbf{\gls{smp}} is a form of multiprocessing, where a system consists of multiple, homogeneous
CPU cores, that all have access to a shared main memory and the I/O devices. SMP systems are
controlled by a single OS, that treats all cores as individual, but equal processors. The shared
main memory allows every core to work on an arbitrary task, independent of its memory location.
Programming for SMP systems requires the usage of multithreading, to allow for an efficient
distribution of tasks to multiple CPU cores.
In SMP systems, a single CPU core is active initially, this core is called the \textbf{\gls{bsp}}.
Other cores, called \textbf{\glspl{ap}}, will be initialized by this core.
% TODO: I think I could remove this section
% \subsection{BIOS and UEFI}
% \label{subsec:biosuefi}
%
% The \textbf{\gls{bios}} provides low-level control over a computer system's hardware, most commonly
% used for booting an OS on system power-up. Its pre-boot environment is limited to the 16-bit
% \textbf{\gls{real mode}} and 1 MB of addressable memory. BIOS originates from the IBM PC and has
% been the default convention for computer system firmware until the \textbf{\gls{uefi}} standard.
%
% The UEFI standard is developed by the UEFI Forum, based on Intel's EFI. It improves on BIOS by
% providing modularity, support for larger partitions, 32-bit or 64-bit environments before booting
% and advanced features like networking capabilities, graphical user interfaces with mouse support or
% security features\footnote{See \url{https://uefi.org/specifications} (visited on 22/02/2023).}.
\subsection{Model Specific Register}
\label{subsec:msr}
A \textbf{\gls{msr}} is a special control register in an IA-32 CPU, that is not guaranteed to be
present in future CPU generations (it is not part of the architectural standard). MSRs that carried
over to future generations and are now guaranteed to be included in future IA-32 or Intel 64 CPUs
are called ``architectural'' MSRs. To interact with MSRs, the special instructions \code{rdmsr} and
\code{wrmsr} are used~\cite{x86isa}. These instructions allow atomic read/write operations on
MSRs\footnote{Detailed description in the IA-32 manual~\cite[sec.~4.2]{ia32}.}.
\subsection{Memory Mapped I/O}
\label{subsec:mmio}
\textbf{\gls{mmio}} is a way for the CPU to perform I/O operations with an external device.
Registers of external devices are mapped to the same address space as the main memory, thus a
memory address can either be a location in physical memory, or belong to a device's register. Read
and write operations are then performed by reading or writing the address the register is mapped
to.
\subsection{Programmable Interval Timer}
\label{subsec:pit}
The \textbf{\gls{pit}}\footnote{Specifically the Intel 8253/8254.} is a hardware timer from the
original IBM PC. It consists of multiple decrementing counters and can generate a signal (for
example an interrupt) once 0 is reached. This can be used to control a preemptive\footnote{A
scheduler is called ``preemptive'', when it is able to forcefully take away the CPU from the
currently working thread, even when the thread did not signal any form of completion.} scheduler or
the integrated PC speaker.
\section{Intel's Interrupt Controllers}
\label{sec:intelcontrollers}
Because it is logistically difficult to connect every external device directly to the CPU, this
task is delegated to an interrupt controller, usually located in the system's chipset. Notable
interrupt controllers (and the only ones considered in this thesis) are the Intel
\textbf{\gls{pic}} and Intel \textbf{\gls{apic}}.
\subsection{Programmable Interrupt Controller}
\label{subsec:intelpic}
The Intel 8259A PIC~\cite{pic} is the interrupt controller Intel used in the original Intel
8086\footnote{The 8259 was used in the Intel 8080 and 8085, the 8259A is a revised version for the
Intel 8086}, the ``father'' of the x86 processor architecture. A single PIC has 8 interrupt lines
for external devices, but multiple PICs can be cascaded for a maximum of \(8 \cdot 8 = 64\)
interrupt lines with 9 PICs. The most common PIC configuration supports 15 IRQs with two PICs: A
slave, connected to interrupt line 2 of the master, which is connected to the CPU\footnote{This
configuration is called the \textbf{\gls{pcat pic architecture}}, as it was used in the IBM
PC/AT~\cite[sec.~1.13]{pcat}.}.
\begin{figure}[h]
\centering
\begin{subfigure}[b]{0.3\textwidth}
\includesvg[width=1.0\linewidth]{img/mp_spec_pic_configuration.svg}
\end{subfigure}
\caption{The PC/AT PIC architecture~\cite[sec.~1.13]{pcat}.}
\label{fig:pcatpic}
\end{figure}
If multiple interrupts get requested simultaneously, the PIC decides which one to service first
based on its \textbf{\gls{interrupt priority}}. The PIC IRQ priorities are determined by the used
interrupt lines, IRQ0 has the highest priority.
The PIC interrupt handling sequence can be briefly outlined as follows:
\begin{enumerate}
\item When the PIC receives an interrupt from a device (PIC interrupts are edge-triggered with high pin
polarity), it sets the corresponding bit in its \textbf{\gls{irr}}\footnote{Received IRQs that are
requesting servicing are marked in the IRR.}
\item If this interrupt is unmasked, an IRQ is sent to the CPU
\item The CPU acknowledges the IRQ
\item The PIC sets the corresponding bit in its \textbf{\gls{isr}}\footnote{IRQs that are being serviced
are marked in the ISR. To reduce confusion, interrupt service routines will be denoted as
``interrupt handler'' instead of ``ISR''.} and clears the previously set bit in the IRR. If the
same interrupt occurs again, it can now be queued a single time in the IRR\@.
\item When the interrupt has been handled by the OS, it sends an EOI to the PIC, which clears the
corresponding bit in the ISR\@.
\end{enumerate}
With the introduction of multiprocessor systems and devices with an ever-increasing need for large
amounts of interrupts (like high-performance networking hardware), the PIC reached its
architectural limits:
\begin{itemize}
\item Multiple CPU cores require sending IPIs for initialization and coordination, which is not possible
using the PIC\@.
\item The PIC is hardwired to a single CPU core. It can be inefficient to handle the entire interrupt
workload on a single core.
\item The IRQ priorities depend on how the devices are physically wired to the PIC\@.
\item The PC/AT PIC architecture only has a very limited number of interrupt lines.
\item The PIC does not support MSIs, which allow efficient handling of PCI interrupts.
\end{itemize}
\subsection{Advanced Programmable Interrupt Controller}
\label{subsec:intelapic}
The original Intel 82489DX discrete APIC was introduced with the Intel i486 processor. It consisted
of two parts: A \textbf{\gls{local apic}}, responsible for receiving special \textbf{\glspl{local
interrupt}}, and external interrupts from the second part, the \textbf{\gls{io apic}}. Unlike in
modern systems, the i486's local APIC was not integrated into the CPU core (hence ``discrete''),
see \autoref{fig:discreteapic}.
The i486 was superseded by the Intel P54C\footnote{The Intel P54C is the successor of the Intel P5,
the first Pentium processor.}, which contained an integrated local APIC for the first time, see
\autoref{fig:integratedapic}\footnote{This is now the default configuration.}.
The APIC was designed to fix the shortcomings of the PIC, specifically regarding multiprocessor
systems:
\begin{itemize}
\item Each CPU core contains its own local APIC. It has the capabilities to issue IPIs and communicate
with the chipset I/O APIC. Also, it includes the APIC timer, which can be used for per-core
scheduling.
\item The chipset I/O APIC allows configuration on a per-interrupt basis (priorities, destination,
trigger mode or pin polarity are all configurable). Also, it is able to send interrupts to
different CPU cores, allowing the efficient processing of large amounts of
interrupts\footnote{There are tools that dynamically reprogram the I/O APIC to distribute
interrupts to available CPU cores, depending on heuristics of past interrupts (IRQ-balancing).}.
\item The order in which external devices are connected to the I/O APIC is flexible.
\item The APIC architecture supports MSIs.
\end{itemize}
To allow distributing the APIC hardware between local APICs of multiple CPU cores and I/O APICs,
the APIC system sends messages over a bus. In the Intel P6 and original Pentium processors a
dedicated APIC bus is used, but since the Intel Pentium 4 and Xeon processors the chipset's system
bus is used instead (see \autoref{fig:systemvsapicbus})\footnote{The Intel Core microarchitecture
is based on the P6 architecture (replacing the Pentium 4's NetBurst architecture), but still uses
the system bus instead of a discrete bus.}. Using the system bus is considered the default in this
document.
Because the order in which external devices are connected to the interrupt controller is flexible
in the APIC architecture, but fixed in the PC/AT PIC architecture, there can be deviations in
device-to-IRQ mappings between the PIC and APIC interrupt controllers. To handle this, ACPI
provides information about how the PIC compatible interrupts (IRQ0 to IRQ15) map to ACPI's GSIs in
the MADT, which has to be taken into account by the os when operating with an APIC. The mapping
information for a single interrupt will be called \textbf{\gls{irq override}}.
There have been different revisions on the APIC architecture after the original, discrete APIC,
notably the \textbf{\gls{xapic}} and \textbf{\gls{x2apic}} architectures. This thesis is mostly
concerned about the older xApic architecture\footnote{The x2Apic architecture is backwards
compatible to the xApic architecture, also, QEMU's TCG does not support the x2Apic architecture.}.
A notable difference between xApic and x2Apic architectures is the register access: xApic uses
32-bit MMIO based register access, while x2Apic uses an MSR based register access, which allows
atomic register access to the 32- and 64-bit wide APIC control MSRs~\cite[sec.~3.11.12]{ia32}.
\section{PC/AT Compatibility}
\label{sec:pcatcompat}
For compatibility to older computer systems, two cascaded PICs are usually present in current
computer systems (see \autoref{fig:discreteapic}/\autoref{fig:integratedapic}). The local APIC can
be initialized to operate with these PICs instead of the I/O APIC, this is called
\textbf{\gls{virtual wire mode}}. It is possible to operate with both the PIC and I/O APIC as
controllers for external interrupts in ``mixed mode'', but this is very uncommon. Because the
presence of a local APIC usually guarantees the presence of an I/O APIC, this thesis only focuses
on interrupt handling with either two PICs (\textbf{\gls{pic mode}}), in case no APIC is available,
or the full APIC architecture (local APIC and I/O APIC in \textbf{\gls{symmetric io
mode}})\footnote{For more information on operating modes, consult the MultiProcessor
specification~\cite[sec.~3.6.2.1]{mpspec}.}.
To switch from PIC to symmetric I/O mode, some\footnote{References to the IMCR are only found in
the relatively old MultiProcessor specification~\cite{mpspec}.} hardware\footnote{QEMU does not
emulate the IMCR.} provides the \textbf{\gls{imcr}}, a special register that controls the physical
connection of the PIC to the CPU. In the original discrete APIC architecture, the IMCR can choose
if either the PIC or local APIC is connected to the CPU (see \autoref{fig:discreteapic}), since the
xApic architecture the IMCR only connects or disconnects the PIC to the local APIC's LINT0 pin (see
\autoref{fig:integratedapic}). When the IMCR is set to connect the PIC, and the xApic ``global
enable/disable'' flag is unset (see \autoref{subsec:lapicenable}), the system is functionally
equivalent to an IA-32 CPU without an integrated local APIC~\cite[sec.~3.11.4.3]{ia32}.
Specifics on handling PC/AT compatible external interrupts follow in \autoref{subsec:ioapicpcat}.
\section{Interrupt Handling in hhuOS}
\label{sec:currenthhuos}
In hhuOS, external interrupts are handled in two steps:
\begin{enumerate}
\item After an IRQ is sent by an interrupt controller, the CPU looks up the interrupt handler address in
the IDT. In hhuOS, every IDT entry contains the address of the \code{dispatch} function (see
\autoref{lst:irqdispatch}), which is invoked with the vector number of the interrupt.
\item The \code{dispatch} function determines which interrupt handler will be called, based on the
supplied vector number. In hhuOS, interrupt handlers are implemented through the
\code{InterruptHandler} interface (see \autoref{lst:irqhandler}), that provides the \code{trigger}
function, which contains the interrupt handling routine. To allow the \code{dispatch} function to
find the desired interrupt handler, it has to be registered to a vector number by the OS
beforehand. This process is handled by the \code{plugin} function of the interrupt handler
interface, which uses the interrupt dispatcher's \code{assign} function (see
\autoref{lst:irqassign}) to register itself to the correct vector number. HhuOS supports assigning
multiple interrupt handlers to a single interrupt vector and cascading interrupts.
\end{enumerate}
\begin{codeblock}[label=lst:irqhandler]{The InterruptHandler interface (InterruptHandler.h)~\cite{hhuos}}{C++}
\cppfile{code/interrupthandler_def.cpp}
\end{codeblock}
\begin{codeblock}[label=lst:irqassign]{Assigning an interrupt handler (InterruptDispatcher.cpp)~\cite{hhuos}}{C++}
\cppfile{code/interruptdispatcher_assign.cpp}
\end{codeblock}
\begin{codeblock}[label=lst:irqdispatch]{Triggering an interrupt handler (InterruptDispatcher.cpp)~\cite{hhuos}}{C++}
\cppfile{code/interruptdispatcher_dispatch.cpp}
\end{codeblock}
To prevent the need of interacting with a specific interrupt controller implementation (e.g.
\code{Pic} class) or the dispatcher, a system service (the \code{InterruptService}) is implemented
to expose this functionality to other parts of the OS (it allows e.g.\ registering interrupt
handlers or masking and unmasking interrupts).
Currently, hhuOS utilizes the PIT to manage the global system time (see \autoref{lst:pithandler}),
which in turn is used to trigger hhuOS's preemptive round-robin scheduler (the \code{Scheduler}
class).
\begin{codeblock}[label=lst:pithandler]{The PIT interrupt handler (Pit.cpp)~\cite{hhuos}}{C++}
\cppfile{code/pit_trigger.cpp}
\end{codeblock}
The PIT and other devices are initialized before the system entry point, in the
\code{System::initializeSystem} function.

107
chap/conclusion.tex Normal file
View File

@ -0,0 +1,107 @@
\chapter{Conclusion}
\label{ch:conclusion}
In this thesis, support for the APIC was integrated into hhuOS. The implementation supports usage
of the local APIC in combination with the I/O APIC for regular interrupt handling without the
PIC\@. Also, the APIC's included timer is used to trigger hhuOS' scheduler, and it is demonstrated
how to initialize a multiprocessor system using the APIC's IPI capabilities. All of this is
implemented with real hardware in mind, so ACPI is used to gather system information during runtime
and adapt the initialization and usage accordingly.
\clearpage
\section{Comparing PIC and APIC Implementations}
\label{sec:comparingpicapic}
Handling interrupts using the PIC is extremely simple, as seen in hhuOS' PIC implementation.
Initialization and usage can be performed by using a total of only four different registers, two
per PIC\footnote{Omitting the infrastructure that is required for both, PIC and APIC, like the IDT
or dispatcher.}.
In comparison, the code complexity required to use the APIC is very high. The most obvious reason
is its significantly increased set of features: Local interrupts are special to the APIC, also the
APIC system is made up of multiple components that require internal communication and individual
initialization. Additionally, the APIC supports advanced processor topologies with large amounts of
cores and offers increased flexibility by allowing to configure individual interrupt's vectors,
destinations, signals and priorities, which results in additional setup.
Another source of complexity that is not present with the PIC is the APIC's variability: With the
PC/AT architecture, the entire hardware interrupt configuration is known before boot. This is not
the case when using the APIC, as the amount of interrupt controllers or even the number and order
of connected devices is only known while the system is running. Parsing this information from ACPI
tables and allowing the implementation to adapt to different hardware configurations, all while
maintaining PC/AT compatibility, increases the amount of code by a large margin.
In general, all of this effort results in a much more powerful and future-proof system: It is not
limited to specific hardware configurations, allows scaling to a large amount of interrupts or
processors, and is required for multiprocessor machines, which equals to almost all modern computer
systems.
\section{Future Improvements}
\label{sec:futureimprov}
\subsection{Dependence on ACPI}
\label{subsec:acpidependance}
The APIC system requires a supplier of system information during operation, but this must not
necessarily be ACPI. Systems following Intel's ``MultiProcessor Specification''~\cite{mpspec} can
acquire the required information by parsing configuration tables similar to ACPI's system
description tables, but provided in accordance to the MultiProcessor Specification. This would
increase the amount of systems supported by this APIC implementation, but the general compatibility
improvement is difficult to quantize, as single-core systems are still supported by the old PIC
implementation\footnote{The MultiProcessor Specification was (pre-) released in
1993~\cite{mpspecpre}, the first ACPI release was in 1996~\cite{acpipre}. Multiprocessor systems
between these years would be affected.}.
Alternatively, systems that do not support ACPI could be supported partially by utilizing the local
APIC's virtual wire mode~\cite[sec.~3.6.2.2]{mpspec}. The reliance on information provided in the
MADT stems mostly from using the I/O APIC as the external interrupt controller. By using the local
APIC for its local interrupt and multiprocessor functionality, but keeping the PC/AT compatible PIC
as the external interrupt controller, multiprocessor systems without ACPI could be supported.
\subsection{Discrete APIC and x2Apic}
\label{subsec:discretex2}
This implementation only supports the xApic architecture, as it's convenient to emulate and the
x2Apic architecture is fully backwards compatible~\cite[sec.~3.11.12]{ia32}. The original, discrete
local APIC (Intel 82489DX) is not supported explicitly, which reduces this implementation's
compatibility to older systems\footnote{Although it is possible that no or only very few
modifications are necessary, as this implementation does not utilize many of the xApic's exclusive
features~\cite[sec.~3.23.27]{ia32}.}. Supporting the x2Apic architecture does not increase
compatibility, but using the x2Apic's MSR-based atomic register access is beneficial in
multiprocessor systems. Newer ACPI versions provide separate x2Apic specific structures in the
MADT~\cite[sec.~5.2.12.12]{acpi65}, so supporting x2Apic also requires supporting modern ACPI
versions\footnote{Currently, hhuOS supports ACPI 1.0b~\cite{acpi1}.}.
\subsection{PCI Devices}
\label{subsec:pcidevices}
The APIC is capable of handling MSIs, but this is not implemented in this thesis. To support PCI
devices using the APIC instead of the PIC, either support for MSIs has to be implemented, or ACPI
has to be used to determine the corresponding I/O APIC interrupt inputs. This is rather
complicated, as it requires interacting with ACPI using AML~\cite[sec.~6.2.13]{acpi65}, which needs
an according interpreter\footnote{There exist modular solutions that can be ported to the target
OS~\cite{acpica}.}.
\subsection{Multiprocessor Systems}
\label{subsec:multiprocessor}
This implementation demonstrates AP startup in SMP systems by using the APIC's IPI mechanism, but
processors are only initialized to a spin-loop. Because the APIC is a prerequisite for more
in-depth SMP support, this implementation enables more substantial improvements in this area, like
distributing tasks to different CPU cores and using the core's local APIC timer to manage a
core-local scheduler.
Another possible area of improvement is the execution of the interrupt handlers: At the moment,
each I/O APIC redirects every received interrupt to the BSP's local APIC. Distributing interrupts
to different CPU cores could improve interrupt handling performance, especially with frequent
interrupts, like from network devices. This redirection could also happen dynamically
(``IRQ-balancing''~\cite{irqbalance}), depending on interrupt workload measurements.
\subsection{UEFI Support}
\label{subsec:uefisupport}
Currently, hhuOS' ACPI system only works with BIOS, so when booting an UEFI system, this
implementation is disabled, because it requires ACPI. By supporting ACPI on UEFI systems, this
implementation could also be used for those systems, which would improve compatibility with modern
platforms.

645
chap/implementation.tex Normal file
View File

@ -0,0 +1,645 @@
\chapter{Implementation}
\label{ch:implementation}
This section will detail how and to what extent the APIC support was implemented. The steps
performed in this implementation are described in a generally applicable way, concrete
implementation details with hhuOS as an example are found in \autoref{ch:listings}.
\autoref{sec:hhuosintegration} deals with the modifications done to the hhuOS system to integrate
the APIC implementation.
\clearpage
\section{Design Decisions and Scope}
\label{sec:design}
The APIC interrupt architecture is split into multiple hardware components and tasks: The
(potentially multiple) local APICs, the (usually single) I/O APIC and the APIC timer (part of each
local APIC). Furthermore, the APIC system needs to interact with its memory mapped registers and
the hhuOS ACPI subsystem, to gather information about the CPU topology and IRQ overrides. Also, the
OS should be able to interact with the APIC system in a simple and easy manner, without needing to
know all of its individual parts.
To keep the whole system structured and simple, the implementation is split into the following main
components (see \autoref{fig:implarch}):
\begin{itemize}
\item \code{LocalApic}: Provides functionality to interact with the local APIC
(masking and unmasking, register access, etc.).
\item \code{IoApic}: Provides functionality to interact with the I/O APIC (masking and
unmasking, register access, etc.)
\item \code{ApicTimer}: Provides functionality to calibrate the APIC timer and handle its interrupts.
\item \code{Apic}: Condenses all the functionality above and exposes it to other parts
of the OS\@.
\end{itemize}
\begin{figure}[h]
\centering
\begin{subfigure}[b]{0.5\textwidth}
\includesvg[width=1.0\linewidth]{img/Architecture.svg}
\end{subfigure}
\caption{Caller hierarchy of the main components.}
\label{fig:implarch}
\end{figure}
This implementation is targeted to support systems with a single I/O APIC\footnote{Operation with
more than one I/O APIC is described further in the MultiProcessor
specification~\cite[sec.~3.6.8]{mpspec}.}, because consumer hardware typically only uses a single
one, and so does QEMU emulation. General information on implementing multiple I/O APIC support can
be found in \autoref{subsec:multiioapic}.
With the introduction of ACPI's GSIs to the OS, new types are introduced to clearly differentiate
different representations of interrupts and prevent unintentional conversions:
\begin{itemize}
\item \code{GlobalSystemInterrupt}: ACPI's interrupt abstraction, detached from the hardware
interrupt lines.
\item \code{InterruptRequest}: Represents an IRQ, allowing the OS to address interrupts by
the name of the device that triggers it. When the APIC is used, IRQ overrides map IRQs to GSIs.
\item \code{InterruptVector}: Represents an interrupt's vector number, as used by the
\code{InterruptDispatcher}. The dispatcher maps interrupt vectors to interrupt handlers.
\end{itemize}
Both BIOS and UEFI are supported by hhuOS, but the hhuOS ACPI subsystem is currently only available
with BIOS\footnote{State from 11/02/23.}, so when hhuOS is booted using UEFI, APIC support can't be
enabled. Also, the APIC can handle MSIs, but they are not included in this implementation, as hhuOS
currently does not utilize them.
SMP systems are partially supported: The APs are initialized, but only to a busy-looping state, as
hhuOS currently is a single-core OS and lacks some required infrastructure. All interrupts are
handled using the BSP\@.
Summary of features that are outside the scope of this thesis:
\begin{itemize}
\item Operation with a discrete APIC or x2Apic.
\item Interrupts with logical destinations or custom priorities.
\item Returning from APIC operation to PIC mode\footnote{This would be theoretically possible with
single-core hardware, but probably useless.}.
\item Relocation of a local APIC's MMIO memory region\footnote{Relocation is possible by writing a new
physical APIC base address to the IA32\textunderscore{}APIC\textunderscore{}BASE MSR.}.
\item Distributing external interrupts to different APs in SMP enabled systems.
\item Usage of the system's performance counter or monitoring interrupts.
\item Meaningful APIC error handling.
\item Handling of MSIs.
\end{itemize}
To be able to easily extend an APIC implementation for single-core systems to SMP systems, some
things have to be taken into account:
\begin{itemize}
\item SMP systems need to manage multiple \code{LocalApic} and \code{ApicTimer} instances. This is
handled by the \code{Apic} class.
\item Initialization of the different components can no longer happen at the same ``location'': The local
APICs and APIC timers of additional APs have to be initialized by the APs themselves, because the
BSP can not access an AP's registers.
\item APs are only allowed to access instances of APIC classes that belong to them.
\item Interrupt handlers that get called on multiple APs may need to take the current processor into
account (for example the APIC timer interrupt handler).
\item Register access has to be synchronized, if it is performed in multiple operations on the same
address space.
\end{itemize}
\section{Code Style}
\label{sec:codestyle}
Individual state of local and I/O APICs is managed through instances of their respective classes.
Because each CPU core can only access the local APIC contained in itself, this can create a
misconception: It is not possible to (e.g.) allow an interrupt in a certain local APIC by calling a
function on a certain \code{LocalApic} instance. This is communicated through code by declaring a
range of functions as \code{static}. It is also in direct contrast to the \code{IoApic} class: I/O
APICs can be addressed by instances, because they are not part of the CPU core: Each core can
always access all I/O APICs (if there are multiple).
Error checking is done to a small extent in this implementation: Publicly exposed functions (from
the \code{Apic} class) do check for invalid invocations, but the internally used classes do not
protect their invariants, because they are not used directly by other parts of the OS. These
classes only selectively expose their interfaces (by using the \code{friend} declaration) for the
same reason.
\clearpage
\section{Local APIC}
\label{sec:lapicinit}
The local APIC block diagram (see \autoref{fig:localapicblock}) shows a number of registers that
are required for initialization:
\begin{itemize}
\item \textbf{\gls{lvt}}: Used to configure how local interrupts are handled.
\item \textbf{\gls{svr}}: Contains the software-enable flag and the spurious interrupt vector number.
\item \textbf{\gls{tpr}}: Decides the order in which interrupts are handled and a possible interrupt
priority threshold, to ignore low priority interrupts.
\item \textbf{\gls{icr}}: Controls the sending of IPIs for starting up APs in SMP enabled systems.
\item \textbf{\gls{apr}}: Controls the priority in the APIC arbitration mechanism.
\end{itemize}
There are multiple registers associated with the LVT, those belong to the different local
interrupts the local APIC can handle. Local interrupts this implementation is concerned about are
listed below:
\begin{itemize}
\item LINT1: The local APIC's NMI source.
\item Timer: Periodic interrupt triggered by the APIC timer.
\item Error: Triggered by errors in the APIC system (e.g.\ invalid vector numbers or corrupted messages
in internal APIC communication).
\end{itemize}
The LINT0 interrupt is unlisted, because it is mainly important for virtual wire mode (it can be
triggered by external interrupts from the PIC). The performance and thermal monitoring interrupts
also remain unused in this implementation.
Besides the local APIC's own registers, the IMCR and \textbf{\gls{ia32 apic base msr}} also require
initialization (described in \autoref{subsec:lapicenable}).
After system power-up, the local APIC is in the following state~\cite[sec.~3.11.4.7]{ia32}:
\begin{itemize}
\item IRR, ISR and TPR are reset to \code{0x00000000}.
\item The LVT is reset to \code{0x00000000}, except for the masking bits (all local interrupts are masked
on power-up).
\item The SVR is reset to \code{0x000000FF}.
\item The APIC is in xApic mode, even if x2Apic support is present.
\item Only the BSP is enabled, other APs have to be enabled by the BSP's local APIC\@.
\end{itemize}
The initialization sequence consists of these steps:
\begin{enumerate}
\item Enable symmetric I/O mode and set the APIC operating mode.
\item Initialize the LVT and NMI\@.
\item Initialize the SVR\@.
\item Clear outstanding signals.
\item Initialize the TPR\@.
\item Initialize the APIC timer and error handler.
\item Startup the APs and initialize their respective local APICs.
\item Synchronize the APRs.
\end{enumerate}
\subsection{Accessing Local APIC Registers in xApic Mode}
\label{subsec:xapicregacc}
Accessing registers in xApic mode is done via MMIO and requires a single page (4 KB) of memory,
mapped to the ``APIC Base'' address, which can be obtained by reading the
IA32\textunderscore{}APIC\textunderscore{}BASE MSR (see
\autoref{fig:ia32apicbasemsr}/\autoref{tab:lapicregsmsr}) or parsing the MADT (see
\autoref{tab:madt}). The IA-32 manual specifies a caching strategy of ``strong
uncachable''\footnote{See IA-32 manual for information on this caching
strategy~\cite[sec.~3.12.3]{ia32}.}~\cite[sec.~3.11.4.1]{ia32} for this region (see
\autoref{sec:apxxapicregacc} for the example implementation).
The address offsets (from the base address) for the local APIC registers are listed in the IA-32
manual~\cite[sec.~3.11.4.1]{ia32} and in \autoref{tab:lapicregs}.
\subsection{Enabling the Local APIC}
\label{subsec:lapicenable}
The following steps have to be executed before any interrupt handling has been enabled by the OS\@.
Because the system boots in PIC mode, \code{0x01} should be written to the
IMCR~\cite[sec.~3.6.2.1]{mpspec} to disconnect the PIC from the local APIC's LINT0 pin (see
\autoref{fig:integratedapic}, for the example implementation see \autoref{sec:apxdisablepic}).
To set the operating mode, it is first determined which modes are supported by executing the
\code{cpuid} instruction with \code{eax=1}: If bit 9 of the \code{edx} register is set, xApic mode
is supported, if bit 21 of the \code{ecx} register is set, x2Apic mode is
supported~\cite[sec.~5.1.2]{cpuid}.
If xApic mode is supported (if the local APIC is an integrated APIC), it will be in that mode
already. The ``global enable/disable'' (``EN'') bit in the
IA32\textunderscore{}APIC\textunderscore{}BASE MSR (see
\autoref{fig:ia32apicbasemsr}/\autoref{tab:lapicregsmsr}) allows disabling xApic mode, and thus the
entire local APIC, globally\footnote{If the system uses the discrete APIC bus, xApic mode cannot be
re-enabled without a system reset~\cite[sec.~3.11.4.3]{ia32}.}.
Enabling x2Apic mode is done by setting the ``EXTD'' bit (see
\autoref{fig:ia32apicbasemsr}/\autoref{tab:lapicregsmsr}) of the
IA32\textunderscore{}APIC\textunderscore{}BASE MSR~\cite[sec.~3.11.4.3]{ia32}.
\begin{figure}[h]
\centering
\begin{subfigure}[b]{0.7\textwidth}
\includesvg[width=1.0\linewidth]{img/ia32_apic_base_msr.svg}
\end{subfigure}
\caption{The IA32\textunderscore{}APIC\textunderscore{}BASE MSR~\cite[sec.~3.11.4.4]{ia32}.}
\label{fig:ia32apicbasemsr}
\end{figure}
Because QEMU does not support x2Apic mode via its TCG\footnote{QEMU Tiny Code Generator transforms
target instructions to instructions for the host CPU.}, this implementation only uses xApic mode.
Besides the ``global enable/disable'' (``EN'') flag, the APIC can also be enabled/disabled by using
the ``software enable/disable'' flag in the SVR, see \autoref{subsec:lapicsoftenable}.
\subsection{Handling Local Interrupts}
\label{subsec:lapiclvtinit}
To configure how the local APIC handles the different local interrupts, the LVT registers are
written (see \autoref{fig:localapiclvt}).
Local interrupts can be configured to use different delivery modes
(excerpt)~\cite[sec.~3.11.5.1]{ia32}:
\begin{itemize}
\item Fixed: Simply delivers the interrupt vector stored in the LVT register.
\item NMI: Configures this interrupt as non-maskable, this ignores the stored vector number.
\item ExtINT: The interrupt is treated as an external interrupt (instead of local interrupt), used e.g.\
in virtual wire mode for LINT0.
\end{itemize}
Initially, all local interrupts are initialized to PC/AT defaults: Masked, edge-triggered,
active-high and with ``fixed'' delivery mode. Most importantly, the vector fields (bits 0:7 of an
LVT register) are set to their corresponding interrupt vector (see \autoref{sec:apxlvtinit} for an
example implementation).
After default-initializing the local interrupts, LINT1 has to be configured separately (see
\autoref{tab:lapicregslvtlint}), because it is the local APIC's NMI source\footnote{In older
specifications~\cite{mpspec}, LINT1 is defined as NMI source (see \autoref{fig:integratedapic}). It
is possible that this changed with newer architectures, so for increased compatibility this
implementation configures the local APIC NMI source as reported by ACPI. It is also possible that
ACPI reports information on the NMI source just for future-proofing.}. The delivery mode is set to
``NMI'' and the interrupt vector to \code{0x00}. This information is also provided by ACPI in the
MADT (see \autoref{tab:madtlnmi}). Other local interrupts (APIC timer and the error interrupt) will
be configured later (see \autoref{subsec:lapictimer} and \autoref{subsec:lapicerror}).
\subsection{Allowing Interrupt Processing}
\label{subsec:lapicsoftenable}
To complete a minimal local APIC initialization, the ``software enable/disable'' flag and the
spurious interrupt vector (both contained in the SVR, see
\autoref{fig:ia32apicsvr}/\autoref{tab:lapicregssvr}), are set. It makes sense to choose
\code{0xFF} for the spurious interrupt vector, as on P6 and Pentium processors, the lowest 4 bits
must be set (see \autoref{fig:ia32apicsvr}).
\begin{figure}[h]
\centering
\begin{subfigure}[b]{0.7\textwidth}
\includesvg[width=1.0\linewidth]{img/ia32_apic_svr.svg}
\end{subfigure}
\caption{The local APIC SVR register~\cite[sec.~3.11.9]{ia32}.}
\label{fig:ia32apicsvr}
\end{figure}
Because the APIC's spurious interrupt has a dedicated interrupt vector (unlike the PIC's spurious
interrupt), it can be ignored easily by registering a stub interrupt handler for the appropriate
vector (see \autoref{sec:apxsvr} for an implementation example).
The final step to initialize the BSP's local APIC is to allow the local APIC to receive interrupts
of all priorities. This is done by writing \code{0x00} to the TPR~\cite[sec.~3.11.8.3]{ia32} (see
\autoref{tab:lapicregstpr}). By configuring the TPRs of different local APICs to different
priorities or priority classes, distribution of external interrupts to CPUs can be controlled, but
this is not used in this thesis.
\subsection{Local Interrupt EOI}
\label{subsec:lapiceoi}
To notify the local APIC that a local interrupt has been handled, its EOI register (see
\autoref{tab:lapicregseoi}) has to be written. Not all local interrupts require EOIs: NMI, SMI,
INIT, ExtINT, STARTUP, or INIT-Deassert interrupts are excluded~\cite[sec.~3.11.8.5]{ia32}.
EOIs for external interrupts are also handled by the local APIC, this is described in
\autoref{subsec:ioapiceoi}.
\subsection{APIC Timer}
\label{subsec:lapictimer}
The APIC timer is integrated into the local APIC, so it requires initialization of the latter. Like
the PIT, the APIC timer can generate periodic interrupts in a specified interval by using a
counter, that is initialized with a starting value depending on the desired interval. Because the
APIC timer doesn't tick with a fixed frequency, but at bus frequency, the initial counter has to be
determined at runtime by using an external time source. In addition to the counter register, the
APIC timer interval is influenced by a divider: Instead of decrementing the counter at every bus
clock, it will be decremented every \(n\)-th bus clock, where \(n\) is the divider. This is useful
to allow for long intervals (with decreased precision), that would require a larger counter
register otherwise.
The APIC timer supports three different timer modes, that can be set in the timer's LVT register:
\begin{enumerate}
\item Oneshot: Trigger exactly one interrupt when the counter reaches zero.
\item Periodic: Trigger an interrupt each time the counter reaches zero, on zero the counter reloads its
initial value.
\item TSC-Deadline: Trigger exactly one interrupt at an absolute time.
\end{enumerate}
This implementation uses the APIC timer in periodic mode, to trigger the scheduler preemption.
Initialization requires the following steps (order recommended by OSDev~\cite{osdev}):
\begin{enumerate}
\item Measure the timer frequency with an external time source.
\item Configuration of the timer's divider register (see \autoref{tab:lapicregstimerdiv}).
\item Setting the timer mode to periodic (see \autoref{tab:lapicregslvtt}).
\item Initializing the counter register (see \autoref{tab:lapicregstimerinit}), depending on the measured
timer frequency and the desired interval.
\end{enumerate}
In this implementation, the APIC timer is calibrated by counting the amount of ticks in one
millisecond using oneshot mode (see \autoref{sec:apxapictimer} for an example implementation). The
measured amount of timer ticks can then be used to calculate the required counter for an arbitrary
millisecond interval, although very large intervals could require the use of a larger divider,
while very small intervals (in micro- or nanosecond scale) could require the opposite, to provide
the necessary precision. For this approach it is important that the timer is initialized with the
same divider that was used during calibration.
To use the timer, an interrupt handler has to be registered to its interrupt vector (see
\autoref{sec:apxapictimer} for an example implementation).
\subsection{APIC Error Interrupt}
\label{subsec:lapicerror}
Errors can occur for example when the local APIC receives an invalid vector number, or an APIC
message gets corrupted on the system bus. To handle these cases, the local APIC provides the local
error interrupt, whose interrupt handler can read the error status from the local APIC's
\textbf{\gls{esr}} (see \autoref{fig:ia32esr}/\autoref{tab:lapicregsesr}) and take appropriate
action.
\begin{figure}[h]
\centering
\begin{subfigure}[b]{0.7\textwidth}
\includesvg[width=1.0\linewidth]{img/ia32_error_status_register.svg}
\end{subfigure}
\caption{Error Status Register~\cite[sec.~3.11.5.3]{ia32}.}
\label{fig:ia32esr}
\end{figure}
The ESR is a ``write/read'' register: Before reading a value from the ESR, it has to be written,
which updates the ESR's contents to the error status since the last write. Writing the ESR also
arms the local error interrupt again~\cite[sec.~3.11.5.3]{ia32}.
Enabling the local error interrupt is now as simple as enabling it in the local APIC's LVT and
registering an interrupt handler for the appropriate vector (see \autoref{sec:apxhandlingerror} for
an example implementation).
\clearpage
\section{I/O APIC}
\label{sec:ioapicinit}
% TODO: Continue moving code to the appendix from here on
To fully replace the PIC and handle external interrupts using the APIC, the I/O APIC, located in
the system chipset, has to be initialized by setting its \textbf{\gls{redtbl}}
registers~\cite[sec.~9.5.8]{ich5} (see \autoref{tab:ioapicregsredtbl}). Like the local APIC's LVT,
the REDTBL allows configuration of interrupt vectors, masking bits, interrupt delivery modes, pin
polarities and trigger modes (see \autoref{subsec:lapiclvtinit}).
Additionally, for external interrupts a destination and destination mode can be specified. This is
required because the I/O APIC is able to forward external interrupts to different local APICs over
the system bus (see \autoref{fig:integratedapic}). SMP systems use this mechanism to distribute
external interrupts to different CPU cores for performance benefits. Because this implementation's
focus is not on SMP, all external interrupts are default initialized to ``physical'' destination
mode\footnote{The alternative is "logical" destination mode, which allows addressing individual or
clusters of local APIC's in a larger volume of
processors~\cite[sec.~3.11.6.2.2]{ia32}.}~\cite[sec.~3.11.6.2.1]{ia32} and are sent to the BSP for
servicing, by using the BSP's local APIC ID as the destination. The other fields are set to
\textbf{\gls{isa}} bus defaults\footnote{Edge-triggered, active-high.}, with ``fixed'' delivery
mode, masked, and the corresponding interrupt vector, as defined by the \code{InterruptVector}
enum.
The I/O APIC does not have to be enabled explicitly, if the local APIC is enabled and the REDTBL is
initialized correctly, external interrupts will be redirected to the local APIC and handled by the
CPU\@.
Unlike the local APIC's registers, the REDTBL registers are accessed indirectly: Two registers, the
``Index'' and ``Data'' register~\cite[sec.~9.5.1]{ich5}, are mapped to the main memory and can be
used analogous to the local APIC's registers. The MMIO base address can be parsed from the MADT
(see \autoref{tab:madtioapic}). Writing an offset to the index register exposes an indirectly
accessible I/O APIC register through the data register (see \autoref{sec:iolistings} for an example
implementation). This indirect addressing scheme is useful, because the number of external
interrupts an I/O APIC supports, and in turn the number of REDTBL registers, can
vary\footnote{Intel's consumer \textbf{\glspl{ich}} always support a fixed amount of 24 external
interrupts though~\cite[sec.~9.5.7]{ich5}.}.
It is possible that one or multiple of the I/O APIC's interrupt inputs act as an NMI source. If
this is the case is reported in the MADT (see \autoref{tab:madtionmi}), so when necessary, the
corresponding REDTBL entries are initialized like the local APIC's NMI source (see
\autoref{subsec:lapiclvtinit}), and using these interrupt inputs for external interrupts is
forbidden.
\subsection{Interrupt Overrides}
\label{subsec:ioapicpcat}
In every PC/AT compatible system, external devices are hardwired to the PIC in the same order.
Because this is not the case for the I/O APIC, the interrupt line used by each PC/AT compatible
interrupt has to be determined by the OS at runtime, by using ACPI. ACPI provides ``Interrupt
Source Override'' structures~\cite[sec.~5.2.8.3.1]{acpi1} inside the MADT (see
\autoref{tab:madtirqoverride}) for each PC/AT compatible interrupt that is mapped differently to
the I/O APIC than to the PIC\@.
In addition to the interrupt input mapping, these structures also allow to customize the pin
polarity and trigger mode of PC/AT compatible interrupts.
This information does not only apply to the REDTBL initialization, but it has to be taken into
account every time an action is performed on a PC/AT compatible interrupt, like masking or
unmasking: If \code{IRQ0} (PIT) should be unmasked, it has to be determined what GSI (or in other
words, I/O APIC interrupt input) it belongs to. In many systems \code{IRQ0} is mapped to
\code{GSI2}, because the PC/AT compatible PICs are connected to \code{GSI0}. Thus, to allow the PIT
interrupt in those systems, the REDTBL entry belonging to \code{GSI2} instead of \code{GSI0} has to
be written (see \autoref{sec:apxirqoverrides} for an example implementation).
\subsection{External Interrupt EOI}
\label{subsec:ioapiceoi}
Notifying the I/O APIC that an external interrupt has been handled differs depending on the
interrupt trigger mode: Edge-triggered external interrupts are completed by writing the local
APIC's EOI register (see \autoref{subsec:lapiceoi})\footnote{Because external interrupts are
forwarded to the local APIC, the local APIC is responsible for tracking them in its IRR and ISR.}.
Level-triggered interrupts are treated separately: Upon registering a level-triggered external
interrupt, the I/O APIC sets an internal ``Remote IRR'' bit in the corresponding REDTBL
entry~\cite[sec.~9.5.8]{ich5} (see \autoref{tab:ioapicregsredtbl}).
There are three possible ways to signal completion of a level-triggered external interrupt to clear
the remote IRR bit:
\begin{enumerate}
\item Using the local APIC's EOI broadcasting feature: If EOI broadcasting is enabled, writing the local
APIC's EOI register also triggers EOIs for each I/O APIC (for the appropriate interrupt), which
clears the remote IRR bit.
\item Sending a directed EOI to an I/O APIC: I/O APICs with versions greater than \code{0x20} include an
I/O EOI register. Writing the vector number of the handled interrupt to this register clears the
remote IRR bit.
\item Simulating a directed EOI for I/O APICs with versions smaller than \code{0x20}: Temporarily masking
and setting a completed interrupt as edge-triggered clears the remote IRR
bit~\cite[io\textunderscore{}apic.c]{linux}.
\end{enumerate}
Because the first option is the only one supported by all APIC versions, it is used in this
implementation\footnote{Disabling EOI broadcasting is not supported by all local
APICs~\cite[sec.~3.11.8.5]{ia32}.}.
At this point, after initializing the local and I/O APIC for the BSP, the APIC system is fully
usable. External interrupts now have to be enabled/disabled by writing the ``masked'' bit in these
interrupts' REDTBL entries, interrupt handler completion is signaled by writing the local APIC's
EOI register, and spurious interrupts are detected by using the local APIC's spurious interrupt
vector.
\subsection{Multiple I/O APICs}
\label{subsec:multiioapic}
Most consumer hardware, for example all IA processors~\cite{ia32} and ICH hubs~\cite{ich5}, only
provide a single I/O APIC, although technically multiple I/O APICs are supported by the
MultiProcessor specification~\cite[sec.~3.6.8]{mpspec}.
If ACPI reports multiple I/O APICs (by supplying multiple MADT I/O APIC structures, see
\autoref{tab:madtioapic}), the previously described initialization has to be performed for each I/O
APIC individually. Additionally, the I/O APIC's ID, also reported by ACPI, has to be written to the
corresponding I/O APIC's ID register (see \autoref{tab:ioapicregsid}), because this register is
always initialized to zero~\cite[sec.~9.5.6]{ich5}.
Using a variable number of I/O APICs requires determining the target I/O APIC for each operation
that concerns a GSI, like masking or unmasking. For this reason, ACPI provides the ``GSI
Base''~\cite[sec.~5.2.8.2]{acpi1} for each available I/O APIC, the number of GSIs a single I/O APIC
can handle can be determined by reading the I/O APIC's version register~\cite[sec.~9.5.7]{ich5}
(see \autoref{tab:ioapicregsver})\footnote{This approach was previously used in this
implementation, but removed for simplicity.}.
\clearpage
\section{Symmetric Multiprocessing}
\label{sec:smpinit}
Like single-core systems, SMP systems boot using only a single core, the BSP. By using the APIC's
capabilities to send IPIs between cores, additional APs can be put into startup state and booted
for system use.
To determine the amount of usable processors, the MADT is parsed (see \autoref{tab:madtlapic}).
Note, that some processors may be reported as disabled, those may not be used by the OS (see
\autoref{tab:madtlapicflags}).
\subsection{Inter-Processor Interrupts}
\label{subsec:ipis}
Issuing IPIs works by writing the local APIC's ICR (see
\autoref{fig:ia32icr}/\autoref{tab:lapicregsicr}). It allows specifying IPI type, destination
(analogous to REDTBL destinations, see \autoref{sec:ioapicinit}) and vector (see
\autoref{sec:apxipis} for an example implementation).
Depending on the APIC architecture, two different IPIs are required: The INIT IPI for systems using
a discrete APIC, and the \textbf{\gls{sipi}} for systems using the xApic or x2Apic architectures:
\begin{itemize}
\item The INIT IPI causes an AP to reset its state and start executing at the address specified at its
system reset vector. If paired with a system warm-reset, the AP can be instructed to start
executing the AP boot sequence by writing the appropriate address to the warm-reset
vector~\cite[sec.~B.4.1]{mpspec}.
\item Since the xApic architecture, the SIPI is used for AP startup: It causes the AP to start executing
code in real mode, at a page specified in the IPIs interrupt vector~\cite[sec.~B.4.2]{mpspec}. By
copying the AP boot routine to a page in lower physical memory, and sending the SIPI with the
correct page number, an AP can be booted.
\end{itemize}
To wait until the IPI is sent, the ICR's delivery status bit can be polled.
\begin{figure}[h]
\centering
\begin{subfigure}[b]{0.7\textwidth}
\includesvg[width=1.0\linewidth]{img/ia32_interrupt_command_register.svg}
\end{subfigure}
\caption{Interrupt Command Register~\cite[sec.~3.11.6.1]{ia32}.}
\label{fig:ia32icr}
\end{figure}
\subsection{Universal Startup Algorithm}
\label{subsec:apstartup}
SMP initialization is performed differently on various processors. Intel's MultiProcessor
specification defines a ``universal startup algorithm'' for multiprocessor
systems~\cite[sec.~B.4]{mpspec}, which can be used to boot SMP systems with either discrete APIC,
xApic or x2Apic, as it issues both, INIT IPI and SIPI\footnote{Technically, it always issues the
INIT IPI, and the SIPI only for xApic or x2Apic, but since the SIPI is ignored by discrete APICs,
it can be sent either way. This ``INIT-SIPI-SIPI'' sequence is also stated in the IA-32
manual~\cite[sec.~3.9.4]{ia32}.}.
This algorithm has some prerequisites: It is required to copy the AP boot routine (detailed in
\autoref{subsec:apboot}) to lower memory, where the APs will start their execution. Also, the APs
need allocated stack memory to call the entry function, and in case of a discrete APIC that uses
the INIT IPI, the system needs to be configured for a warm-reset (by writing \code{0xAH} to the
CMOS shutdown status byte, located at \code{0xF}~\cite[sec.~B.4]{mpspec}), because the INIT IPI
does not support supplying the address where AP execution should begin, unlike the SIPI. The
warm-reset vector (a 32-bit field, located at physical address
\code{40:67}~\cite[sec.~B.4]{mpspec}) needs to be set to the physical address the AP startup
routine was copied to. Additionally, the entire AP startup procedure has to be performed with all
sources of interrupts disabled, which offers a small challenge, since some timings need to be taken
into account\footnote{This implementation uses the PIT's mode 0 on channel 0 for timekeeping.}.
The usage of delays in the algorithm is quite specific, but the specification provides no further
information on the importance of these timings or required precision. The algorithm allowed for
successful startup of additional APs when tested in QEMU (with and without KVM) and on certain real
hardware, although for different processors or emulators (like Bochs), different timings might be
required~\cite[lapic.c]{xv6}.
After preparation, the universal startup algorithm is now performed as follows, for each AP
sequentially (see \autoref{sec:apxmpusa} for an example implementation):
\begin{enumerate}
\item Assert and de-assert the level-triggered INIT IPI\@.
\item Delay for 10 milliseconds.
\item Send the SIPI\@.
\item Delay for 200 microseconds.
\item Send the SIPI again.
\item Delay for 200 microseconds again.
\item Wait until the AP has signaled boot completion, then continue to the next.
\end{enumerate}
If the system uses a discrete APIC, the APs will reach the boot routine by starting execution at
the location specified in the warm-reset vector, if the system uses the xApic or x2Apic
architecture, the APs will reach the boot routine because its location was specified in the SIPI\@.
Signaling boot completion from the APs entry function can be done by using a global bitmap
variable, where the \(n\)-th bit indicates the running state of the \(n\)-th processor. This
variable does not have to be synchronized across APs, because the startup is performed
sequentially.
\subsection{Application Processor Boot Routine}
\label{subsec:apboot}
After executing the ``INIT-SIPI-SIPI'' sequence, the targeted AP will start executing its boot
routine in real mode. The general steps required are similar to those required when booting a
single-core system, but since the BSP in SMP systems is already fully operational at this point,
much can be recycled. The AP boot routine this implementation uses can be roughly described as
follows (see \autoref{sec:apxapboot} for an example implementation):
\begin{enumerate}
\item Load a temporary \textbf{\gls{gdt}}, used for switching to protected mode.
\item Enable protected mode by writing \code{cr0}.
\item Far jump to switch to protected mode and reload the code-segment register, set up the other
segments manually.
\item Load the \code{cr3}, \code{cr0} and \code{cr4} values used by the BSP to enable paging (in that
order).
\item Load the IDT used by the BSP\@.
\item Determine the AP's APIC ID by using CPUID\@.
\item Load the GDT and \textbf{\gls{tss}} prepared for this AP\@.
\item Load the stack prepared for this AP\@.
\item Call the (C++) AP entry function.
\end{enumerate}
The APIC ID is used to determine which GDT and stack were prepared for a certain AP\@. It is
necessary for each AP to have its own GDT, because each processor needs its own TSS for context
switching, for example when interrupt-based system calls are used on all CPUs.
Because it is relocated into lower physical memory (in this implementation to \code{0x8000}), this
code has to be position independent. For this reason, absolute physical addresses have to be used
when jumping, loading the IDTR and GDTR, or referencing variables. Also, any variables required
during boot have to be available after relocation, this can be achieved by locating them inside the
``TEXT'' section of the routine, so they stay with the rest of the instructions when copying. These
variables have to be initialized during runtime, before the routine is copied (see
\autoref{sec:apxpreparesmp} for an example implementation).
\subsection{Application Processor Post-Boot Routine}
\label{subsec:apsystementry}
In the entry function, called at the end of the boot routine, the AP signals boot completion as
described in \autoref{subsec:apstartup} and initializes its local APIC by repeating the necessary
steps from \autoref{subsec:lapiclvtinit}, \autoref{subsec:lapicsoftenable},
\autoref{subsec:lapictimer} and \autoref{subsec:lapicerror}\footnote{MMIO memory does not have to
be allocated again, as all local APICs use the same memory region in this implementation. Also, the
initial value for the APIC timer's counter can be reused, if already calibrated.}.
Because multiple local APICs are present and active in the system now, the possibility arises that
a certain local APIC receives multiple messages from different local APICs at a similar time. To
decide the order of handling these messages, an arbitration mechanism based on the local APIC's ID
is used~\cite[sec.~3.11.7]{ia32}. To make sure the arbitration priority matches the local APIC's
ID, the ARPs can be synchronized by issuing an INIT-level-deassert IPI\footnote{This is not
supported on Pentium 4 and Xeon processors.} (see \autoref{sec:apxappostboot} for an example
implementation).
\clearpage

26
chap/introduction.tex Normal file
View File

@ -0,0 +1,26 @@
\chapter{Introduction}
\label{ch:introduction}
Computer systems are very useful, because they are able to interact with the ``outside world'', for
instance by reading values from sensors, controlling external appliances or interacting with a user
through human interface devices. In each of these scenarios, the system's CPU has to react to
``external changes'', like a key press or sensor reading. An efficient hardware solution to this
problem are ``interrupts''.
In this thesis, support for the ``APIC'', a modern and widely used interrupt controller
architecture, introduced by Intel for the Pentium 4 processor, will be implemented into hhuOS, ``A
small operating system for learning purposes''~\cite{hhuos}. This support will cover a complete
replacement of the older ``PIC'' interrupt controller, introduction of an alternative timer - a
part of the APIC architecture - for scheduling, and utilizing the APIC to boot multiprocessor
systems.
The following chapter explains important background concepts, in \autoref{ch:implementation} the
required steps to use the APIC and their implementation are explained in general,
\autoref{ch:verification} deals with the verification process of the developed software on emulated
and real hardware, and \autoref{ch:conclusion} draws conclusions regarding the previous
implementation and future improvements.
Specific details on the code created during this thesis are given in \autoref{ch:listings},
separated from the main body.
\clearpage

82
chap/verification.tex Normal file
View File

@ -0,0 +1,82 @@
\chapter{Verification}
\label{ch:verification}
Common techniques for testing software include component-based tests, like ``unit tests'', and
``end-to-end tests'', where the complete functionality of a software system with all its parts is
tested. As unit testing is mostly suitable for independent slices of a system's application logic,
it is not very useful for testing low-level software designed to run directly on hardware devices.
This chapter deals with the process and results of testing hhuOS with the APIC implementation
developed during this thesis.
\clearpage
\section{Methods of Verification}
\label{sec:verificationmethods}
This application can be tested by running the entire hhuOS operating system on both emulated and
real hardware, and monitoring its state of operation\footnote{There is almost no logic that can be
tested isolated or hardware independently.}.
This can be done in multiple ways:
\begin{itemize}
\item When running hhuOS in an emulated environment, the current machine state can be inspected
directly\footnote{QEMU offers the ``QEMU monitor'' to query information about specific hardware
components, like the local or I/O APIC (\code{info lapic} and \code{info pic}).}.
\item To test the functionality of an interrupt controller specifically, stub interrupt handlers can be
used to verify that a specific interrupt (like an IPI) has been registered.
\item By attaching a debugger (very simple for emulated hardware), it can be observed that e.g.\ the
timer interrupt is correctly increasing the timestamp for each running CPU\@.
\item By exposing some of the APIC's internal data through hhuOS' virtual file system, end-to-end
verification can be performed from the system itself, as debugging and monitoring is significantly
more difficult when running on real hardware.
\item Because the interrupt controller is a vital part for many components of an operating system,
observing a successful boot is already a significant indicator for a correct implementation.
\end{itemize}
\section{Results}
\label{sec:verificationresults}
QEMU was used as the main development platform, the implemented features were tested by using the
QEMU monitor. Specifically, QEMU provides the current register state of all local and I/O APICs, by
attaching a debugger to the running operating system correct behavior was observed on the emulated
hardware level:
\begin{itemize}
\item Working local interrupts - verified by observing the local APIC's IRR\@.
\item Propagation of interrupts to the CPU - verified by observing the local APIC's ISR\@.
\item A working local APIC timer - verified by observing the APIC timer's registers.
\end{itemize}
Although hhuOS is developed mainly for learning purposes, every OS' core task remains to be the
management of computer hardware. For this reason this implementation was additionally tested on a
``ThinkPad T60s'' with an Intel ``Core 2 Duo'' processor. By providing internal status data through
the virtual file system, implemented features (including booting additional APs) were verified on
this very specific set of hardware.
More specifically, information about detected and enabled local APICs and the I/O APIC, register
values from the BSP's LVT and the REDTBL, the contents of the PIC's \textbf{\gls{imr}}, and amounts
of occurred interrupts by core (similar to \code{/proc/interrupts} in Linux~\cite{linux}]) are
exposed on the path \code{/device/apic/}. This way, the following things could be verified on real
hardware:
\begin{itemize}
\item The APIC is indeed used instead of the PIC - verified by observing the PIC's IMR\@.
\item Successful MMIO for local and I/O APIC - verified by observing the LVT and REDTBL\@.
\item Devices ``plugging in'' to the APIC instead of the PIC - verified by observing the LVT and
REDTBL\@.
\item Interrupt handlers are called correctly - verified by using the keyboard.
\item Working startup of additional APs - verified by checking the state of the AP's local APICs and
observing the system log.
\item Handling interrupts on another AP - verified by redirecting the keyboard interrupt to another
processor and observing the number of occurred keyboard interrupts on this
processor\footnote{Interestingly, this was easier to verify on real hardware than in QEMU, because
QEMU usually instantly crashes when interrupts are enabled on an AP beside the BSP. Also,
redirecting the keyboard interrupt in QEMU significantly changes the behaviour of any key press and
renders the keyboard unusable. This is expected, as hhuOS' paging is not designed for multiple
processors. On the ThinkPad T60s though, it was possible (surprisingly) to use the redirected
keyboard interrupt to \code{cat} the \code{/device/apic/irqs} file to observe the interrupt
statistics, which showed the keyboard interrupts arriving on a different core than the BSP. After a
certain time, the system crashes on the ThinkPad aswell.}.
\end{itemize}

748
class/thesis.cls Normal file
View File

@ -0,0 +1,748 @@
% @file thesis.cls
%
% @brief Document class for theses.
%
% @author Stefan Nothaas, Arbeitsgruppe Betriebssysteme, Institut für Informatik, HHU Düsseldorf
% @author Filip Krakowski, Arbeitsgruppe Betriebssyteme, Institut für Informatik, HHU Düsseldorf
%
% @since 2021/04/29 (major refactoring, minted, university logo)
% @since 2019/04/29 (bugfix, wrong page number for reference section)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{class/thesis}[2021/04/29 Template for theses]
% Use book class as base
\LoadClass[12pt,twoside,a4paper]{book}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Packages
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\RequirePackage[left=3cm,right=2.5cm,top=3cm,bottom=2.5cm]{geometry}
\RequirePackage[utf8]{inputenc}
\RequirePackage[T1]{fontenc}
\RequirePackage[english,ngerman]{babel}
\RequirePackage{mathtools}
% \RequirePackage{amssymb} % Produces some errors I don't understand
\RequirePackage[minted]{tcolorbox}
% \RequirePackage{minted}
\RequirePackage{fancyhdr} % For headers
\RequirePackage{color}
% \RequirePackage[usenames,dvipsnames]{xcolor} % Option Clash, already loaded by sth else
\RequirePackage{graphicx}
\RequirePackage{tikz}
\RequirePackage{subcaption} % Floats in floats
\RequirePackage{float}
\RequirePackage{multirow} % For tables
% \RequirePackage{todonotes}
\RequirePackage{hyperref} % [hidelinks]
\RequirePackage{algorithm2e}
\RequirePackage{tocloft}
\RequirePackage{listings}
\RequirePackage{textcomp}
\RequirePackage{ifthen}
\RequirePackage{pgf} % Not sure if pgf was meant, but pgffor doesn't exist (at least not in my texlive?)
\RequirePackage{enumitem}
% Some additions
% Borders around svg figures
\RequirePackage{svg}
\RequirePackage{float}
\floatstyle{boxed}
\restylefloat{figure}
\RequirePackage{csquotes}
\RequirePackage{tabularx}
% Extra chapters
\RequirePackage[acronym,automake,nonumberlist,nogroupskip]{glossaries} % Must be loaded after hyperref, [toc]
\RequirePackage[page]{appendix} % [toc]
% \RequirePackage{tocbibind} % Add lists to toc, still needs [heading=bibintoc] for some reason, [nottoc]?
% Font
\RequirePackage{beton} % Computer Concrete font
\DeclareFontSeriesDefault[rm]{bf}{sbc} % Computer Concrete does not have bold font
\RequirePackage{eulerpx} % Math font
\RequirePackage{inconsolata} % Code font
% Group listings by chapter, pretocmd prepends something to a command
\RequirePackage{etoolbox}
\pretocmd{\chapter}{\addtocontents{listings}{\protect\addvspace{10pt}}}{}{}
% Control lot/lof parskip
\RequirePackage{tocloft}
% Allow referencing subsubsections (don't have those anymore)
% \setcounter{secnumdepth}{3}
% \setcounter{tocdepth}{3}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Package settings
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\tcbuselibrary{skins, breakable}
\usetikzlibrary{shadings, backgrounds}
\fancypagestyle{plain}{%
\fancyhf{}
\renewcommand{\headrulewidth}{0pt}
\fancyfoot[RO,LE]{\thepage}
}
\fancypagestyle{thesis}{%
\fancyhf{}
\renewcommand{\headrulewidth}{0.4pt}
\fancyfoot[RO,LE]{\thepage}
\fancyhead[LO,RE]{\slshape \leftmark}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Bibliography
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\RequirePackage[style=ieee,backend=biber]{biblatex}
\addbibresource{references.bib}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Translations
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\translatemastersthesis}{}
\newcommand{\translatebachelorsthesis}{}
\newcommand{\translateprojectwork}{}
\newcommand{\translateprimaryreviewer}{}
\newcommand{\translatesecondaryreviewer}{}
\newcommand{\translatesupervisor}{}
\newcommand{\translatesubmittedby}{}
\newcommand{\translatefrom}{}
\newcommand{\translateuniversityname}{}
\newcommand{\translatedepartment}{}
\newcommand{\translatedeclaration}{}
\newcommand{\translatedeclarationtitle}{}
\addto\captionsenglish{
\SetAlgorithmName{Algorithm}{Algorithm}{List of Algorithms}
\renewcommand{\chaptername}{Chapter}
\renewcommand{\translatemastersthesis}{Master's Thesis}
\renewcommand{\translatebachelorsthesis}{Bachelor's Thesis}
\renewcommand{\translateprojectwork}{Project Work}
\renewcommand{\translateprimaryreviewer}{Primary Reviewer}
\renewcommand{\translatesecondaryreviewer}{Secondary Reviewer}
\renewcommand{\translatesupervisor}{Supervisor}
\renewcommand{\translatesubmittedby}{submitted by}
\renewcommand{\translatefrom}{from}
\renewcommand{\translateuniversityname}{Heinrich Heine University Düsseldorf}
\renewcommand{\translatedepartment}{Department Operating Systems}
\renewcommand{\translatedeclarationtitle}{Statutory Declaration}
\renewcommand{\translatedeclaration}{I hereby state that I have written this {\thesistypename} independently and that I have not used any sources or aids other than those declared. All passages taken from the literature have been marked as such. This thesis has not yet been submitted to any examination authority in the same or a similar form.}
}
\addto\captionsngerman{
\SetAlgorithmName{Algorithmus}{Algorithmus}{Algorithmenverzeichniss}
\renewcommand{\chaptername}{Kapitel}
\renewcommand{\translatemastersthesis}{Masterarbeit}
\renewcommand{\translatebachelorsthesis}{Bachelorarbeit}
\renewcommand{\translateprojectwork}{Projektarbeit}
\renewcommand{\translateprimaryreviewer}{Erstgutachter}
\renewcommand{\translatesecondaryreviewer}{Zweitgutachter}
\renewcommand{\translatesupervisor}{Betreuer}
\renewcommand{\translatesubmittedby}{vorgelegt von}
\renewcommand{\translatefrom}{aus}
\renewcommand{\translateuniversityname}{Heinrich-Heine-Universität Düsseldorf}
\renewcommand{\translatedepartment}{Abteilung Betriebssysteme}
\renewcommand{\translatedeclarationtitle}{Ehrenwörtliche Erklärung}
\renewcommand{\translatedeclaration}{Hiermit versichere ich, die vorliegende {\thesistypename} selbstständig verfasst und keine anderen als die angegebenen Quellen und Hilfsmittel benutzt zu haben. Alle Stellen, die aus den Quellen entnommen wurden, sind als solche kenntlich gemacht worden. Diese Arbeit hat in gleicher oder ähnlicher Form noch keiner Prüfungsbehörde vorgelegen.}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Variables
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\thesistitle}[1]{\title{#1}}
\newcommand{\thesisauthor}[1]{\author{#1}}
\newcommand{\submissiondate}[1]{\date{#1}}
\def\@thesislanguage{}
\newcommand{\thesislanguage}[1]{\def\@thesislanguage{#1}}
\def\@thesiskeywords{}
\newcommand{\thesiskeywords}[1]{\def\@thesiskeywords{#1}}
\def\@authorbirthplace{}
\newcommand{\authorbirthplace}[1]{\def\@authorbirthplace{#1}}
\def\@authorbirthname{}
\newcommand{\authorbirthname}[1]{\def\@authorbirthname{#1}}
\def\@firstreviewer{}
\newcommand{\firstreviewer}[1]{\def\@firstreviewer{#1}}
\def\@secondreviewer{}
\newcommand{\secondreviewer}[1]{\def\@secondreviewer{#1}}
\def\@supervisor{}
\newcommand{\supervisor}[1]{\def\@supervisor{#1}}
\def\@thesistype{}
\newcommand{\thesistype}[1]{\def\@thesistype{#1}}
\def\@glossaryenabled{}
\newcommand{\glossaryenabled}[1]{\def\@glossaryenabled{#1}}
\def\@listoffiguresenabled{}
\newcommand{\listoffiguresenabled}[1]{\def\@listoffiguresenabled{#1}}
\def\@listoftablesenabled{}
\newcommand{\listoftablesenabled}[1]{\def\@listoftablesenabled{#1}}
\def\@listofalgorithmsenabled{}
\newcommand{\listofalgorithmsenabled}[1]{\def\@listofalgorithmsenabled{#1}}
\def\@hidefigures{}
\newcommand{\hidefigures}[1]{\def\@hidefigures{#1}}
\def\@hidecode{}
\newcommand{\hidecode}[1]{\def\@hidecode{#1}}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Colors
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Primary
\definecolor{hhuCorporateBlue}{HTML}{006AB3}
\definecolor{hhuCorporateGrey}{HTML}{D9DADB}
% Secondary
\definecolor{hhuCorporateGreen}{HTML}{97BF0D}
\definecolor{hhuCorporateOrange}{HTML}{F29400}
\definecolor{hhuCorporateRed}{HTML}{BE0A26}
\definecolor{hhuCorporateDarkBlue}{HTML}{003865}
\definecolor{hhuCorporateLightBlue}{HTML}{32B8C9}
% Code
\colorlet{titlebg}{hhuCorporateGrey!80!white}
\colorlet{titlecolor}{black}
\colorlet{termbg}{hhuCorporateGrey!10!white}
\colorlet{termfg}{hhuCorporateGrey!20!white}
\colorlet{codebg}{white}
\colorlet{numberbg}{hhuCorporateGrey!25!white}
\colorlet{languagebg}{hhuCorporateGrey!20!white}
\definecolor{mintedtext}{HTML}{F8F8F2}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Document settings
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\setlength{\marginparwidth}{2.1cm}
\AtBeginDocument{
\hypersetup{
pdfauthor={\@author},
pdftitle={\@title},
pdfkeywords={\@thesiskeywords},
pdfproducer={LaTeX with hyperref},
pdfcreator={PDFLaTeX}
}
\selectlanguage{\@thesislanguage}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Thesis environment
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newenvironment{thesis}
{
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Global options
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\setlength{\parindent}{0pt}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Disable fancy headers
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\pagestyle{empty}
\pagenumbering{gobble}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Title page
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\thesiscover
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Table of contents
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\tableofcontents
\cleardoublepage
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Re-enable fancy headers
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \pagenumbering{arabic} % Only number chapters
\pagestyle{thesis}
\ifthenelse{\equal{\@glossaryenabled}{true}}
{%
\setacronymstyle{short-long}
\printglossary[type=\acronymtype]
\cleardoublepage
\printglossary
\cleardoublepage
}%
{}
\ifthenelse{\equal{\@hidefigures}{true}}
{%
\excludecomment{figure}
\let\endfigure\relax
}%
{}
\ifthenelse{\equal{\@hidecode}{true}}
{%
\excludecomment{codeblock}
\let\endcodeblock\relax
}%
{}
\pagenumbering{arabic}
}
{
\pagenumbering{gobble}
\printbibliography % [heading=bibintoc]
%\cleardoublepage
\clearpage
\tcblistof[\chapter*]{listings}{List of Listings}
% \addcontentsline{toc}{chapter}{List of Listings}
%\cleardoublepage
\clearpage
% The lof/lot linespacing should match the lol linespacing
\setlength{\cftparskip}{2pt}
\ifthenelse{\equal{\@listoftablesenabled}{true}}
{%
\listoftables
%\cleardoublepage
\clearpage
}%
{}
\ifthenelse{\equal{\@listoffiguresenabled}{true}}
{%
\listoffigures
%\cleardoublepage
\clearpage
}%
{}
\ifthenelse{\equal{\@listofalgorithmsenabled}{true}}
{%
\listofalgorithms
%\cleardoublepage
\clearpage
}%
{}
\declaration
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Title page
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\thesiscover}
{
\begin{titlepage}
\newgeometry{left=2.5cm,right=2.5cm,top=3cm}
\begin{center}
\includesvg[width=5cm]{img/hhu_color.svg}
\vspace{0.75cm}
{\Large \thesistypename}
\vspace{0.75cm}
% Thesis title
\rule{\textwidth}{0.25mm}\\
\vspace{-5pt}
\rule{\textwidth}{0.8mm}\\
{\Huge \textsc{\@title\\}}
\rule{\textwidth}{0.8mm}\\
\vspace{-5pt}
\rule{\textwidth}{0.25mm}
\vspace{7.5em}
{\translatesubmittedby} \\[.5em]
{\huge \@author} \\[.5em]
{{\translatefrom} \@authorbirthplace}\\
\vfill
% Department
{\translatedepartment}\\
Prof. Dr. Michael Schöttner\\
{\translateuniversityname}\\
\vspace{1cm}
% Date
\vspace{0.5cm}
\@date
\vspace{0.5cm}
% People
\begin{tabular}{r l}
{\translateprimaryreviewer}: & \@firstreviewer \\
\ifthenelse{\equal{\@thesistype}{project}}{}{{\translatesecondaryreviewer}: & \@secondreviewer \\}
{\translatesupervisor}: & \@supervisor \\
\end{tabular}
\end{center}
\end{titlepage}
\clearpage{\pagestyle{empty}\cleardoublepage}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Literature
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\literature}
{
% Why is this here twice?
% \bibliography{\literaturebibtexdatei}
% \bibliographystyle{plain}
% \addcontentsline{toc}{chapter}{Literaturverzeichnis}
% \cleardoublepage
\bibliography{\literaturebibtexdatei}
\bibliographystyle{plain}
\clearpage{\pagestyle{empty}\cleardoublepage}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Statutory Declaration
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\declaration}
{
\cleardoublepage
\pagestyle{empty}
\huge
\noindent\textbf{\translatedeclarationtitle}
\large
\vspace{3cm}
{\noindent\translatedeclaration}
\vspace{4cm}
\begin{center}
\begin{tabular}{lc}
Düsseldorf, \@date \hspace{1.5cm} & \hspace{7cm} \\[-10pt]
& \hrulefill \\
& \@author
\\
\end{tabular}
\end{center}
\clearpage{\pagestyle{empty}\cleardoublepage}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Miscellaneous
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\thesistypename}{%
\ifthenelse{\equal{\@thesistype}{bachelor}}
{\translatebachelorsthesis}
{%
\ifthenelse{\equal{\@thesistype}{master}}
{\translatemastersthesis}
{\translateprojectwork}
}%
}
\newtcolorbox[auto counter,list inside=listings,number within=chapter]{codeblock}[3][]
{%
enhanced,
colbacktitle=titlebg,
coltitle=titlecolor,
colframe=titlebg,
interior style={%
top color=codebg,
bottom color=codebg
},
boxrule=.5pt,
arc=0.6mm,
width= (\linewidth),
fonttitle=\footnotesize,
adjusted title=\thetcbcounter\quad\texttt{#2},
list entry=\thetcbcounter\quad\texttt{#2},
after title={%
\hfill\setlength{\fboxsep}{2pt}
\codelang{#3}
},
overlay={%
\begin{tcbclipinterior}\fill[numberbg] (frame.south west)
rectangle ([xshift=5mm]frame.north west);
\end{tcbclipinterior}
},
top=0mm,
bottom=0mm,
right=0mm,
left=5mm,
#1
}
\newtcolorbox{terminalblock}
{%
enhanced,
colbacktitle=titlebg,
coltitle=titlecolor,
colframe=titlebg,
interior style={%
top color=codebg,
bottom color=codebg
},
boxrule=.5pt,
arc=0.6mm,
width= (\linewidth),
fonttitle=\footnotesize,
adjusted title={%
\tikz\draw[hhuCorporateGrey!50!black,fill=hhuCorporateGrey!50!black] (0,0) circle (.5ex);
\tikz\draw[hhuCorporateGrey!60!black,fill=hhuCorporateGrey!60!black] (0,0) circle (.5ex);
\tikz\draw[hhuCorporateGrey!70!black,fill=hhuCorporateGrey!70!black] (0,0) circle (.5ex);
},
top=1mm,
bottom=0mm,
left=1mm,
right=1mm
}
\newtcbox{\codehighlight}{nobeforeafter,boxrule=.5pt,colback=black!5,colframe=black!35,
arc=2pt,boxsep=0pt,left=2pt,right=2pt,top=2pt,bottom=1pt, tcbox raise base}
\newcommand{\code}[1]{\codehighlight{\texttt{#1}}}
\newtcbox{\languagehighlight}{nobeforeafter,boxrule=0pt,colback=black!5,arc=1pt,
boxsep=0pt,left=2pt,right=2pt,top=2pt,bottom=2pt, tcbox raise base}
\newcommand{\codelang}[1]{\languagehighlight{\texttt{#1}}}
\newenvironment{noteblock}%
{
\setlength\topsep{4pt}
\setlength\parskip{0pt}
\begin{center}
\begin{tabular}{|p{.95\linewidth}}
}
%
{
\end{tabular}
\end{center}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Code environments
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newminted{java}{
linenos,
autogobble,
breaklines=true,
breaksymbol=,
breakindent=4mm,
breakbefore=.,
breakbeforesymbolpre=,
breakbeforesymbolpost=,
baselinestretch=0.8,
escapeinside=||,
framesep=5mm,
numbersep=7pt,
% fontfamily=tt,
fontsize=\footnotesize,
% style=bw,
escapeinside=||
}
\newminted{kotlin}{
linenos,
autogobble,
breaklines=true,
breaksymbol=,
breakindent=4mm,
breakbefore=.,
breakbeforesymbolpre=,
breakbeforesymbolpost=,
baselinestretch=0.8,
escapeinside=||,
framesep=5mm,
numbersep=7pt,
% fontfamily=tt,
fontsize=\footnotesize,
% style=bw,
escapeinside=||
}
\newminted{scala}{
linenos,
autogobble,
breaklines=true,
breaksymbol=,
breakindent=4mm,
breakbefore=.,
breakbeforesymbolpre=,
breakbeforesymbolpost=,
baselinestretch=0.8,
escapeinside=||,
framesep=5mm,
numbersep=7pt,
% fontfamily=tt,
fontsize=\footnotesize,
% style=bw,
escapeinside=||
}
\newminted{c}{
linenos,
autogobble,
breaklines=true,
breaksymbol=,
breakindent=4mm,
breakbefore=.,
breakbeforesymbolpre=,
breakbeforesymbolpost=,
baselinestretch=0.8,
escapeinside=||,
framesep=5mm,
numbersep=7pt,
% fontfamily=tt,
fontsize=\footnotesize,
% style=bw,
escapeinside=||
}
\newmintedfile[cppfile]{cpp}{
linenos,
autogobble,
breaklines=true,
breaksymbol=,
breakindent=4mm,
breakbefore=.,
breakbeforesymbolpre=,
breakbeforesymbolpost=,
baselinestretch=0.8,
escapeinside=||,
framesep=5mm,
numbersep=7pt,
% fontfamily=tt,
fontsize=\footnotesize,
% style=bw,
escapeinside=||
}
\newmintedfile[nasmfile]{nasm}{
linenos,
autogobble,
breaklines=true,
breaksymbol=,
breakindent=4mm,
breakbefore=.,
breakbeforesymbolpre=,
breakbeforesymbolpost=,
baselinestretch=0.8,
escapeinside=||,
framesep=5mm,
numbersep=7pt,
% fontfamily=tt,
fontsize=\footnotesize,
% style=bw,
escapeinside=||
}
\newminted{rust}{
linenos,
autogobble,
breaklines=true,
breaksymbol=,
breakindent=4mm,
breakbefore=.,
breakbeforesymbolpre=,
breakbeforesymbolpost=,
baselinestretch=1.0,
escapeinside=||,
framesep=5mm,
numbersep=7pt,
% fontfamily=tt,
fontsize=\footnotesize,
% style=bw,
escapeinside=||
}
\newminted{go}{
linenos,
autogobble,
breaklines=true,
breaksymbol=,
breakindent=4mm,
breakbefore=.,
breakbeforesymbolpre=,
breakbeforesymbolpost=,
baselinestretch=1.0,
escapeinside=||,
framesep=5mm,
numbersep=7pt,
% fontfamily=tt,
fontsize=\footnotesize,
% style=bw,
escapeinside=||
}
\newminted{text}{
autogobble,
breaklines=true,
breaksymbol=,
breakindent=4mm,
breakbefore=.,
breakbeforesymbolpre=,
breakbeforesymbolpost=,
baselinestretch=1.0,
escapeinside=||,
framesep=5mm,
numbersep=7pt,
% fontfamily=tt,
fontsize=\footnotesize,
% style=bw,
escapeinside=||
}

13
code/ap_boot_copy.cpp Normal file
View File

@ -0,0 +1,13 @@
// Allocate physical memory for copying the startup routine
auto &memoryService = System::getService<MemoryService>();
void *startupCodeMemory = memoryService.mapIO(0x8000, Util::PAGESIZE);
// Identity map the allocated physical memory to the kernel address space
memoryService.unmap(reinterpret_cast<uint32_t>(startupCodeMemory));
memoryService.mapPhysicalAddress(0x8000, 0x8000,
Kernel::Paging::PRESENT | Kernel::Paging::READ_WRITE);
// Copy the startup routine and prepared variables to the identity mapped page
auto startupCode = Util::Address<uint32_t>(reinterpret_cast<uint32_t>(&boot_ap));
auto destination = Util::Address<uint32_t>(0x8000);
destination.copyRange(startupCode, boot_ap_size);

4
code/ap_boot_post.cpp Normal file
View File

@ -0,0 +1,4 @@
// Excerpt from the smpEntry function
Apic::initializeCurrentLocalApic();
Apic::enableCurrentErrorHandler();
Apic::startCurrentTimer();

View File

@ -0,0 +1,25 @@
; Continuing boot_ap_32:
; Get the local APIC ID of this AP, to locate GDT and stack
mov eax, 0x1
cpuid
shr ebx, 0x18
mov edi, ebx ; Now the ID is in EDI
; Load the prepared AP GDT
mov ebx, [boot_ap_gdts - boot_ap + startup_address]
mov eax, [ebx + edi * 0x4]
lgdt [eax]
; Load the TSS
mov ax, 0x28
ltr ax
; Load the correct stack for this AP
mov ebx, [boot_ap_stacks - boot_ap + startup_address]
mov esp, [ebx + edi * 0x4]
add esp, stack_size ; Stack starts at the bottom
mov ebp, esp
; Call the entry function
push edi
call [boot_ap_entry - boot_ap + startup_address]

View File

@ -0,0 +1,12 @@
; This section has to be compiled for 32-bit protected mode
boot_ap_32:
; Set cr3, cr0 and cr4 to the BSP's values for paging
mov eax, [boot_ap_cr3 - boot_ap + startup_address]
mov cr3, eax
mov eax, [boot_ap_cr0 - boot_ap + startup_address]
mov cr0, eax
mov eax, [boot_ap_cr4 - boot_ap + startup_address]
mov cr4, eax
; Load the system IDT
lidt [boot_ap_idtr - boot_ap + startup_address]

16
code/ap_boot_real.asm Normal file
View File

@ -0,0 +1,16 @@
; Continuing boot_ap:
; Enable Protected Mode, executed from an identity mapped page.
mov eax, cr0
or al, 0x1 ; Set PE bit
mov cr0, eax
; Setup the protected mode segments
mov ax, 0x10
mov ds, ax ; Data segment register
mov es, ax ; Extra segment register
mov ss, ax ; Stack segment register
mov fs, ax ; General purpose segment register
mov gs, ax ; General purpose segment register
; Far jump to protected mode, set code segment register
jmp dword 0x8:boot_ap_32 - boot_ap + 0x8000

View File

@ -0,0 +1,13 @@
; This section has to be compiled for 16-bit real mode
boot_ap:
; Disable interrupts
cli
; Enable A20 address line
in al, 0x92
or al, 2
out 0x92, al
; Load the temporary GDT required for the far jump into protected mode.
lgdt [tmp_gdt_desc - boot_ap + 0x8000]

19
code/ap_boot_usa.cpp Normal file
View File

@ -0,0 +1,19 @@
// Excerpt from the Universal Startup Algorithm
for (uint8_t cpu = 0; cpu < cpuCount; ++cpu) {
if (cpu == LocalApic::getId()) { continue; } // Skip the BSP
LocalApic::clearErrors();
LocalApic::sendInitIpi(cpu, ICREntry::Level::ASSERT);
LocalApic::waitForIpiDispatch();
LocalApic::sendInitIpi(cpu, ICREntry::Level::DEASSERT);
LocalApic::waitForIpiDispatch();
Pit::earlyDelay(10'000); // 10 milliseconds
for (uint8_t i = 0; i < 2; ++i) {
LocalApic::clearErrors();
LocalApic::sendStartupIpi(cpu, apStartupAddress);
LocalApic::waitForIpiDispatch();
Pit::earlyDelay(200); // 200 microseconds
}
while (!(runningAPs & (1 << cpu))) {} // Wait until the AP is running
}

View File

@ -0,0 +1,15 @@
// These variables are located in the startup routine's TEXT section
// and exported from smp_boot.asm.
// Use IDTR from the BSP
asm volatile("sidt %0" : "=m"(boot_ap_idtr));
// Use cr0, cr3 and cr4 from the BSP
asm volatile("mov %%cr0, %%eax;" : "=a"(boot_ap_cr0));
asm volatile("mov %%cr3, %%eax;" : "=a"(boot_ap_cr3));
asm volatile("mov %%cr4, %%eax;" : "=a"(boot_ap_cr4));
// Set the address of the pre-allocated GDTs, stacks and the entry function
boot_ap_gdts = reinterpret_cast<uint32_t>(apGdts);
boot_ap_stacks = reinterpret_cast<uint32_t>(apStacks);
boot_ap_entry = reinterpret_cast<uint32_t>(&smpEntry);

10
code/apic_allow.cpp Normal file
View File

@ -0,0 +1,10 @@
void Apic::allow(InterruptRequest interruptRequest) {
IoApic::IrqOverride *override = IoApic::getOverride(interruptRequest);
if (override == nullptr) {
// If no override is specified, the IRQ is identity mapped to the GSI
IoApic::allow(static_cast<GlobalSystemInterrupt>(interruptRequest));
} else {
// If an override is specified, lookup which GSI the IRQ is mapped to
IoApic::allow(override->target);
}
}

View File

@ -0,0 +1,8 @@
void ApicErrorHandler::trigger(const InterruptFrame &frame) {
// Write/read register: Write first, then read
// Writing the ESR updates its contents and arms the interrupt again
LocalApic::writeDoubleWord(LocalApic::ESR, 0);
uint32_t errors = LocalApic::readDoubleWord(LocalApic::ESR);
log.error("APIC error on core [%d]: [0x%x]!", LocalApic::getId(), errors);
}

View File

@ -0,0 +1,11 @@
// Excerpt from the ApicTimer::calibrate function
uint32_t ApicTimer::calibrate() {
// Start the timer with a large counter
LocalApic::writeDoubleWord(LocalApic::TIMER_INITIAL, 0xFFFFFFFF);
// Wait a little
Pit::earlyDelay(10'000);
// Calculate how often the timer ticked in one millisecond
return (0xFFFFFFFF - LocalApic::readDoubleWord(LocalApic::TIMER_CURRENT)) / 10;
}

View File

@ -0,0 +1,10 @@
// Excerpt from the APIC timer interrupt handler
void ApicTimer::trigger(const InterruptFrame &frame) {
if (cpuId != LocalApic::getId()) {
// Abort if the handler doesn't belong to the current CPU
return;
}
// Increase the "core-local" time
time.addNanoseconds(timerInterval * 1'000'000); // Interval is in milliseconds
}

View File

@ -0,0 +1,8 @@
// Excerpt from the "InterruptDispatcher" class
void InterruptDispatcher::assign(uint8_t slot, InterruptHandler &isr) {
if (handler[slot] == nullptr) {
handler[slot] = new Util::ArrayList<InterruptHandler*>;
}
handler[slot]->add(&isr); // Register an interrupt handler to an interrupt vector
}

View File

@ -0,0 +1,4 @@
// Excerpt from the "checkSpuriousInterrupt" function
bool InterruptService::checkSpuriousInterrupt(InterruptVector interrupt) {
return interrupt == InterruptVector::SPURIOUS;
}

View File

@ -0,0 +1,12 @@
// Excerpt from the "dispatch" function
interruptDepthWrapper.inc();
interruptService.sendEndOfInterrupt(slot); // Signal interrupt servicing
asm volatile("sti"); // Allow cascaded interrupts
uint32_t size = handlerList->size();
for (uint32_t i = 0; i < size; i++) {
handlerList->get(i)->trigger(frame); // Call registered interrupt handlers
}
asm volatile("cli");
interruptDepthWrapper.dec();

View File

@ -0,0 +1,5 @@
// Excerpt from the "dispatch" function
if (interruptService.checkSpuriousInterrupt(slot)) {
spuriousCounterWrapper.inc();
return; // Early return to skip the calling of any handlers
}

View File

@ -0,0 +1,4 @@
// Excerpt from the "InterruptHandler" class definition
public:
virtual void plugin() = 0; // Register the handler
virtual void trigger(const InterruptFrame &frame) = 0; // Handle an interrupt

View File

@ -0,0 +1,7 @@
void InterruptService::allowHardwareInterrupt(InterruptRequest interrupt) {
if (Apic::isEnabled()) {
Apic::allow(interrupt);
} else {
Pic::allow(interrupt);
}
}

View File

@ -0,0 +1,6 @@
struct IrqOverride {
InterruptRequest source;
GlobalSystemInterrupt target;
REDTBLEntry::PinPolarity polarity;
REDTBLEntry::TriggerMode trigger;
};

View File

@ -0,0 +1,13 @@
struct REDTBLEntry {
InterruptVector vector;
DeliveryMode deliveryMode;
DestinationMode destinationMode;
DeliveryStatus deliveryStatus;
PinPolarity pinPolarity;
TriggerMode triggerMode;
bool isMasked;
uint8_t destination;
explicit REDTBLEntry(uint64_t registerValue);
explicit operator uint64_t() const;
};

View File

@ -0,0 +1,26 @@
// Excerpt from the IoAPic::initializeREDTBL function
void IoApic::initializeREDTBL() {
// GSI2 belongs to the PIT in many systems
auto gsi = GlobalSystemInterrupt(2);
IrqOverride *override = getOverride(gsi);
REDTBLEntry redtblEntry{};
redtblEntry.deliveryMode = REDTBLEntry::DeliveryMode::FIXED;
redtblEntry.destinationMode = REDTBLEntry::DestinationMode::PHYSICAL;
redtblEntry.isMasked = true;
redtblEntry.destination = LocalApic::getId(); // Redirect to BSP
if (override != nullptr) {
// Apply any information provided by an interrupt override
redtblEntry.vector = override->source + 32;
redtblEntry.pinPolarity = override->polarity;
redtblEntry.triggerMode = override->trigger;
} else {
// Apply PC/AT compatible ISA bus defaults
redtblEntry.vector = gsi + 32;
redtblEntry.pinPolarity = REDTBLEntry::PinPolarity::HIGH;
redtblEntry.triggerMode = REDTBLEntry::TriggerMode::EDGE;
}
writeREDTBL(gsi, redtblEntry);
}

View File

@ -0,0 +1,4 @@
void IoApic::writeIndirectRegister(uint32_t reg, uint32_t val) {
writeMMIORegister<uint8_t>(0x00, reg); // Write the index register
writeMMIORegister<uint32_t>(0x10, val); // Write the data register
}

View File

@ -0,0 +1,4 @@
template<typename T>
void IoApic::writeMMIORegister(uint32_t reg, T val) {
*reinterpret_cast<volatile T *>(mmioAddress + reg) = val;
}

View File

@ -0,0 +1,7 @@
void IoApic::writeREDTBL(GlobalSystemInterrupt gsi, const REDTBLEntry &redtbl) {
auto val = static_cast<uint64_t>(redtbl);
redtblLock.acquire(); // Synchronized in case of multiple APs
writeIndirectRegister(0x10 + 2 * gsi, val & 0xFFFFFFFF); // Low DW
writeIndirectRegister(0x10 + 2 * gsi + 1, val >> 32); // High DW
redtblLock.release();
}

View File

@ -0,0 +1,12 @@
void LocalApic::synchronizeArbitrationIds() {
ICREntry icrEntry{};
icrEntry.vector = 0;
icrEntry.deliveryMode = ICREntry::DeliveryMode::INIT;
icrEntry.destinationMode = ICREntry::DestinationMode::PHYSICAL;
icrEntry.level = ICREntry::Level::DEASSERT;
icrEntry.triggerMode = ICREntry::TriggerMode::LEVEL;
icrEntry.destinationShorthand = ICREntry::DestinationShorthand::ALL;
icrEntry.destination = 0;
writeICR(icrEntry);
waitForIpiDispatch();
}

13
code/lapic_icr_entry.cpp Normal file
View File

@ -0,0 +1,13 @@
struct ICREntry {
InterruptVector vector;
DeliveryMode deliveryMode;
DestinationMode destinationMode;
DeliveryStatus deliveryStatus;
Level level;
TriggerMode triggerMode;
DestinationShorthand destinationShorthand;
uint8_t destination;
explicit ICREntry(uint64_t registerValue);
explicit operator uint64_t() const;
};

7
code/lapic_imcr.cpp Normal file
View File

@ -0,0 +1,7 @@
void LocalApic::disablePicMode() {
IoPort registerSelectorPort = IoPort(0x22);
IoPort registerDataPort = IoPort(0x23);
registerSelectorPort.writeByte(0x70); // IMCR address is 0x70
registerDataPort.writeByte(0x01); // 0x01 disconnects PIC
}

View File

@ -0,0 +1,11 @@
void LocalApic::issueINIT(uint8_t cpuId, ICREntry::Level level) {
ICREntry icrEntry{};
icrEntry.vector = 0;
icrEntry.deliveryMode = ICREntry::DeliveryMode::INIT;
icrEntry.destinationMode = ICREntry::DestinationMode::PHYSICAL;
icrEntry.level = level; // ASSERT or DEASSERT
icrEntry.triggerMode = ICREntry::TriggerMode::LEVEL;
icrEntry.destinationShorthand = ICREntry::DestinationShorthand::NO;
icrEntry.destination = cpuId;
writeICR(icrEntry); // Writing the ICR issues IPI
}

12
code/lapic_lvt_entry.cpp Normal file
View File

@ -0,0 +1,12 @@
struct LVTEntry {
InterruptVector vector;
DeliveryMode deliveryMode;
DeliveryStatus deliveryStatus;
PinPolarity pinPolarity;
TriggerMode triggerMode;
bool isMasked;
TimerMode timerMode;
explicit LVTEntry(uint32_t registerValue);
explicit operator uint32_t() const;
};

View File

@ -0,0 +1,7 @@
LVTEntry lvtEntry{};
lvtEntry.deliveryMode = LVTEntry::DeliveryMode::FIXED;
lvtEntry.pinPolarity = LVTEntry::PinPolarity::HIGH;
lvtEntry.triggerMode = LVTEntry::TriggerMode::EDGE;
lvtEntry.isMasked = true;
lvtEntry.vector = InterruptVector::LINT0;
writeLVT(LINT0, lvtEntry);

View File

@ -0,0 +1,9 @@
uint32_t allocateMMIORegion() {
// The apicBaseAddress is obtained via ACPI
auto &memoryService = System::getService<MemoryService>();
void *virtAddressPtr = memoryService.mapIO(apicBaseAddress, Util::PAGESIZE);
// Account for possible misalignment, as mapIO returns a page-aligned pointer
uint32_t pageOffset = apicBaseAddress % Util::PAGESIZE;
return reinterpret_cast<uint32_t>(virtAddressPtr) + pageOffset;
}

View File

@ -0,0 +1,4 @@
void LocalApic::writeDoubleWord(uint32_t reg, uint32_t val) {
// Use volatile to prevent compiletime caching and code elimination
*reinterpret_cast<volatile uint32_t *>(virtAddress + reg) = val;
}

9
code/lapic_msr_entry.cpp Normal file
View File

@ -0,0 +1,9 @@
struct BaseMSREntry {
bool isBSP;
bool isX2Apic;
bool isXApic;
uint32_t baseField;
explicit BaseMSREntry(uint64_t registerValue);
explicit operator uint64_t() const;
};

View File

@ -0,0 +1,11 @@
void LocalApic::issueSIPI(uint8_t cpuId, uint32_t page) {
ICREntry icrEntry{};
icrEntry.vector = page;
icrEntry.deliveryMode = ICREntry::DeliveryMode::STARTUP;
icrEntry.destinationMode = ICREntry::DestinationMode::PHYSICAL;
icrEntry.level = ICREntry::Level::ASSERT;
icrEntry.triggerMode = ICREntry::TriggerMode::EDGE;
icrEntry.destinationShorthand = ICREntry::DestinationShorthand::NO;
icrEntry.destination = cpuId;
writeICR(icrEntry); // Writing the ICR issues an IPI
}

9
code/lapic_svr_entry.cpp Normal file
View File

@ -0,0 +1,9 @@
struct SVREntry {
InterruptVector vector;
bool isSWEnabled;
bool hasFocusProcessorChecking;
bool suppressEoiBroadcasting;
explicit SVREntry(uint32_t registerValue);
explicit operator uint32_t() const;
};

View File

@ -0,0 +1,4 @@
SVREntry svrEntry{};
svrEntry.vector = InterruptVector::SPURIOUS;
svrEntry.isSWEnabled = true; // Keep the APIC software enabled
writeSVR(svrEntry);

7
code/lapic_write_icr.cpp Normal file
View File

@ -0,0 +1,7 @@
void LocalApic::writeICR(const ICREntry &icrEntry) {
auto val = static_cast<uint64_t>(icrEntry);
icrLock.acquire(); // Synchronized in case of multiple APs
writeDoubleWord(0x310, val >> 32);
writeDoubleWord(0x300, val & 0xFFFFFFFF); // Writing the low DW sends the IPI
icrLock.release();
}

3
code/lapic_write_lvt.cpp Normal file
View File

@ -0,0 +1,3 @@
void LocalApic::writeLVT(uint32_t reg, const LVTEntry &lvtEntry) {
writeDoubleWord(reg, static_cast<uint32_t>(lvtEntry));
}

4
code/lapic_write_msr.cpp Normal file
View File

@ -0,0 +1,4 @@
void LocalApic::writeBaseMSR(const MSREntry &msrEntry) {
ModelSpecificRegister baseMSR = ModelSpecificRegister(0x1B);
baseMSR.writeQuadWord(static_cast<uint64_t>(msrEntry)); // Atomic write
}

3
code/lapic_write_svr.cpp Normal file
View File

@ -0,0 +1,3 @@
void LocalApic::writeSVR(const SVREntry &svrEntry) {
writeDoubleWord(0xF0, static_cast<uint32_t>(svrEntry));
}

12
code/pit_after.cpp Normal file
View File

@ -0,0 +1,12 @@
void Pit::trigger(const InterruptFrame &frame) {
time.addNanoseconds(timerInterval); // Increase system time
// Don't use PIT for scheduling when the APIC timer is enabled
if (Apic::isEnabled()) {
return;
}
if (time.toMilliseconds() % yieldInterval == 0) {
System::getService<SchedulerService>().yield(); // Trigger preemption
}
}

8
code/pit_trigger.cpp Normal file
View File

@ -0,0 +1,8 @@
// Excerpt from the "Pit" interrupt handler
void Pit::trigger(const InterruptFrame &frame) {
time.addNanoseconds(timerInterval); // Increase system time
if (time.toMilliseconds() % yieldInterval == 0) {
System::getService<SchedulerService>().yield(); // Trigger preemption
}
}

4
code/smp_entry.cpp Normal file
View File

@ -0,0 +1,4 @@
// Excerpt from the smpEntry function
void smpEntry(uint8_t cpuId) {
runningAPs |= (1 << cpuId); // Mark that this AP is running
}

9
code/system_after.cpp Normal file
View File

@ -0,0 +1,9 @@
// Excerpt from System::initializeSystem(). Located before interrupts
// are enabled and any devices have registered their handlers.
if (Apic::isSupported()) {
Apic::enable();
if (Apic::isSmpSupported()) {
Apic::startupSmp();
}
}

243
glossary.tex Normal file
View File

@ -0,0 +1,243 @@
\makeglossaries
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Acronyms
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newacronym{acpi}{ACPI}{\gls{advanced configuration and power interface}}
\newacronym{aml}{AML}{acpi machine language}
\newacronym{ap}{AP}{\gls{application processor}}
\newacronym{apr}{APR}{arbitration priority register}
\newacronym{apic}{APIC}{advanced programmable interrupt controller}
\newacronym{bios}{BIOS}{basic input/output system}
\newacronym{bsp}{BSP}{\gls{bootstrap processor}}
\newacronym{cpuid}{CPUID}{cpu identification}
\newacronym{eoi}{EOI}{\gls{end-of-interrupt}}
\newacronym{esr}{ESR}{error status register}
\newacronym{gdt}{GDT}{global descriptor table}
\newacronym{gdtr}{GDTR}{global descriptor table register}
\newacronym{gsi}{GSI}{\gls{global system interrupt}}
\newacronym{ich}{ICH}{intel input/output controller hub}
\newacronym{icr}{ICR}{\gls{interrupt command register}}
\newacronym{idt}{IDT}{interrupt descriptor table}
\newacronym{idtr}{IDTR}{interrupt descriptor table register}
\newacronym{imcr}{IMCR}{\gls{interrupt mode control register}}
\newacronym{imr}{IMR}{interrupt mask register}
\newacronym{inti}{INTI}{interrupt input}
\newacronym{ipi}{IPI}{inter-processor interrupt}
\newacronym{irq}{IRQ}{interrupt request}
\newacronym{irr}{IRR}{\gls{interrupt request register}}
\newacronym{isa}{ISA}{industry standard architecture}
\newacronym{isr}{ISR}{\gls{in-service register}}
\newacronym{lvt}{LVT}{\gls{local vector table}}
\newacronym{madt}{MADT}{multiple apic descriptor table}
\newacronym{mmio}{MMIO}{memory mapped input/output}
\newacronym{msr}{MSR}{model specific register}
\newacronym{msi}{MSI}{\gls{message-signaled interrupt}}
\newacronym{nmi}{NMI}{\gls{non-maskable interrupt}}
\newacronym{pci}{PCI}{peripheral component interconnect}
\newacronym{pic}{PIC}{programmable interrupt controller}
\newacronym{pit}{PIT}{\gls{programmable interval timer}}
\newacronym{redtbl}{REDTBL}{redirection table}
\newacronym{sipi}{SIPI}{startup inter-processor interrupt}
\newacronym{smi}{SMI}{system management interrupt}
\newacronym{smp}{SMP}{\gls{symmetric multiprocessing}}
\newacronym{svr}{SVR}{\gls{spurious interrupt vector register}}
\newacronym{tmr}{TMR}{trigger-mode register}
\newacronym{tpr}{TPR}{\gls{task-priority register}}
\newacronym{tss}{TSS}{task state segment}
\newacronym{uefi}{UEFI}{unified extensible firmware interface}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Glossary Entries
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \newglossaryentry{}{
% name={},
% description={}
% }
\newglossaryentry{advanced configuration and power interface}{
name={advanced configuration and power interface},
description={a standard for operating systems to allow software to query information about the system hardware configuration}
}
\newglossaryentry{apic timer}{
name={APIC timer},
description={a hardware timer that can trigger periodic interrupts by using a counter, integrated into the local APIC}
}
\newglossaryentry{application processor}{
name={application processor},
description={a processor inside an SMP system, e.g. a CPU core}
}
\newglossaryentry{bootstrap processor}{
name={bootstrap processor},
description={the application processor used to boot an SMP system}
}
\newglossaryentry{cascaded interrupt}{
name={cascaded interrupt},
description={an interrupt, serviced during another interrupt handler}
}
\newglossaryentry{end-of-interrupt}{
name={end-of-interrupt},
description={a notification to an interrupt controller that an interrupt has been handled}
}
\newglossaryentry{external interrupt}{
name={external interrupt},
description={an interrupt from an external hardware device}
}
\newglossaryentry{global system interrupt}{
name={global system interrupt},
description={an abstraction used by ACPI to decouple interrupts from hardware interrupt lines}
}
\newglossaryentry{ia32 apic base msr}{
name={IA32\textunderscore{}APIC\textunderscore{}BASE MSR},
description={an x86 architectural MSR that contains the local APIC's physical MMIO address and the xApic global enable/disable flag}
}
\newglossaryentry{io apic}{
name={I/O APIC},
description={a part of the APIC architecture inside the chipset, responsible for receiving external interrupts}
}
\newglossaryentry{init ipi}{
name={INIT IPI},
description={an interprocessor interrupt sent from the BSP to the APs, to begin the AP initialization process}
}
\newglossaryentry{inter-processor interrupt}{
name={inter-processor interrupt},
description={an interrupt sent between CPU cores}
}
\newglossaryentry{interrupt}{
name={interrupt},
description={a request for the CPU to handle an event}
}
\newglossaryentry{interrupt command register}{
name={interrupt command register},
description={a register of the local APIC used to issue interprocessor interrupts}
}
\newglossaryentry{interrupt controller}{
name={interrupt controller},
description={a hardware component designated to receive interrupts and forward them to the CPU}
}
\newglossaryentry{interrupt handler}{
name={interrupt handler},
description={a function designated to handle a specific interrupt}
}
\newglossaryentry{interrupt mode control register}{
name={interrupt mode control register},
description={a register present in some systems to choose the physically connected interrupt controller}
}
\newglossaryentry{interrupt priority}{
name={interrupt priority},
description={the interrupt priority decides the order, in which multiple, simultaneously arriving interrupts, are forwarded to the CPU}
}
\newglossaryentry{interrupt vector}{
name={interrupt vector},
description={a slot of an interrupt handler in the IDT}
}
\newglossaryentry{interrupt request register}{
name={interrupt request register},
description={a register, part of the PIC and local APIC, which keeps track of received interrupts}
}
\newglossaryentry{in-service register}{
name={in-service register},
description={a register, part of the PIC and local APIC, which keeps track of interrupts that are being serviced}
}
\newglossaryentry{irq override}{
name={IRQ override},
description={information from ACPI, that describes how interrupt lines correspond to global system interrupts}
}
\newglossaryentry{local apic}{
name={local APIC},
description={a part of the APIC architecture inside a CPU core, responsible for receiving local interrupts and communication with the I/O APIC}
}
\newglossaryentry{local interrupt}{
name={local interrupt},
description={an CPU internal interrupt handled by the local APIC, like the APIC timer interrupt}
}
\newglossaryentry{local vector table}{
name={local vector table},
description={a set of registers, part of the local APIC, that configure how local interrupts are handled}
}
\newglossaryentry{masking}{
name={masking},
description={marking an interrupt as ignored}
}
\newglossaryentry{memory-mapped io}{
name={memory-mapped I/O},
description={a way to access a devices registers by mapping them to addresses in the main memory}
}
\newglossaryentry{message-signaled interrupt}{
name={message-signaled interrupt},
description={an interrupt sent in-band over a PCI-bus}
}
\newglossaryentry{non-maskable interrupt}{
name={non-maskable interrupt},
description={a system critical interrupt that cannot be masked}
}
\newglossaryentry{pcat pic architecture}{
name={PC/AT PIC architecture},
description={an interrupt controller configuration using two cascaded PICs for a total of 15 interrupt lines}
}
\newglossaryentry{pic mode}{
name={PIC mode},
description={only use the PIC for interrupt handling, like the PC/AT}
}
\newglossaryentry{pin polarity}{
name={pin polarity},
description={describes if a signal is represented by either a high or low level change or theshold}
}
\newglossaryentry{programmable interval timer}{
name={programmable interval timer},
description={a hardware timer that can trigger periodic interrupts by using a counter}
}
\newglossaryentry{protected mode}{
name={protected mode},
description={the 32-bit operating mode of x86 CPUs which includes security features such as paging}
}
\newglossaryentry{real mode}{
name={real mode},
description={an operating mode of x86 CPUs with 16-bit segmented memory addressing, resulting in 1 MB of usable memory with 20-bit address width}
}
\newglossaryentry{redirection table}{
name={redirection table},
description={a set of registers, part of the I/O APIC, that configure how external interrupts are handled}
}
\newglossaryentry{spurious interrupt}{
name={spurious interrupt},
description={an interrupt that is triggered in case an original interrupt is no longer valid on delivery}
}
\newglossaryentry{spurious interrupt vector register}{
name={spurious interrupt vector register},
description={a register of the local APIC which contains the APIC software enable flag and the spurious interrupt vector}
}
\newglossaryentry{startup ipi}{
name={STARTUP IPI},
description={an interprocessor interrupt sent from the BSP to the APs, to load the AP startup routine and finish AP initialization}
}
\newglossaryentry{symmetric io mode}{
name={symmetric I/O mode},
description={use the I/O APIC in combination with the local APIC for interrupt handling in multiprocessor systems}
}
\newglossaryentry{symmetric multiprocessing}{
name={symmetric multiprocessing},
description={a computer architecture where multiple CPUs operate on a shared main memory}
}
\newglossaryentry{task-priority register}{
name={task-priority register},
description={a register of the local APIC which determines interrupt handling order and priority theshold}
}
\newglossaryentry{trigger mode}{
name={trigger mode},
description={describes if a signal is represented by either a change in level or a level theshold}
}
\newglossaryentry{virtual wire mode}{
name={virtual wire mode},
description={use the local APIC in combination with the PIC as external interrupt controller}
}
\newglossaryentry{xapic}{
name={xApic},
description={a revision of the APIC architecture, register access is handled through MMIO}
}
\newglossaryentry{x2apic}{
name={x2Apic},
description={a revision of the APIC architecture, register access is handled through MSRs}
}

859
img/Architecture.svg Normal file
View File

@ -0,0 +1,859 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="331.91998pt"
height="274.07999pt"
viewBox="0 0 331.91998 274.07999"
version="1.1"
id="svg288"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg" content="%3Cmxfile%20host%3D%22app.diagrams.net%22%20modified%3D%222023-02-22T21%3A36%3A30.923Z%22%20agent%3D%225.0%20(X11)%22%20version%3D%2220.8.23%22%20etag%3D%22rvZp2vNKKJioHv2OAW5W%22%3E%3Cdiagram%20name%3D%22Page-1%22%20id%3D%22HYT1I5f8udhBxdHM_BtV%22%3E7Vldb5swFP01PG7iKyR5zNfWap1UKZPWPnrggifAzJgA%2B%2FUz4RpCSCSWNjiV%2BhTu8fXXuT5H4GjWKiq%2BMpQE36mHQ83UvUKz1pppGlPbFD8VUgKizwHxGfEAa4Et%2BYtlIqAZ8XDaSeSUhpwkXdClcYxd3sEQYzTvpr3QsDtrgnzcA7YuCvvoT%2BLxoEZnE73F7zDxAzmzoUNLhGQyAGmAPJofQNZGs1aMUl4%2FRcUKhxV7kpe635czrc3CGI75kA7A%2Bw6FGext8Xi%2FEsgdYl4uhoFl8lLundEs9nDV3dCsZR4QjrcJcqvWXJRbYAGPQmh%2BoTGH8hkzEcNsmHFcnF2x0fAgThCmEeasFCnQwZLUweGZOhDnbSUMmRMcVEHmISi%2B3wzd8iMegKLTdFk9OrAnTgaElPGA%2BjRG4aZFly1huojanAdKE6DpN%2Ba8BJ5QxukQEquJOxSmNGMuQDaIAjEf806lBxDNcIg42XVHfw1rdu%2BQaaYTikUsPbLr0On8yaqTv9%2Fyp3S%2F54VIMGZJsd%2B4bBdPfvX7QIUoFwlx5YBiKfsx6%2Ba3mmYVojQ9N8VZfeg3oQ9nTH1MbkEfgihWPsF4%2B%2BC5Cj5PZLguDhvXpYwKwp%2FaTBE9wwzVc9upCmSfAVqcjqJF6PpIiRixOQzmsVnOj4pcrwp6HdW5Wcag0jsqSn9pqS%2Bw1BNltNVZ6vRqlnpPR%2FbTX%2BxVY70TWzYchbY8U6LNC%2By00XMj7mF6HqBf%2Be1wI%2B9Ec6V2%2BZ%2F0XmCXp%2BhW6JdyOVcwzMouf5AIsw%2FPfGPPtGcKPdMwenyMoNAhyjrxcTdVqCzzHfGk0oGU3B1cyJOhKyTqetcFH2%2B2I1w4TEZ1aSU3DkNU5ZxQlUr7cXqq%2BoZZXN3M3%2FgFr33F8yTC9q69vvRo%2F7KwNv8A%3C%2Fdiagram%3E%3C%2Fmxfile%3E">
<defs
id="defs74">
<g
id="g66">
<g
id="glyph-0-0" />
<g
id="glyph-0-1">
<path
d="M -0.015625 0 L 3.6875 -9.65625 L 5.0625 -9.65625 L 9.015625 0 L 7.5625 0 L 6.4375 -2.921875 L 2.390625 -2.921875 L 1.34375 0 Z M 2.765625 -3.96875 L 6.03125 -3.96875 L 5.03125 -6.640625 C 4.71875 -7.453125 4.488281 -8.117188 4.34375 -8.640625 C 4.21875 -8.015625 4.046875 -7.398438 3.828125 -6.796875 Z M 2.765625 -3.96875 "
id="path3" />
</g>
<g
id="glyph-0-2">
<path
d="M 1.046875 0 L 1.046875 -9.65625 L 4.6875 -9.65625 C 5.320313 -9.65625 5.8125 -9.625 6.15625 -9.5625 C 6.625 -9.476563 7.019531 -9.328125 7.34375 -9.109375 C 7.664063 -8.890625 7.921875 -8.578125 8.109375 -8.171875 C 8.304688 -7.773438 8.40625 -7.335938 8.40625 -6.859375 C 8.40625 -6.035156 8.144531 -5.335938 7.625 -4.765625 C 7.101563 -4.203125 6.160156 -3.921875 4.796875 -3.921875 L 2.3125 -3.921875 L 2.3125 0 Z M 2.3125 -5.0625 L 4.8125 -5.0625 C 5.632813 -5.0625 6.21875 -5.210938 6.5625 -5.515625 C 6.914063 -5.828125 7.09375 -6.265625 7.09375 -6.828125 C 7.09375 -7.222656 6.988281 -7.566406 6.78125 -7.859375 C 6.582031 -8.148438 6.316406 -8.335938 5.984375 -8.421875 C 5.765625 -8.484375 5.363281 -8.515625 4.78125 -8.515625 L 2.3125 -8.515625 Z M 2.3125 -5.0625 "
id="path6" />
</g>
<g
id="glyph-0-3">
<path
d="M 1.25 0 L 1.25 -9.65625 L 2.53125 -9.65625 L 2.53125 0 Z M 1.25 0 "
id="path9" />
</g>
<g
id="glyph-0-4">
<path
d="M 7.921875 -3.390625 L 9.203125 -3.0625 C 8.929688 -2.007813 8.445313 -1.207031 7.75 -0.65625 C 7.0625 -0.101563 6.210938 0.171875 5.203125 0.171875 C 4.160156 0.171875 3.3125 -0.0390625 2.65625 -0.46875 C 2.007813 -0.894531 1.515625 -1.507813 1.171875 -2.3125 C 0.835938 -3.113281 0.671875 -3.976563 0.671875 -4.90625 C 0.671875 -5.90625 0.863281 -6.78125 1.25 -7.53125 C 1.632813 -8.28125 2.179688 -8.847656 2.890625 -9.234375 C 3.597656 -9.617188 4.378906 -9.8125 5.234375 -9.8125 C 6.191406 -9.8125 7 -9.566406 7.65625 -9.078125 C 8.320313 -8.585938 8.785156 -7.894531 9.046875 -7 L 7.78125 -6.703125 C 7.5625 -7.410156 7.238281 -7.921875 6.8125 -8.234375 C 6.382813 -8.554688 5.847656 -8.71875 5.203125 -8.71875 C 4.460938 -8.71875 3.84375 -8.539063 3.34375 -8.1875 C 2.84375 -7.832031 2.488281 -7.351563 2.28125 -6.75 C 2.082031 -6.15625 1.984375 -5.539063 1.984375 -4.90625 C 1.984375 -4.082031 2.101563 -3.363281 2.34375 -2.75 C 2.582031 -2.144531 2.953125 -1.6875 3.453125 -1.375 C 3.960938 -1.070313 4.515625 -0.921875 5.109375 -0.921875 C 5.816406 -0.921875 6.414063 -1.128906 6.90625 -1.546875 C 7.40625 -1.960938 7.742188 -2.578125 7.921875 -3.390625 Z M 7.921875 -3.390625 "
id="path12" />
</g>
<g
id="glyph-0-5">
<path
d="M 1.078125 0 L 1.078125 -9.65625 L 2.359375 -9.65625 L 2.359375 -5.6875 L 7.375 -5.6875 L 7.375 -9.65625 L 8.65625 -9.65625 L 8.65625 0 L 7.375 0 L 7.375 -4.546875 L 2.359375 -4.546875 L 2.359375 0 Z M 1.078125 0 "
id="path15" />
</g>
<g
id="glyph-0-6">
<path
d="M 5.453125 -0.859375 C 5.015625 -0.484375 4.59375 -0.21875 4.1875 -0.0625 C 3.78125 0.0820313 3.34375 0.15625 2.875 0.15625 C 2.101563 0.15625 1.507813 -0.03125 1.09375 -0.40625 C 0.6875 -0.78125 0.484375 -1.257813 0.484375 -1.84375 C 0.484375 -2.1875 0.5625 -2.5 0.71875 -2.78125 C 0.875 -3.0625 1.078125 -3.285156 1.328125 -3.453125 C 1.585938 -3.628906 1.875 -3.765625 2.1875 -3.859375 C 2.414063 -3.910156 2.765625 -3.96875 3.234375 -4.03125 C 4.191406 -4.144531 4.898438 -4.28125 5.359375 -4.4375 C 5.359375 -4.601563 5.359375 -4.707031 5.359375 -4.75 C 5.359375 -5.226563 5.25 -5.566406 5.03125 -5.765625 C 4.71875 -6.035156 4.265625 -6.171875 3.671875 -6.171875 C 3.117188 -6.171875 2.707031 -6.070313 2.4375 -5.875 C 2.175781 -5.675781 1.976563 -5.332031 1.84375 -4.84375 L 0.6875 -5 C 0.789063 -5.488281 0.960938 -5.882813 1.203125 -6.1875 C 1.453125 -6.5 1.800781 -6.738281 2.25 -6.90625 C 2.707031 -7.070313 3.238281 -7.15625 3.84375 -7.15625 C 4.4375 -7.15625 4.921875 -7.082031 5.296875 -6.9375 C 5.671875 -6.800781 5.945313 -6.625 6.125 -6.40625 C 6.300781 -6.195313 6.421875 -5.929688 6.484375 -5.609375 C 6.523438 -5.398438 6.546875 -5.035156 6.546875 -4.515625 L 6.546875 -2.9375 C 6.546875 -1.832031 6.570313 -1.132813 6.625 -0.84375 C 6.675781 -0.550781 6.773438 -0.269531 6.921875 0 L 5.6875 0 C 5.5625 -0.25 5.484375 -0.535156 5.453125 -0.859375 Z M 5.359375 -3.515625 C 4.921875 -3.335938 4.273438 -3.1875 3.421875 -3.0625 C 2.929688 -2.988281 2.582031 -2.90625 2.375 -2.8125 C 2.175781 -2.726563 2.019531 -2.601563 1.90625 -2.4375 C 1.800781 -2.269531 1.75 -2.082031 1.75 -1.875 C 1.75 -1.5625 1.867188 -1.296875 2.109375 -1.078125 C 2.347656 -0.867188 2.695313 -0.765625 3.15625 -0.765625 C 3.613281 -0.765625 4.019531 -0.863281 4.375 -1.0625 C 4.726563 -1.269531 4.988281 -1.546875 5.15625 -1.890625 C 5.289063 -2.160156 5.359375 -2.554688 5.359375 -3.078125 Z M 5.359375 -3.515625 "
id="path18" />
</g>
<g
id="glyph-0-7">
<path
d="M 0.875 0 L 0.875 -7 L 1.9375 -7 L 1.9375 -5.9375 C 2.207031 -6.425781 2.457031 -6.75 2.6875 -6.90625 C 2.925781 -7.070313 3.179688 -7.15625 3.453125 -7.15625 C 3.859375 -7.15625 4.265625 -7.023438 4.671875 -6.765625 L 4.265625 -5.671875 C 3.972656 -5.835938 3.679688 -5.921875 3.390625 -5.921875 C 3.140625 -5.921875 2.910156 -5.84375 2.703125 -5.6875 C 2.492188 -5.53125 2.347656 -5.316406 2.265625 -5.046875 C 2.128906 -4.617188 2.0625 -4.15625 2.0625 -3.65625 L 2.0625 0 Z M 0.875 0 "
id="path21" />
</g>
<g
id="glyph-0-8">
<path
d="M 5.421875 0 L 5.421875 -0.875 C 4.984375 -0.1875 4.332031 0.15625 3.46875 0.15625 C 2.914063 0.15625 2.40625 0.00390625 1.9375 -0.296875 C 1.46875 -0.609375 1.101563 -1.039063 0.84375 -1.59375 C 0.582031 -2.144531 0.453125 -2.773438 0.453125 -3.484375 C 0.453125 -4.179688 0.566406 -4.8125 0.796875 -5.375 C 1.035156 -5.945313 1.382813 -6.382813 1.84375 -6.6875 C 2.3125 -7 2.835938 -7.15625 3.421875 -7.15625 C 3.835938 -7.15625 4.207031 -7.0625 4.53125 -6.875 C 4.863281 -6.695313 5.132813 -6.46875 5.34375 -6.1875 L 5.34375 -9.65625 L 6.53125 -9.65625 L 6.53125 0 Z M 1.671875 -3.484375 C 1.671875 -2.585938 1.859375 -1.914063 2.234375 -1.46875 C 2.617188 -1.03125 3.066406 -0.8125 3.578125 -0.8125 C 4.097656 -0.8125 4.535156 -1.023438 4.890625 -1.453125 C 5.253906 -1.878906 5.4375 -2.523438 5.4375 -3.390625 C 5.4375 -4.347656 5.253906 -5.050781 4.890625 -5.5 C 4.523438 -5.945313 4.070313 -6.171875 3.53125 -6.171875 C 3 -6.171875 2.554688 -5.953125 2.203125 -5.515625 C 1.847656 -5.085938 1.671875 -4.410156 1.671875 -3.484375 Z M 1.671875 -3.484375 "
id="path24" />
</g>
<g
id="glyph-0-9">
<path
d="M 2.171875 0 L 0.046875 -7 L 1.265625 -7 L 2.375 -2.953125 L 2.796875 -1.453125 C 2.804688 -1.523438 2.925781 -2.003906 3.15625 -2.890625 L 4.265625 -7 L 5.484375 -7 L 6.53125 -2.9375 L 6.875 -1.59375 L 7.28125 -2.953125 L 8.484375 -7 L 9.625 -7 L 7.453125 0 L 6.21875 0 L 5.109375 -4.1875 L 4.828125 -5.375 L 3.421875 0 Z M 2.171875 0 "
id="path27" />
</g>
<g
id="glyph-0-10">
<path
d="M 5.671875 -2.25 L 6.90625 -2.09375 C 6.707031 -1.382813 6.347656 -0.832031 5.828125 -0.4375 C 5.304688 -0.0390625 4.640625 0.15625 3.828125 0.15625 C 2.804688 0.15625 1.992188 -0.15625 1.390625 -0.78125 C 0.796875 -1.414063 0.5 -2.300781 0.5 -3.4375 C 0.5 -4.613281 0.800781 -5.523438 1.40625 -6.171875 C 2.007813 -6.828125 2.796875 -7.15625 3.765625 -7.15625 C 4.691406 -7.15625 5.453125 -6.832031 6.046875 -6.1875 C 6.640625 -5.550781 6.9375 -4.660156 6.9375 -3.515625 C 6.9375 -3.441406 6.9375 -3.332031 6.9375 -3.1875 L 1.71875 -3.1875 C 1.757813 -2.425781 1.972656 -1.835938 2.359375 -1.421875 C 2.753906 -1.015625 3.242188 -0.8125 3.828125 -0.8125 C 4.265625 -0.8125 4.632813 -0.925781 4.9375 -1.15625 C 5.25 -1.382813 5.492188 -1.75 5.671875 -2.25 Z M 1.78125 -4.171875 L 5.6875 -4.171875 C 5.632813 -4.753906 5.484375 -5.191406 5.234375 -5.484375 C 4.859375 -5.941406 4.367188 -6.171875 3.765625 -6.171875 C 3.222656 -6.171875 2.765625 -5.988281 2.390625 -5.625 C 2.023438 -5.257813 1.820313 -4.773438 1.78125 -4.171875 Z M 1.78125 -4.171875 "
id="path30" />
</g>
<g
id="glyph-0-11">
<path
d="M 0.984375 0 L 0.984375 -9.65625 L 2.265625 -9.65625 L 2.265625 -1.140625 L 7.015625 -1.140625 L 7.015625 0 Z M 0.984375 0 "
id="path33" />
</g>
<g
id="glyph-0-12">
<path
d="M 0.453125 -3.5 C 0.453125 -4.789063 0.8125 -5.75 1.53125 -6.375 C 2.125 -6.894531 2.859375 -7.15625 3.734375 -7.15625 C 4.691406 -7.15625 5.472656 -6.835938 6.078125 -6.203125 C 6.691406 -5.578125 7 -4.707031 7 -3.59375 C 7 -2.695313 6.863281 -1.988281 6.59375 -1.46875 C 6.320313 -0.957031 5.925781 -0.554688 5.40625 -0.265625 C 4.894531 0.015625 4.335938 0.15625 3.734375 0.15625 C 2.753906 0.15625 1.960938 -0.15625 1.359375 -0.78125 C 0.753906 -1.40625 0.453125 -2.3125 0.453125 -3.5 Z M 1.671875 -3.5 C 1.671875 -2.601563 1.863281 -1.929688 2.25 -1.484375 C 2.644531 -1.035156 3.140625 -0.8125 3.734375 -0.8125 C 4.316406 -0.8125 4.800781 -1.035156 5.1875 -1.484375 C 5.582031 -1.929688 5.78125 -2.613281 5.78125 -3.53125 C 5.78125 -4.394531 5.582031 -5.050781 5.1875 -5.5 C 4.800781 -5.945313 4.316406 -6.171875 3.734375 -6.171875 C 3.140625 -6.171875 2.644531 -5.945313 2.25 -5.5 C 1.863281 -5.0625 1.671875 -4.394531 1.671875 -3.5 Z M 1.671875 -3.5 "
id="path36" />
</g>
<g
id="glyph-0-13">
<path
d="M 5.453125 -2.5625 L 6.609375 -2.40625 C 6.484375 -1.601563 6.160156 -0.972656 5.640625 -0.515625 C 5.117188 -0.0664063 4.472656 0.15625 3.703125 0.15625 C 2.742188 0.15625 1.972656 -0.15625 1.390625 -0.78125 C 0.816406 -1.40625 0.53125 -2.300781 0.53125 -3.46875 C 0.53125 -4.226563 0.65625 -4.890625 0.90625 -5.453125 C 1.15625 -6.015625 1.535156 -6.4375 2.046875 -6.71875 C 2.554688 -7.007813 3.113281 -7.15625 3.71875 -7.15625 C 4.476563 -7.15625 5.097656 -6.960938 5.578125 -6.578125 C 6.054688 -6.191406 6.363281 -5.644531 6.5 -4.9375 L 5.359375 -4.765625 C 5.242188 -5.234375 5.046875 -5.582031 4.765625 -5.8125 C 4.492188 -6.050781 4.160156 -6.171875 3.765625 -6.171875 C 3.160156 -6.171875 2.671875 -5.957031 2.296875 -5.53125 C 1.929688 -5.101563 1.75 -4.425781 1.75 -3.5 C 1.75 -2.5625 1.925781 -1.878906 2.28125 -1.453125 C 2.644531 -1.023438 3.113281 -0.8125 3.6875 -0.8125 C 4.15625 -0.8125 4.546875 -0.953125 4.859375 -1.234375 C 5.171875 -1.523438 5.367188 -1.96875 5.453125 -2.5625 Z M 5.453125 -2.5625 "
id="path39" />
</g>
<g
id="glyph-0-14">
<path
d="M 0.859375 0 L 0.859375 -9.65625 L 2.046875 -9.65625 L 2.046875 0 Z M 0.859375 0 "
id="path42" />
</g>
<g
id="glyph-0-15">
<path
d="M 0.890625 2.6875 L 0.890625 -7 L 1.96875 -7 L 1.96875 -6.078125 C 2.21875 -6.429688 2.503906 -6.695313 2.828125 -6.875 C 3.148438 -7.0625 3.539063 -7.15625 4 -7.15625 C 4.59375 -7.15625 5.117188 -7 5.578125 -6.6875 C 6.035156 -6.382813 6.378906 -5.953125 6.609375 -5.390625 C 6.835938 -4.828125 6.953125 -4.210938 6.953125 -3.546875 C 6.953125 -2.828125 6.820313 -2.179688 6.5625 -1.609375 C 6.3125 -1.035156 5.941406 -0.597656 5.453125 -0.296875 C 4.960938 0.00390625 4.445313 0.15625 3.90625 0.15625 C 3.507813 0.15625 3.15625 0.0703125 2.84375 -0.09375 C 2.53125 -0.257813 2.273438 -0.46875 2.078125 -0.71875 L 2.078125 2.6875 Z M 1.96875 -3.453125 C 1.96875 -2.554688 2.148438 -1.890625 2.515625 -1.453125 C 2.878906 -1.023438 3.316406 -0.8125 3.828125 -0.8125 C 4.359375 -0.8125 4.8125 -1.035156 5.1875 -1.484375 C 5.5625 -1.929688 5.75 -2.625 5.75 -3.5625 C 5.75 -4.445313 5.5625 -5.109375 5.1875 -5.546875 C 4.820313 -5.992188 4.390625 -6.21875 3.890625 -6.21875 C 3.378906 -6.21875 2.929688 -5.984375 2.546875 -5.515625 C 2.160156 -5.046875 1.96875 -4.359375 1.96875 -3.453125 Z M 1.96875 -3.453125 "
id="path45" />
</g>
<g
id="glyph-0-16">
<path
d="M 0.890625 -8.296875 L 0.890625 -9.65625 L 2.078125 -9.65625 L 2.078125 -8.296875 Z M 0.890625 0 L 0.890625 -7 L 2.078125 -7 L 2.078125 0 Z M 0.890625 0 "
id="path48" />
</g>
<g
id="glyph-0-17">
<path
d="M 0.421875 -2.09375 L 1.59375 -2.265625 C 1.65625 -1.796875 1.835938 -1.4375 2.140625 -1.1875 C 2.441406 -0.9375 2.859375 -0.8125 3.390625 -0.8125 C 3.941406 -0.8125 4.347656 -0.921875 4.609375 -1.140625 C 4.867188 -1.367188 5 -1.628906 5 -1.921875 C 5 -2.191406 4.882813 -2.40625 4.65625 -2.5625 C 4.488281 -2.664063 4.082031 -2.800781 3.4375 -2.96875 C 2.570313 -3.1875 1.96875 -3.375 1.625 -3.53125 C 1.289063 -3.6875 1.035156 -3.90625 0.859375 -4.1875 C 0.691406 -4.476563 0.609375 -4.796875 0.609375 -5.140625 C 0.609375 -5.453125 0.679688 -5.738281 0.828125 -6 C 0.972656 -6.269531 1.164063 -6.488281 1.40625 -6.65625 C 1.59375 -6.800781 1.84375 -6.921875 2.15625 -7.015625 C 2.476563 -7.109375 2.820313 -7.15625 3.1875 -7.15625 C 3.738281 -7.15625 4.21875 -7.070313 4.625 -6.90625 C 5.039063 -6.75 5.347656 -6.535156 5.546875 -6.265625 C 5.742188 -5.992188 5.878906 -5.632813 5.953125 -5.1875 L 4.796875 -5.03125 C 4.742188 -5.382813 4.59375 -5.660156 4.34375 -5.859375 C 4.09375 -6.066406 3.734375 -6.171875 3.265625 -6.171875 C 2.722656 -6.171875 2.335938 -6.082031 2.109375 -5.90625 C 1.878906 -5.726563 1.765625 -5.519531 1.765625 -5.28125 C 1.765625 -5.125 1.8125 -4.984375 1.90625 -4.859375 C 2 -4.734375 2.148438 -4.628906 2.359375 -4.546875 C 2.472656 -4.503906 2.820313 -4.398438 3.40625 -4.234375 C 4.238281 -4.015625 4.820313 -3.832031 5.15625 -3.6875 C 5.488281 -3.539063 5.75 -3.332031 5.9375 -3.0625 C 6.125 -2.789063 6.21875 -2.453125 6.21875 -2.046875 C 6.21875 -1.660156 6.101563 -1.289063 5.875 -0.9375 C 5.644531 -0.59375 5.3125 -0.320313 4.875 -0.125 C 4.445313 0.0625 3.957031 0.15625 3.40625 0.15625 C 2.5 0.15625 1.804688 -0.03125 1.328125 -0.40625 C 0.847656 -0.78125 0.546875 -1.34375 0.421875 -2.09375 Z M 0.421875 -2.09375 "
id="path51" />
</g>
<g
id="glyph-0-18">
<path
d="M 3.5 0 L 3.5 -8.515625 L 0.3125 -8.515625 L 0.3125 -9.65625 L 7.96875 -9.65625 L 7.96875 -8.515625 L 4.78125 -8.515625 L 4.78125 0 Z M 3.5 0 "
id="path54" />
</g>
<g
id="glyph-0-19">
<path
d="M 0.890625 0 L 0.890625 -7 L 1.953125 -7 L 1.953125 -6.015625 C 2.171875 -6.359375 2.460938 -6.632813 2.828125 -6.84375 C 3.191406 -7.050781 3.601563 -7.15625 4.0625 -7.15625 C 4.582031 -7.15625 5.007813 -7.046875 5.34375 -6.828125 C 5.675781 -6.609375 5.910156 -6.304688 6.046875 -5.921875 C 6.597656 -6.742188 7.316406 -7.15625 8.203125 -7.15625 C 8.898438 -7.15625 9.429688 -6.960938 9.796875 -6.578125 C 10.171875 -6.191406 10.359375 -5.597656 10.359375 -4.796875 L 10.359375 0 L 9.1875 0 L 9.1875 -4.40625 C 9.1875 -4.875 9.144531 -5.210938 9.0625 -5.421875 C 8.988281 -5.628906 8.847656 -5.796875 8.640625 -5.921875 C 8.441406 -6.054688 8.207031 -6.125 7.9375 -6.125 C 7.445313 -6.125 7.039063 -5.957031 6.71875 -5.625 C 6.394531 -5.300781 6.234375 -4.78125 6.234375 -4.0625 L 6.234375 0 L 5.046875 0 L 5.046875 -4.546875 C 5.046875 -5.066406 4.945313 -5.457031 4.75 -5.71875 C 4.5625 -5.988281 4.25 -6.125 3.8125 -6.125 C 3.476563 -6.125 3.164063 -6.035156 2.875 -5.859375 C 2.59375 -5.679688 2.390625 -5.421875 2.265625 -5.078125 C 2.140625 -4.742188 2.078125 -4.257813 2.078125 -3.625 L 2.078125 0 Z M 0.890625 0 "
id="path57" />
</g>
<g
id="glyph-0-20">
<path
d="M 0.984375 0 L 0.984375 -9.65625 L 2.265625 -9.65625 L 2.265625 -4.859375 L 7.0625 -9.65625 L 8.796875 -9.65625 L 4.734375 -5.734375 L 8.96875 0 L 7.28125 0 L 3.84375 -4.890625 L 2.265625 -3.34375 L 2.265625 0 Z M 0.984375 0 "
id="path60" />
</g>
<g
id="glyph-0-21">
<path
d="M 0.890625 0 L 0.890625 -7 L 1.953125 -7 L 1.953125 -6 C 2.460938 -6.769531 3.207031 -7.15625 4.1875 -7.15625 C 4.601563 -7.15625 4.988281 -7.078125 5.34375 -6.921875 C 5.695313 -6.773438 5.960938 -6.578125 6.140625 -6.328125 C 6.316406 -6.078125 6.4375 -5.785156 6.5 -5.453125 C 6.550781 -5.234375 6.578125 -4.847656 6.578125 -4.296875 L 6.578125 0 L 5.390625 0 L 5.390625 -4.25 C 5.390625 -4.738281 5.34375 -5.097656 5.25 -5.328125 C 5.15625 -5.566406 4.988281 -5.757813 4.75 -5.90625 C 4.519531 -6.050781 4.25 -6.125 3.9375 -6.125 C 3.425781 -6.125 2.988281 -5.960938 2.625 -5.640625 C 2.257813 -5.316406 2.078125 -4.707031 2.078125 -3.8125 L 2.078125 0 Z M 0.890625 0 "
id="path63" />
</g>
</g>
<clipPath
id="clip-0">
<path
clip-rule="nonzero"
d="M 116 221 L 216 221 L 216 272.046875 L 116 272.046875 Z M 116 221 "
id="path68" />
</clipPath>
<clipPath
id="clip-1">
<path
clip-rule="nonzero"
d="M 240 150 L 331.921875 150 L 331.921875 197 L 240 197 Z M 240 150 "
id="path71" />
</clipPath>
</defs>
<path
fill-rule="nonzero"
fill="rgb(100%, 100%, 100%)"
fill-opacity="1"
d="M 127.777344 225.953125 L 204.222656 225.953125 C 204.664063 225.953125 205.101563 225.996094 205.535156 226.085938 C 205.972656 226.171875 206.394531 226.296875 206.800781 226.46875 C 207.210938 226.636719 207.601563 226.84375 207.96875 227.089844 C 208.335938 227.335938 208.675781 227.617188 208.992188 227.929688 C 209.304688 228.242188 209.582031 228.585938 209.828125 228.953125 C 210.074219 229.320313 210.28125 229.710938 210.453125 230.117188 C 210.621094 230.527344 210.75 230.949219 210.835938 231.382813 C 210.921875 231.816406 210.964844 232.257813 210.964844 232.699219 L 210.964844 264.175781 C 210.964844 264.617188 210.921875 265.058594 210.835938 265.492188 C 210.75 265.925781 210.621094 266.347656 210.453125 266.757813 C 210.28125 267.167969 210.074219 267.554688 209.828125 267.921875 C 209.582031 268.292969 209.304688 268.632813 208.992188 268.945313 C 208.675781 269.257813 208.335938 269.539063 207.96875 269.785156 C 207.601563 270.03125 207.210938 270.238281 206.800781 270.40625 C 206.394531 270.578125 205.972656 270.703125 205.535156 270.792969 C 205.101563 270.878906 204.664063 270.921875 204.222656 270.921875 L 127.777344 270.921875 C 127.335938 270.921875 126.898438 270.878906 126.460938 270.792969 C 126.027344 270.703125 125.605469 270.578125 125.199219 270.40625 C 124.789063 270.238281 124.398438 270.03125 124.03125 269.785156 C 123.664063 269.539063 123.324219 269.257813 123.007813 268.945313 C 122.695313 268.632813 122.417969 268.292969 122.171875 267.921875 C 121.925781 267.554688 121.714844 267.167969 121.546875 266.757813 C 121.378906 266.347656 121.25 265.925781 121.164063 265.492188 C 121.078125 265.058594 121.035156 264.617188 121.035156 264.175781 L 121.035156 232.699219 C 121.035156 232.257813 121.078125 231.816406 121.164063 231.382813 C 121.25 230.949219 121.378906 230.527344 121.546875 230.117188 C 121.714844 229.710938 121.925781 229.320313 122.171875 228.953125 C 122.417969 228.585938 122.695313 228.242188 123.007813 227.929688 C 123.324219 227.617188 123.664063 227.335938 124.03125 227.089844 C 124.398438 226.84375 124.789063 226.636719 125.199219 226.46875 C 125.605469 226.296875 126.027344 226.171875 126.460938 226.085938 C 126.898438 225.996094 127.335938 225.953125 127.777344 225.953125 Z M 127.777344 225.953125 "
id="path76" />
<g
clip-path="url(#clip-0)"
id="g80">
<path
fill="none"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="#000000"
stroke-opacity="1"
stroke-miterlimit="4"
d="m 169.99809,300.99772 h 102.00385 c 0.58898,0 1.17276,0.0573 1.75132,0.17721 0.58377,0.11467 1.14669,0.28146 1.68877,0.51081 0.54728,0.22412 1.06851,0.50037 1.55846,0.82874 0.48995,0.32837 0.94342,0.70366 1.36561,1.12064 0.41698,0.41698 0.78705,0.87566 1.11542,1.36561 0.32838,0.48995 0.60463,1.01118 0.83397,1.55325 0.22412,0.54729 0.39613,1.11021 0.5108,1.68877 0.11467,0.57856 0.172,1.16755 0.172,1.75653 v 42.00036 c 0,0.58898 -0.0573,1.17797 -0.172,1.75653 -0.11467,0.57856 -0.28668,1.14148 -0.5108,1.68877 -0.22934,0.54729 -0.50559,1.0633 -0.83397,1.55325 -0.32837,0.49517 -0.69844,0.94863 -1.11542,1.36561 -0.42219,0.41698 -0.87566,0.79227 -1.36561,1.12064 -0.48995,0.32837 -1.01118,0.60462 -1.55846,0.82875 -0.54208,0.22934 -1.105,0.39613 -1.68877,0.51601 -0.57856,0.11467 -1.16234,0.172 -1.75132,0.172 H 169.99809 c -0.58898,0 -1.17275,-0.0573 -1.75653,-0.172 -0.57856,-0.11988 -1.14148,-0.28667 -1.68355,-0.51601 -0.54729,-0.22413 -1.06852,-0.50038 -1.55847,-0.82875 -0.48995,-0.32837 -0.94342,-0.70366 -1.36561,-1.12064 -0.41698,-0.41698 -0.78705,-0.87044 -1.11542,-1.36561 -0.32837,-0.48995 -0.60984,-1.00596 -0.83396,-1.55325 -0.22413,-0.54729 -0.39613,-1.11021 -0.5108,-1.68877 -0.11467,-0.57856 -0.17201,-1.16755 -0.17201,-1.75653 v -42.00036 c 0,-0.58898 0.0573,-1.17797 0.17201,-1.75653 0.11467,-0.57856 0.28667,-1.14148 0.5108,-1.68877 0.22412,-0.54207 0.50559,-1.0633 0.83396,-1.55325 0.32837,-0.48995 0.69844,-0.94863 1.11542,-1.36561 0.42219,-0.41698 0.87566,-0.79227 1.36561,-1.12064 0.48995,-0.32837 1.01118,-0.60462 1.55847,-0.82874 0.54207,-0.22935 1.10499,-0.39614 1.68355,-0.51081 0.58378,-0.11988 1.16755,-0.17721 1.75653,-0.17721 z m 0,0"
transform="matrix(0.749436,0,0,0.749436,0.374718,0.374718)"
id="path78" />
</g>
<g
fill="#000000"
fill-opacity="1"
id="g90">
<use
xlink:href="#glyph-0-1"
x="149.87541"
y="244.31601"
id="use82" />
<use
xlink:href="#glyph-0-2"
x="158.87303"
y="244.31601"
id="use84" />
<use
xlink:href="#glyph-0-3"
x="167.87065"
y="244.31601"
id="use86" />
<use
xlink:href="#glyph-0-4"
x="171.61856"
y="244.31601"
id="use88" />
</g>
<g
fill="#000000"
fill-opacity="1"
id="g108">
<use
xlink:href="#glyph-0-5"
x="136.38557"
y="260.80359"
id="use92" />
<use
xlink:href="#glyph-0-6"
x="146.1275"
y="260.80359"
id="use94" />
<use
xlink:href="#glyph-0-7"
x="153.62991"
y="260.80359"
id="use96" />
<use
xlink:href="#glyph-0-8"
x="158.12213"
y="260.80359"
id="use98" />
<use
xlink:href="#glyph-0-9"
x="165.62454"
y="260.80359"
id="use100" />
<use
xlink:href="#glyph-0-6"
x="175.36647"
y="260.80359"
id="use102" />
<use
xlink:href="#glyph-0-7"
x="182.86888"
y="260.80359"
id="use104" />
<use
xlink:href="#glyph-0-10"
x="187.3611"
y="260.80359"
id="use106" />
</g>
<path
fill="none"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="rgb(0%, 0%, 0%)"
stroke-opacity="1"
stroke-miterlimit="10"
d="M 221.000017 260.998867 L 221.000017 294.62834 "
transform="matrix(0.749436, 0, 0, 0.749436, 0.374718, 0.374718)"
id="path110" />
<path
fill-rule="nonzero"
fill="rgb(0%, 0%, 0%)"
fill-opacity="1"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="rgb(0%, 0%, 0%)"
stroke-opacity="1"
stroke-miterlimit="10"
d="M 221.000017 299.882294 L 217.502593 292.882235 L 221.000017 294.62834 L 224.49744 292.882235 Z M 221.000017 299.882294 "
transform="matrix(0.749436, 0, 0, 0.749436, 0.374718, 0.374718)"
id="path112" />
<path
fill-rule="nonzero"
fill="rgb(100%, 100%, 100%)"
fill-opacity="1"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="rgb(0%, 0%, 0%)"
stroke-opacity="1"
stroke-miterlimit="4"
d="M 161.001742 201.000592 L 280.998292 201.000592 L 280.998292 260.998867 L 161.001742 260.998867 Z M 161.001742 201.000592 "
transform="matrix(0.749436, 0, 0, 0.749436, 0.374718, 0.374718)"
id="path114" />
<g
fill="#000000"
fill-opacity="1"
id="g134">
<use
xlink:href="#glyph-0-11"
x="136.37386"
y="169.37245"
id="use116" />
<use
xlink:href="#glyph-0-12"
x="143.87627"
y="169.37245"
id="use118" />
<use
xlink:href="#glyph-0-13"
x="151.37868"
y="169.37245"
id="use120" />
<use
xlink:href="#glyph-0-6"
x="158.1236"
y="169.37245"
id="use122" />
<use
xlink:href="#glyph-0-14"
x="165.62601"
y="169.37245"
id="use124" />
<use
xlink:href="#glyph-0-1"
x="168.62302"
y="169.37245"
id="use126" />
<use
xlink:href="#glyph-0-15"
x="177.62064"
y="169.37245"
id="use128" />
<use
xlink:href="#glyph-0-16"
x="185.12303"
y="169.37245"
id="use130" />
<use
xlink:href="#glyph-0-13"
x="188.12004"
y="169.37245"
id="use132" />
</g>
<g
fill="#000000"
fill-opacity="1"
id="g146">
<use
xlink:href="#glyph-0-4"
x="148.75127"
y="185.86003"
id="use136" />
<use
xlink:href="#glyph-0-14"
x="158.49319"
y="185.86003"
id="use138" />
<use
xlink:href="#glyph-0-6"
x="161.4902"
y="185.86003"
id="use140" />
<use
xlink:href="#glyph-0-17"
x="168.99261"
y="185.86003"
id="use142" />
<use
xlink:href="#glyph-0-17"
x="175.73753"
y="185.86003"
id="use144" />
</g>
<path
fill="none"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="rgb(0%, 0%, 0%)"
stroke-opacity="1"
stroke-miterlimit="10"
d="M 60.999405 260.998867 L 60.999405 330.999461 L 154.632365 330.999461 "
transform="matrix(0.749436, 0, 0, 0.749436, 0.374718, 0.374718)"
id="path148" />
<path
fill-rule="nonzero"
fill="rgb(0%, 0%, 0%)"
fill-opacity="1"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="rgb(0%, 0%, 0%)"
stroke-opacity="1"
stroke-miterlimit="10"
d="M 159.881107 330.999461 L 152.881048 334.502096 L 154.632365 330.999461 L 152.881048 327.502037 Z M 159.881107 330.999461 "
transform="matrix(0.749436, 0, 0, 0.749436, 0.374718, 0.374718)"
id="path150" />
<path
fill="none"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="rgb(0%, 0%, 0%)"
stroke-opacity="1"
stroke-miterlimit="10"
d="M 120.99768 231.002336 L 154.632365 231.002336 "
transform="matrix(0.749436, 0, 0, 0.749436, 0.374718, 0.374718)"
id="path152" />
<path
fill-rule="nonzero"
fill="rgb(0%, 0%, 0%)"
fill-opacity="1"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="rgb(0%, 0%, 0%)"
stroke-opacity="1"
stroke-miterlimit="10"
d="M 159.881107 231.002336 L 152.881048 234.499759 L 154.632365 231.002336 L 152.881048 227.4997 Z M 159.881107 231.002336 "
transform="matrix(0.749436, 0, 0, 0.749436, 0.374718, 0.374718)"
id="path154" />
<path
fill-rule="nonzero"
fill="rgb(100%, 100%, 100%)"
fill-opacity="1"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="rgb(0%, 0%, 0%)"
stroke-opacity="1"
stroke-miterlimit="4"
d="M 1.00113 201.000592 L 120.99768 201.000592 L 120.99768 260.998867 L 1.00113 260.998867 Z M 1.00113 201.000592 "
transform="matrix(0.749436, 0, 0, 0.749436, 0.374718, 0.374718)"
id="path156" />
<g
fill="#000000"
fill-opacity="1"
id="g170">
<use
xlink:href="#glyph-0-3"
x="26.967972"
y="169.37245"
id="use158" />
<use
xlink:href="#glyph-0-12"
x="30.715881"
y="169.37245"
id="use160" />
<use
xlink:href="#glyph-0-1"
x="38.218288"
y="169.37245"
id="use162" />
<use
xlink:href="#glyph-0-15"
x="47.215908"
y="169.37245"
id="use164" />
<use
xlink:href="#glyph-0-16"
x="54.718315"
y="169.37245"
id="use166" />
<use
xlink:href="#glyph-0-13"
x="57.715324"
y="169.37245"
id="use168" />
</g>
<g
fill="#000000"
fill-opacity="1"
id="g182">
<use
xlink:href="#glyph-0-4"
x="28.84156"
y="185.86003"
id="use172" />
<use
xlink:href="#glyph-0-14"
x="38.583492"
y="185.86003"
id="use174" />
<use
xlink:href="#glyph-0-6"
x="41.580502"
y="185.86003"
id="use176" />
<use
xlink:href="#glyph-0-17"
x="49.082909"
y="185.86003"
id="use178" />
<use
xlink:href="#glyph-0-17"
x="55.827831"
y="185.86003"
id="use180" />
</g>
<path
fill="none"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="rgb(0%, 0%, 0%)"
stroke-opacity="1"
stroke-miterlimit="10"
d="M 381.000629 260.998867 L 381.000629 330.999461 L 287.367668 330.999461 "
transform="matrix(0.749436, 0, 0, 0.749436, 0.374718, 0.374718)"
id="path184" />
<path
fill-rule="nonzero"
fill="rgb(0%, 0%, 0%)"
fill-opacity="1"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="rgb(0%, 0%, 0%)"
stroke-opacity="1"
stroke-miterlimit="10"
d="M 282.118927 330.999461 L 289.118986 327.502037 L 287.367668 330.999461 L 289.118986 334.502096 Z M 282.118927 330.999461 "
transform="matrix(0.749436, 0, 0, 0.749436, 0.374718, 0.374718)"
id="path186" />
<path
fill="none"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="rgb(0%, 0%, 0%)"
stroke-opacity="1"
stroke-miterlimit="10"
d="M 321.002354 231.002336 L 287.367668 231.002336 "
transform="matrix(0.749436, 0, 0, 0.749436, 0.374718, 0.374718)"
id="path188" />
<path
fill-rule="nonzero"
fill="rgb(0%, 0%, 0%)"
fill-opacity="1"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="rgb(0%, 0%, 0%)"
stroke-opacity="1"
stroke-miterlimit="10"
d="M 282.118927 231.002336 L 289.118986 227.4997 L 287.367668 231.002336 L 289.118986 234.499759 Z M 282.118927 231.002336 "
transform="matrix(0.749436, 0, 0, 0.749436, 0.374718, 0.374718)"
id="path190" />
<path
fill-rule="nonzero"
fill="rgb(100%, 100%, 100%)"
fill-opacity="1"
d="M 240.945313 151.011719 L 330.875 151.011719 L 330.875 195.976563 L 240.945313 195.976563 Z M 240.945313 151.011719 "
id="path192" />
<g
clip-path="url(#clip-1)"
id="g196">
<path
fill="none"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="#000000"
stroke-opacity="1"
stroke-miterlimit="4"
d="M 321.00235,201.00059 H 440.9989 v 59.99828 H 321.00235 Z m 0,0"
transform="matrix(0.749436,0,0,0.749436,0.374718,0.374718)"
id="path194" />
</g>
<g
fill="#000000"
fill-opacity="1"
id="g208">
<use
xlink:href="#glyph-0-1"
x="255.42874"
y="169.37245"
id="use198" />
<use
xlink:href="#glyph-0-15"
x="264.42636"
y="169.37245"
id="use200" />
<use
xlink:href="#glyph-0-16"
x="271.92877"
y="169.37245"
id="use202" />
<use
xlink:href="#glyph-0-13"
x="274.92578"
y="169.37245"
id="use204" />
<use
xlink:href="#glyph-0-18"
x="281.67068"
y="169.37245"
id="use206" />
</g>
<g
fill="#000000"
fill-opacity="1"
id="g218">
<use
xlink:href="#glyph-0-16"
x="289.41022"
y="169.37245"
id="use210" />
<use
xlink:href="#glyph-0-19"
x="292.40723"
y="169.37245"
id="use212" />
<use
xlink:href="#glyph-0-10"
x="303.64438"
y="169.37245"
id="use214" />
<use
xlink:href="#glyph-0-7"
x="311.14679"
y="169.37245"
id="use216" />
</g>
<g
fill="#000000"
fill-opacity="1"
id="g230">
<use
xlink:href="#glyph-0-4"
x="268.66095"
y="185.86003"
id="use220" />
<use
xlink:href="#glyph-0-14"
x="278.40289"
y="185.86003"
id="use222" />
<use
xlink:href="#glyph-0-6"
x="281.3999"
y="185.86003"
id="use224" />
<use
xlink:href="#glyph-0-17"
x="288.90231"
y="185.86003"
id="use226" />
<use
xlink:href="#glyph-0-17"
x="295.64722"
y="185.86003"
id="use228" />
</g>
<path
fill="none"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="rgb(0%, 0%, 0%)"
stroke-opacity="1"
stroke-miterlimit="10"
d="M 161.001742 130.999998 L 60.999405 130.999998 L 60.999405 194.631215 "
transform="matrix(0.749436, 0, 0, 0.749436, 0.374718, 0.374718)"
id="path232" />
<path
fill-rule="nonzero"
fill="rgb(0%, 0%, 0%)"
fill-opacity="1"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="rgb(0%, 0%, 0%)"
stroke-opacity="1"
stroke-miterlimit="10"
d="M 60.999405 199.879957 L 57.501981 192.879898 L 60.999405 194.631215 L 64.50204 192.879898 Z M 60.999405 199.879957 "
transform="matrix(0.749436, 0, 0, 0.749436, 0.374718, 0.374718)"
id="path234" />
<path
fill="none"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="rgb(0%, 0%, 0%)"
stroke-opacity="1"
stroke-miterlimit="10"
d="M 221.000017 161.001742 L 221.000017 194.631215 "
transform="matrix(0.749436, 0, 0, 0.749436, 0.374718, 0.374718)"
id="path236" />
<path
fill-rule="nonzero"
fill="rgb(0%, 0%, 0%)"
fill-opacity="1"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="rgb(0%, 0%, 0%)"
stroke-opacity="1"
stroke-miterlimit="10"
d="M 221.000017 199.879957 L 217.502593 192.879898 L 221.000017 194.631215 L 224.49744 192.879898 Z M 221.000017 199.879957 "
transform="matrix(0.749436, 0, 0, 0.749436, 0.374718, 0.374718)"
id="path238" />
<path
fill="none"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="rgb(0%, 0%, 0%)"
stroke-opacity="1"
stroke-miterlimit="10"
d="M 280.998292 130.999998 L 381.000629 130.999998 L 381.000629 194.631215 "
transform="matrix(0.749436, 0, 0, 0.749436, 0.374718, 0.374718)"
id="path240" />
<path
fill-rule="nonzero"
fill="rgb(0%, 0%, 0%)"
fill-opacity="1"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="rgb(0%, 0%, 0%)"
stroke-opacity="1"
stroke-miterlimit="10"
d="M 381.000629 199.879957 L 377.497993 192.879898 L 381.000629 194.631215 L 384.498053 192.879898 Z M 381.000629 199.879957 "
transform="matrix(0.749436, 0, 0, 0.749436, 0.374718, 0.374718)"
id="path242" />
<path
fill-rule="nonzero"
fill="rgb(100%, 100%, 100%)"
fill-opacity="1"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="rgb(0%, 0%, 0%)"
stroke-opacity="1"
stroke-miterlimit="4"
d="M 161.001742 100.998255 L 280.998292 100.998255 L 280.998292 161.001742 L 161.001742 161.001742 Z M 161.001742 100.998255 "
transform="matrix(0.749436, 0, 0, 0.749436, 0.374718, 0.374718)"
id="path244" />
<g
fill="#000000"
fill-opacity="1"
id="g254">
<use
xlink:href="#glyph-0-1"
x="152.49844"
y="94.428886"
id="use246" />
<use
xlink:href="#glyph-0-15"
x="161.49606"
y="94.428886"
id="use248" />
<use
xlink:href="#glyph-0-16"
x="168.99846"
y="94.428886"
id="use250" />
<use
xlink:href="#glyph-0-13"
x="171.99548"
y="94.428886"
id="use252" />
</g>
<g
fill="#000000"
fill-opacity="1"
id="g266">
<use
xlink:href="#glyph-0-4"
x="148.75127"
y="110.91647"
id="use256" />
<use
xlink:href="#glyph-0-14"
x="158.49319"
y="110.91647"
id="use258" />
<use
xlink:href="#glyph-0-6"
x="161.4902"
y="110.91647"
id="use260" />
<use
xlink:href="#glyph-0-17"
x="168.99261"
y="110.91647"
id="use262" />
<use
xlink:href="#glyph-0-17"
x="175.73753"
y="110.91647"
id="use264" />
</g>
<path
fill="none"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="rgb(0%, 0%, 0%)"
stroke-opacity="1"
stroke-miterlimit="10"
d="M 221.000017 60.999405 L 221.000017 94.628878 "
transform="matrix(0.749436, 0, 0, 0.749436, 0.374718, 0.374718)"
id="path268" />
<path
fill-rule="nonzero"
fill="rgb(0%, 0%, 0%)"
fill-opacity="1"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="rgb(0%, 0%, 0%)"
stroke-opacity="1"
stroke-miterlimit="10"
d="M 221.000017 99.87762 L 217.502593 92.87756 L 221.000017 94.628878 L 224.49744 92.87756 Z M 221.000017 99.87762 "
transform="matrix(0.749436, 0, 0, 0.749436, 0.374718, 0.374718)"
id="path270" />
<path
fill-rule="nonzero"
fill="rgb(100%, 100%, 100%)"
fill-opacity="1"
stroke-width="1"
stroke-linecap="butt"
stroke-linejoin="miter"
stroke="rgb(0%, 0%, 0%)"
stroke-opacity="1"
stroke-miterlimit="4"
d="M 169.998095 1.00113 L 272.001939 1.00113 C 272.590923 1.00113 273.174696 1.058464 273.753257 1.173134 C 274.337029 1.287804 274.899953 1.459808 275.442027 1.683935 C 275.989314 1.913274 276.51054 2.189524 277.000492 2.517896 C 277.490444 2.846268 277.94391 3.216338 278.366103 3.638531 C 278.783083 4.055511 279.153153 4.508978 279.481525 4.99893 C 279.809898 5.488882 280.086147 6.010107 280.315486 6.557394 C 280.539613 7.099469 280.711618 7.662392 280.826287 8.246165 C 280.940957 8.824725 280.998292 9.408498 280.998292 9.997483 L 280.998292 51.997839 C 280.998292 52.592036 280.940957 53.175809 280.826287 53.754369 C 280.711618 54.33293 280.539613 54.895853 280.315486 55.44314 C 280.086147 55.990427 279.809898 56.50644 279.481525 57.001605 C 279.153153 57.491557 278.783083 57.945023 278.366103 58.362003 C 277.94391 58.784196 277.490444 59.154266 277.000492 59.482638 C 276.51054 59.81101 275.989314 60.08726 275.442027 60.316599 C 274.899953 60.540726 274.337029 60.712731 273.753257 60.8274 C 273.174696 60.94207 272.590923 60.999405 272.001939 60.999405 L 169.998095 60.999405 C 169.40911 60.999405 168.825338 60.94207 168.241565 60.8274 C 167.663005 60.712731 167.100081 60.540726 166.558006 60.316599 C 166.01072 60.08726 165.489494 59.81101 164.999542 59.482638 C 164.50959 59.154266 164.056124 58.784196 163.633931 58.362003 C 163.216951 57.945023 162.84688 57.491557 162.518508 57.001605 C 162.190136 56.50644 161.908674 55.990427 161.684547 55.44314 C 161.46042 54.895853 161.288416 54.33293 161.173746 53.754369 C 161.059077 53.175809 161.001742 52.592036 161.001742 51.997839 L 161.001742 9.997483 C 161.001742 9.408498 161.059077 8.824725 161.173746 8.246165 C 161.288416 7.662392 161.46042 7.099469 161.684547 6.557394 C 161.908674 6.010107 162.190136 5.488882 162.518508 4.99893 C 162.84688 4.508978 163.216951 4.055511 163.633931 3.638531 C 164.056124 3.216338 164.50959 2.846268 164.999542 2.517896 C 165.489494 2.189524 166.01072 1.913274 166.558006 1.683935 C 167.100081 1.459808 167.663005 1.287804 168.241565 1.173134 C 168.825338 1.058464 169.40911 1.00113 169.998095 1.00113 Z M 169.998095 1.00113 "
transform="matrix(0.749436, 0, 0, 0.749436, 0.374718, 0.374718)"
id="path272" />
<g
fill="#000000"
fill-opacity="1"
id="g286">
<use
xlink:href="#glyph-0-20"
x="146.12823"
y="27.729118"
id="use274" />
<use
xlink:href="#glyph-0-10"
x="155.12585"
y="27.729118"
id="use276" />
<use
xlink:href="#glyph-0-7"
x="162.62827"
y="27.729118"
id="use278" />
<use
xlink:href="#glyph-0-21"
x="167.12048"
y="27.729118"
id="use280" />
<use
xlink:href="#glyph-0-10"
x="174.62289"
y="27.729118"
id="use282" />
<use
xlink:href="#glyph-0-14"
x="182.12531"
y="27.729118"
id="use284" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 42 KiB

94
img/hhu_color.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 25 KiB

3297
img/ia32_apic_base_msr.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 301 KiB

4730
img/ia32_apic_svr.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 281 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 265 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 332 KiB

7178
img/ia32_lvt.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 300 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 404 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 264 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 186 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 205 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 125 KiB

69
properties.tex Normal file
View File

@ -0,0 +1,69 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Titel der Arbeit %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\thesistitle{Interrupt Handling using the x86 APIC}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Schlüsselwörter %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\thesiskeywords{Interrupt,APIC,hhuOS}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Sprache der Arbeit %
% %
% ngerman - Deutsch (neue Rechtschreibung) %
% english - Englisch %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\thesislanguage{english}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Art der Arbeit %
% %
% bachelor - Bachelorarbeit %
% master - Masterarbeit %
% project - Projektarbeit %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\thesistype{bachelor}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Ausgabe von Verzeichnissen %
% %
% true - Aktiviert %
% false - Deaktiviert %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\glossaryenabled{true}
\listofalgorithmsenabled{false}
\listoffiguresenabled{true}
\listoftablesenabled{true}
\hidefigures{false}
\hidecode{false}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Vollständiger Name %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\thesisauthor{Christoph Urlacher}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Geburtsort %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\authorbirthplace{Ratingen}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Datum der Abgabe %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\submissiondate{March 15th, 2023}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Erstgutachter %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\firstreviewer{Prof. Dr. Michael Schöttner}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Zweitgutachter %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\secondreviewer{Prof. Dr. Stefan Conrad}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Betreuer %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\supervisor{M.Sc. Fabian Ruhland}

270
references.bib Normal file
View File

@ -0,0 +1,270 @@
@Manual{pic,
month = jun,
organization = {Intel Corporation},
title = {{Intel 8259A Datasheet}},
url = {https://pdos.csail.mit.edu/6.828/2017/readings/hardware/8259A.pdf},
urldate = {2023-02-08},
year = {1978},
note = {Rev 3},
comment = {Datasheet for Intel's Programmable Interrupt Controller},
file = {:/home/christoph/Notes/HHU/Bachelorarbeit/literature/Intel 8259A Datasheet.pdf:PDF},
keywords = {PIC},
}
@Manual{ia32,
month = dec,
organization = {Intel Corporation},
title = {{Intel 64 and IA-32 Architectures Software Developer's Manual}},
url = {https://cdrdv2.intel.com/v1/dl/getContent/671200},
urldate = {2023-02-08},
year = {2022},
abstract = {The general manual for Intel's 32 bit and 64 bit architectures},
file = {:/home/christoph/Notes/HHU/Bachelorarbeit/literature/Intel 64 and IA-32 Manual.pdf:PDF},
keywords = {x86, Intel 64, Intel IA-32},
}
@Manual{ioapic,
month = may,
organization = {Intel Corporation},
title = {{Intel 82093AA Datasheet}},
url = {https://pdos.csail.mit.edu/6.828/2017/readings/ia32/ioapic.pdf},
urldate = {2023-02-08},
year = {1996},
comment = {Datasheet of Intel's external I/O APIC},
file = {:/home/christoph/Notes/HHU/Bachelorarbeit/literature/Intel 82093AA Datasheet.pdf:PDF},
keywords = {I/O APIC},
}
@Manual{acpi1,
month = feb,
organization = {UEFI Forum},
title = {{Advanced Configuration and Power Interface Specification}},
url = {http://uefi.org/sites/default/files/resources/ACPI_1_Errata_B.pdf},
urldate = {2023-02-08},
year = {1999},
note = {Rev 1.0b},
file = {:/home/christoph/Notes/HHU/Bachelorarbeit/literature/ACPI 1 Specification.pdf:PDF},
}
@Manual{acpi2,
month = aug,
organization = {UEFI Forum},
title = {{Advanced Configuration and Power Interface Specification}},
url = {http://uefi.org/sites/default/files/resources/ACPI_2_Errata_C.pdf},
urldate = {2023-02-08},
year = {2003},
note = {Rev 2.0c},
file = {:/home/christoph/Notes/HHU/Bachelorarbeit/literature/ACPI 2 Specification.pdf:PDF},
}
@Manual{acpi65,
month = aug,
organization = {UEFI Forum},
title = {{Advanced Configuration and Power Interface Specification}},
url = {https://uefi.org/sites/default/files/resources/ACPI_Spec_6_5_Aug29.pdf},
urldate = {2023-02-08},
year = {2022},
note = {Rev 6.5},
file = {:/home/christoph/Notes/HHU/Bachelorarbeit/literature/ACPI 6_5 Specification.pdf:PDF},
keywords = {ACPI Specification, UEFI},
}
@Manual{cpp20draft,
month = oct,
organization = {ISO/IEC JTC and SC22 WG21 and N4860},
title = {{C++20 International Standard Draft}},
url = {https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/n4868.pdf},
urldate = {2023-02-08},
year = {2020},
note = {N4860},
abstract = {C++ Draft International Standard},
file = {:/home/christoph/Notes/HHU/Bachelorarbeit/literature/C++20 Standard Draft.pdf:PDF},
}
@Manual{c99draft,
month = sep,
organization = {ISO/IEC JTC SC22 WG14},
title = {{C99 International Standard Draft}},
url = {https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf},
urldate = {2023-02-08},
year = {1999},
note = {N1256},
abstract = {Programming languages - C},
file = {:/home/christoph/Notes/HHU/Bachelorarbeit/literature/C99 Standard Draft.pdf:PDF},
}
@Manual{ich2,
month = oct,
organization = {Intel Corporation},
title = {{Intel ICH2 Datasheet}},
url = {https://www.intel.com/content/dam/doc/datasheet/82801ba-i-o-controller-hub-2-82801bam-i-o-controller-hub-2-mobile-datasheet.pdf},
urldate = {2023-02-08},
year = {2000},
file = {:/home/christoph/Notes/HHU/Bachelorarbeit/literature/Intel ICH2 Datasheet.pdf:PDF},
}
@Manual{ich5,
month = apr,
organization = {Intel Corporation},
title = {{Intel ICH5 Datasheet}},
url = {https://www.intel.com/content/dam/doc/datasheet/82801eb-82801er-io-controller-hub-datasheet.pdf},
urldate = {2023-02-08},
year = {2003},
note = {Rev 001},
file = {:/home/christoph/Notes/HHU/Bachelorarbeit/literature/Intel ICH5 Datasheet.pdf:PDF},
}
@Manual{mpspec,
month = may,
organization = {Intel Corporation},
title = {{Intel MultiProcessor Specification}},
url = {https://web.archive.org/web/20121002210153/http://download.intel.com/design/archives/processors/pro/docs/24201606.pdf},
urldate = {2023-02-08},
year = {1997},
note = {Rev 1.4},
file = {:/home/christoph/Notes/HHU/Bachelorarbeit/literature/Intel MultiProcessor Specification.pdf:PDF},
}
@TechReport{msilatency,
author = {Coleman, James},
institution = {Intel Corporation},
title = {{Reducing Interrupt Latency Through the Use of Message Signalled Interrupts}},
year = {2009},
month = jan,
type = {techreport},
file = {:/home/christoph/Notes/HHU/Bachelorarbeit/literature/Intel Reducing Interrupt Latency through the Use of MSIs Whitepaper.pdf:PDF},
url = {https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/msg-signaled-interrupts-paper.pdf},
}
@Manual{cpuid,
month = may,
organization = {Intel Corporation},
title = {{Intel Processor Identification and the CPUID Instruction}},
url = {https://www.scss.tcd.ie/~jones/CS4021/processor-identification-cpuid-instruction-note.pdf},
urldate = {2023-02-08},
year = {2012},
file = {:/home/christoph/Notes/HHU/Bachelorarbeit/literature/Intel CPUID Application Note.pdf:PDF},
}
@Misc{hhuos,
author = {Akguel, Burak and Gesse, Christian and Ruhland, Fabian and Krakowski, Filip and Schoettner, Michael and others},
howpublished = {GitHub},
note = {Branch "experimental"},
title = {{hhuOS - A small operating system}},
url = {https://github.com/hhuOS/hhuOS/tree/experimental},
urldate = {2023-02-08},
}
@Manual{pci22,
month = dec,
organization = {PCI Special Interest Group},
title = {{PCI 2.2 Local Bus Specification}},
url = {https://www.ics.uci.edu/~harris/ics216/pci/PCI_22.pdf},
urldate = {2023-02-08},
year = {1998},
note = {Rev 2.2},
file = {:/home/christoph/Notes/HHU/Bachelorarbeit/literature/PCI 2_2 Specification.pdf:PDF},
}
@Manual{pcat,
month = mar,
organization = {IBM},
title = {{PC/AT Technical Reference}},
url = {http://bitsavers.informatik.uni-stuttgart.de/pdf/ibm/pc/at/6183355_PC_AT_Technical_Reference_Mar86.pdf},
urldate = {2023-02-08},
year = {1986},
file = {:/home/christoph/Notes/HHU/Bachelorarbeit/literature/PC_AT Technical Reference.pdf:PDF},
}
@Manual{80386,
organization = {Intel Corporation},
title = {{Intel 80386 Manual}},
url = {https://bitsavers.org/components/intel/80386/230985-001_80386_Programmers_Reference_Manual_1986.pdf},
urldate = {2023-02-10},
year = {1986},
file = {:/home/christoph/Notes/HHU/Bachelorarbeit/literature/Intel 80386 Manual.pdf:PDF},
}
@Misc{x86isa,
author = {Félix Cloutier},
month = sep,
title = {{x86 and amd64 instruction reference}},
year = {2022},
url = {https://www.felixcloutier.com/x86/index.html},
urldate = {2023-02-10},
}
@Misc{linux,
author = {Torvalds, Linus and others},
month = feb,
title = {{Linux 6.1.11}},
year = {2023},
url = {https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/?h=v6.1.11},
urldate = {2023-02-10},
}
@Misc{xv6,
author = {Kaashoek, Frans and Morris, Robert and Cox, Russ},
title = {{xv6 OS}},
url = {https://github.com/mit-pdos/xv6-public},
urldate = {2023-02-10},
}
@Misc{osdev,
title = {{OSDev}},
url = {https://wiki.osdev.org/},
urldate = {2023-02-10},
}
@Misc{serenity,
author = {Kling, Andreas and others},
title = {{SerenityOS}},
url = {https://github.com/SerenityOS/serenity},
urldate = {2023-02-10},
}
@Manual{acpipre,
month = dec,
organization = {UEFI Forum},
title = {{Advanced Configuration and Power Interface Specification}},
url = {https://uefi.org/sites/default/files/resources/ACPI_1.pdf},
urldate = {2023-02-21},
year = {1996},
note = {Rev 1.0},
}
@Manual{mpspecpre,
month = oct,
organization = {Intel Corporation},
title = {{Intel MultiProcessor Specification}},
year = {1993},
note = {Rev 1.0},
}
@Misc{irqbalance,
author = {Horman, Neil and Waskiewicz, P. J. and Arapov, Anton and others},
title = {Irqbalance},
url = {https://github.com/Irqbalance/irqbalance},
urldate = {2023-02-23},
}
@Misc{acpica,
title = {{ACPICA}},
organization = {Intel Corporation},
url = {https://acpica.org/},
urldate = {2023-02-23},
}
@Manual{pit,
month = sep,
organization = {Intel Corporation},
title = {{Intel 8254 Datasheet}},
url = {https://www.scs.stanford.edu/10wi-cs140/pintos/specs/8254.pdf},
urldate = {2023-02-26},
year = {1993},
note = {Rev 5},
abstract = {DATASHEET SEARCH, DATABOOK, COMPONENT, FREE DOWNLOAD SITE},
file = {:/home/christoph/Notes/HHU/Bachelorarbeit/literature/Intel 8254 Datasheet.pdf:PDF},
}
@Comment{jabref-meta: databaseType:bibtex;}

45
thesis.tex Normal file
View File

@ -0,0 +1,45 @@
% !TeX document-id = {631e44a8-cd91-47da-bf82-1571f8787194}
% !TeX TXS-program:compile = txs:///pdflatex/[--shell-escape]
\documentclass{class/thesis}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Bitte ergänzen Sie Ihre persönlichen Daten innerhalb %
% der im Folgenden inkludierten Datei properties.tex %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\include{properties}
\include{glossary}
\begin{document}
% Capitalize all the names
\renewcommand{\figureautorefname}{Figure}
\renewcommand{\tableautorefname}{Table}
\renewcommand{\partautorefname}{Part} \renewcommand{\appendixautorefname}{Appendix}
\renewcommand{\chapterautorefname}{Chapter} \renewcommand{\sectionautorefname}{Section}
\renewcommand{\subsectionautorefname}{Section} \renewcommand{\subsubsectionautorefname}{Section}
\makeatletter\newcommand{\tcb@cnt@codeblockautorefname}{Listing}\makeatother
% \renewcommand{\clearpage}{}
% \renewcommand{\cleardoublepage}{}
\begin{thesis}
\include{chap/introduction}
\include{chap/background}
\include{chap/implementation}
\include{chap/verification}
\include{chap/conclusion}
% \pagenumbering{gobble} % Don't number appendix?
\begin{appendices}
\include{chap/appendix_listings}
% \raggedbottom % The figures/tables shouldn't have huge vspace between them
\include{chap/appendix_tables}
\include{chap/appendix_figures}
\end{appendices}
\end{thesis}
\end{document}