1

Sync with BSuSP

This commit is contained in:
2023-03-03 15:40:25 +01:00
parent 8bec9735e3
commit 5349bca520
27 changed files with 804 additions and 2523 deletions

View File

@ -1,236 +0,0 @@
\relax
\providecommand{\transparent@use}[1]{}
\providecommand\hyper@newdestlabel[2]{}
\@writefile{listings}{\addvspace {10pt}}
\@writefile{toc}{\contentsline {chapter}{\numberline {2}Background}{3}{chapter.2}\protected@file@percent }
\@writefile{lof}{\addvspace {10\p@ }}
\@writefile{lot}{\addvspace {10\p@ }}
\@writefile{loa}{\addvspace {10\p@ }}
\newlabel{ch:background}{{2}{3}{Background}{chapter.2}{}}
\@writefile{toc}{\contentsline {section}{\numberline {2.1}Handling of External Events}{4}{section.2.1}\protected@file@percent }
\newlabel{sec:eventhandling}{{2.1}{4}{Handling of External Events}{section.2.1}{}}
\@writefile{toc}{\contentsline {section}{\numberline {2.2}Fundamental Concepts}{4}{section.2.2}\protected@file@percent }
\newlabel{sec:fundamentals}{{2.2}{4}{Fundamental Concepts}{section.2.2}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {2.2.1}Interrupt}{4}{subsection.2.2.1}\protected@file@percent }
\newlabel{subsec:interrupt}{{2.2.1}{4}{Interrupt}{subsection.2.2.1}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {2.2.2}Interrupt Controller}{5}{subsection.2.2.2}\protected@file@percent }
\newlabel{subsec:controller}{{2.2.2}{5}{Interrupt Controller}{subsection.2.2.2}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {2.2.3}Interrupt Handler}{5}{subsection.2.2.3}\protected@file@percent }
\newlabel{subsec:handler}{{2.2.3}{5}{Interrupt Handler}{subsection.2.2.3}{}}
\@writefile{lof}{\contentsline {figure}{\numberline {2.1}{\ignorespaces Interrupt Handler Execution.\relax }}{6}{figure.2.1}\protected@file@percent }
\providecommand*\caption@xref[2]{\@setref\relax\@undefined{#1}}
\newlabel{fig:interruptexecution}{{2.1}{6}{Interrupt Handler Execution.\relax }{figure.2.1}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {2.2.4}Interrupt Trigger Mode}{6}{subsection.2.2.4}\protected@file@percent }
\newlabel{subsec:triggermode}{{2.2.4}{6}{Interrupt Trigger Mode}{subsection.2.2.4}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {2.2.5}Spurious Interrupt}{6}{subsection.2.2.5}\protected@file@percent }
\newlabel{subsec:spurious}{{2.2.5}{6}{Spurious Interrupt}{subsection.2.2.5}{}}
\@writefile{toc}{\contentsline {section}{\numberline {2.3}Used Technologies}{7}{section.2.3}\protected@file@percent }
\newlabel{sec:technologies}{{2.3}{7}{Used Technologies}{section.2.3}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {2.3.1}Advanced Configuration and Power Interface}{7}{subsection.2.3.1}\protected@file@percent }
\newlabel{subsec:acpi}{{2.3.1}{7}{Advanced Configuration and Power Interface}{subsection.2.3.1}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {2.3.2}CPU Identification}{7}{subsection.2.3.2}\protected@file@percent }
\newlabel{subsec:cpuid}{{2.3.2}{7}{CPU Identification}{subsection.2.3.2}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {2.3.3}Symmetric Multiprocessing}{7}{subsection.2.3.3}\protected@file@percent }
\newlabel{subsec:smp}{{2.3.3}{7}{Symmetric Multiprocessing}{subsection.2.3.3}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {2.3.4}Model Specific Register}{8}{subsection.2.3.4}\protected@file@percent }
\newlabel{subsec:msr}{{2.3.4}{8}{Model Specific Register}{subsection.2.3.4}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {2.3.5}Memory Mapped I/O}{8}{subsection.2.3.5}\protected@file@percent }
\newlabel{subsec:mmio}{{2.3.5}{8}{Memory Mapped I/O}{subsection.2.3.5}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {2.3.6}Programmable Interval Timer}{8}{subsection.2.3.6}\protected@file@percent }
\newlabel{subsec:pit}{{2.3.6}{8}{Programmable Interval Timer}{subsection.2.3.6}{}}
\@writefile{toc}{\contentsline {section}{\numberline {2.4}Intel's Interrupt Controllers}{8}{section.2.4}\protected@file@percent }
\newlabel{sec:intelcontrollers}{{2.4}{8}{Intel's Interrupt Controllers}{section.2.4}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {2.4.1}Programmable Interrupt Controller}{8}{subsection.2.4.1}\protected@file@percent }
\newlabel{subsec:intelpic}{{2.4.1}{8}{Programmable Interrupt Controller}{subsection.2.4.1}{}}
\@writefile{lof}{\contentsline {figure}{\numberline {2.2}{\ignorespaces The PC/AT PIC Architecture~\blx@tocontentsinit {0}\autocite [sec.~1.13]{pcat}.\relax }}{9}{figure.2.2}\protected@file@percent }
\newlabel{fig:pcatpic}{{2.2}{9}{The PC/AT PIC Architecture~\autocite [sec.~1.13]{pcat}.\relax }{figure.2.2}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {2.4.2}Advanced Programmable Interrupt Controller}{10}{subsection.2.4.2}\protected@file@percent }
\newlabel{subsec:intelapic}{{2.4.2}{10}{Advanced Programmable Interrupt Controller}{subsection.2.4.2}{}}
\@writefile{lof}{\contentsline {figure}{\numberline {2.3}{\ignorespaces The Discrete APIC Architecture~\blx@tocontentsinit {0}\autocite [sec.~5.1]{mpspec}.\relax }}{11}{figure.2.3}\protected@file@percent }
\newlabel{fig:discreteapic}{{2.3}{11}{The Discrete APIC Architecture~\autocite [sec.~5.1]{mpspec}.\relax }{figure.2.3}{}}
\@writefile{lof}{\contentsline {figure}{\numberline {2.4}{\ignorespaces The Integrated APIC Architecture~\blx@tocontentsinit {0}\autocite [sec.~5.2]{mpspec}.\relax }}{12}{figure.2.4}\protected@file@percent }
\newlabel{fig:integratedapic}{{2.4}{12}{The Integrated APIC Architecture~\autocite [sec.~5.2]{mpspec}.\relax }{figure.2.4}{}}
\@writefile{lof}{\contentsline {figure}{\numberline {2.5}{\ignorespaces System Bus vs APIC Bus~\blx@tocontentsinit {0}\autocite [sec.~3.11.1]{ia32}.\relax }}{13}{figure.2.5}\protected@file@percent }
\newlabel{fig:systemvsapicbus}{{2.5}{13}{System Bus vs APIC Bus~\autocite [sec.~3.11.1]{ia32}.\relax }{figure.2.5}{}}
\@writefile{toc}{\contentsline {section}{\numberline {2.5}PC/AT Compatibility}{13}{section.2.5}\protected@file@percent }
\newlabel{sec:pcatcompat}{{2.5}{13}{PC/AT Compatibility}{section.2.5}{}}
\@writefile{toc}{\contentsline {section}{\numberline {2.6}Interrupt Handling in HhuOS}{14}{section.2.6}\protected@file@percent }
\newlabel{sec:currenthhuos}{{2.6}{14}{Interrupt Handling in HhuOS}{section.2.6}{}}
\@setckpt{chap/background}{
\setcounter{page}{15}
\setcounter{equation}{0}
\setcounter{enumi}{2}
\setcounter{enumii}{0}
\setcounter{enumiii}{0}
\setcounter{enumiv}{0}
\setcounter{footnote}{17}
\setcounter{mpfootnote}{0}
\setcounter{part}{0}
\setcounter{chapter}{2}
\setcounter{section}{6}
\setcounter{subsection}{0}
\setcounter{subsubsection}{0}
\setcounter{paragraph}{0}
\setcounter{subparagraph}{0}
\setcounter{figure}{5}
\setcounter{table}{0}
\setcounter{parentequation}{0}
\setcounter{tcbbreakpart}{1}
\setcounter{tcblayer}{0}
\setcounter{tcolorbox@number}{15}
\setcounter{FancyVerbLine}{0}
\setcounter{linenumber}{1}
\setcounter{LN@truepage}{22}
\setcounter{FV@TrueTabGroupLevel}{0}
\setcounter{FV@TrueTabCounter}{0}
\setcounter{FV@HighlightLinesStart}{0}
\setcounter{FV@HighlightLinesStop}{0}
\setcounter{FancyVerbLineBreakLast}{0}
\setcounter{FV@BreakBufferDepth}{0}
\setcounter{float@type}{16}
\setcounter{minted@FancyVerbLineTemp}{0}
\setcounter{minted@pygmentizecounter}{0}
\setcounter{listing}{0}
\setcounter{tcblisting}{0}
\setcounter{caption@flags}{6}
\setcounter{continuedfloat}{0}
\setcounter{subfigure}{0}
\setcounter{subtable}{0}
\setcounter{section@level}{1}
\setcounter{Item}{12}
\setcounter{Hfootnote}{17}
\setcounter{bookmark@seq@number}{21}
\setcounter{AlgoLine}{0}
\setcounter{algocfline}{0}
\setcounter{algocfproc}{0}
\setcounter{algocf}{0}
\setcounter{lofdepth}{1}
\setcounter{lotdepth}{1}
\setcounter{svg@param@lastpage}{0}
\setcounter{svg@param@currpage}{-1}
\setcounter{su@anzahl}{0}
\setcounter{LT@tables}{0}
\setcounter{LT@chunks}{0}
\setcounter{@pps}{0}
\setcounter{@ppsavesec}{0}
\setcounter{@ppsaveapp}{0}
\setcounter{tabx@nest}{0}
\setcounter{listtotal}{0}
\setcounter{listcount}{0}
\setcounter{liststart}{0}
\setcounter{liststop}{0}
\setcounter{citecount}{0}
\setcounter{citetotal}{0}
\setcounter{multicitecount}{0}
\setcounter{multicitetotal}{0}
\setcounter{instcount}{26}
\setcounter{maxnames}{3}
\setcounter{minnames}{3}
\setcounter{maxitems}{3}
\setcounter{minitems}{1}
\setcounter{citecounter}{0}
\setcounter{maxcitecounter}{0}
\setcounter{savedcitecounter}{0}
\setcounter{uniquelist}{0}
\setcounter{uniquename}{0}
\setcounter{refsection}{0}
\setcounter{refsegment}{0}
\setcounter{maxextratitle}{0}
\setcounter{maxextratitleyear}{0}
\setcounter{maxextraname}{0}
\setcounter{maxextradate}{0}
\setcounter{maxextraalpha}{0}
\setcounter{abbrvpenalty}{50}
\setcounter{highnamepenalty}{50}
\setcounter{lownamepenalty}{25}
\setcounter{maxparens}{3}
\setcounter{parenlevel}{0}
\setcounter{blx@maxsection}{0}
\setcounter{mincomprange}{10}
\setcounter{maxcomprange}{100000}
\setcounter{mincompwidth}{1}
\setcounter{afterword}{0}
\setcounter{savedafterword}{0}
\setcounter{annotator}{0}
\setcounter{savedannotator}{0}
\setcounter{author}{0}
\setcounter{savedauthor}{0}
\setcounter{bookauthor}{0}
\setcounter{savedbookauthor}{0}
\setcounter{commentator}{0}
\setcounter{savedcommentator}{0}
\setcounter{editor}{0}
\setcounter{savededitor}{0}
\setcounter{editora}{0}
\setcounter{savededitora}{0}
\setcounter{editorb}{0}
\setcounter{savededitorb}{0}
\setcounter{editorc}{0}
\setcounter{savededitorc}{0}
\setcounter{foreword}{0}
\setcounter{savedforeword}{0}
\setcounter{holder}{0}
\setcounter{savedholder}{0}
\setcounter{introduction}{0}
\setcounter{savedintroduction}{0}
\setcounter{namea}{0}
\setcounter{savednamea}{0}
\setcounter{nameb}{0}
\setcounter{savednameb}{0}
\setcounter{namec}{0}
\setcounter{savednamec}{0}
\setcounter{translator}{0}
\setcounter{savedtranslator}{0}
\setcounter{shortauthor}{0}
\setcounter{savedshortauthor}{0}
\setcounter{shorteditor}{0}
\setcounter{savedshorteditor}{0}
\setcounter{labelname}{0}
\setcounter{savedlabelname}{0}
\setcounter{institution}{0}
\setcounter{savedinstitution}{0}
\setcounter{lista}{0}
\setcounter{savedlista}{0}
\setcounter{listb}{0}
\setcounter{savedlistb}{0}
\setcounter{listc}{0}
\setcounter{savedlistc}{0}
\setcounter{listd}{0}
\setcounter{savedlistd}{0}
\setcounter{liste}{0}
\setcounter{savedliste}{0}
\setcounter{listf}{0}
\setcounter{savedlistf}{0}
\setcounter{location}{0}
\setcounter{savedlocation}{0}
\setcounter{organization}{0}
\setcounter{savedorganization}{0}
\setcounter{origlocation}{0}
\setcounter{savedoriglocation}{0}
\setcounter{origpublisher}{0}
\setcounter{savedorigpublisher}{0}
\setcounter{publisher}{0}
\setcounter{savedpublisher}{0}
\setcounter{language}{0}
\setcounter{savedlanguage}{0}
\setcounter{origlanguage}{0}
\setcounter{savedoriglanguage}{0}
\setcounter{pageref}{0}
\setcounter{savedpageref}{0}
\setcounter{textcitecount}{0}
\setcounter{textcitetotal}{0}
\setcounter{textcitemaxnames}{0}
\setcounter{biburlbigbreakpenalty}{100}
\setcounter{biburlbreakpenalty}{200}
\setcounter{biburlnumpenalty}{0}
\setcounter{biburlucpenalty}{0}
\setcounter{biburllcpenalty}{0}
\setcounter{smartand}{1}
\setcounter{bbx:relatedcount}{0}
\setcounter{bbx:relatedtotal}{0}
\setcounter{cbx@tempcnta}{0}
\setcounter{cbx@tempcntb}{6}
\setcounter{cbx@tempcntc}{0}
\setcounter{cbx@tempcntd}{-1}
\setcounter{tcb@cnt@codeblock}{0}
}

View File

@ -1,7 +1,7 @@
\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}.
In this chapter, important domain-specific concepts will be explained, to create the necessary foundation to follow \autoref{ch:implementation}.
Important terms present in the glossary are marked in \textbf{bold} on their first occurrence.
\clearpage
@ -347,25 +347,4 @@ PC/AT compatibility is usually achieved in these systems by connecting two PICs
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 stages (see \autoref{subsec:apxcurrenthhuos} for code examples):
\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, 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, 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 to register itself to the correct vector number.
HhuOS supports assigning multiple interrupt handlers to a single interrupt vector and cascading interrupts.
\end{enumerate}
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, which in turn is used to trigger hhuOS' preemptive round-robin scheduler (the \code{Scheduler} class).
The PIT and other devices are initialized before the system entry point, in the \code{System::initializeSystem} function.
\cleardoublepage

View File

@ -1,201 +0,0 @@
\relax
\providecommand{\transparent@use}[1]{}
\providecommand\hyper@newdestlabel[2]{}
\@writefile{listings}{\addvspace {10pt}}
\@writefile{toc}{\contentsline {chapter}{\numberline {5}Conclusion}{37}{chapter.5}\protected@file@percent }
\@writefile{lof}{\addvspace {10\p@ }}
\@writefile{lot}{\addvspace {10\p@ }}
\@writefile{loa}{\addvspace {10\p@ }}
\newlabel{ch:conclusion}{{5}{37}{Conclusion}{chapter.5}{}}
\@writefile{toc}{\contentsline {section}{\numberline {5.1}Comparing PIC and APIC Implementations}{38}{section.5.1}\protected@file@percent }
\newlabel{sec:comparingpicapic}{{5.1}{38}{Comparing PIC and APIC Implementations}{section.5.1}{}}
\@writefile{toc}{\contentsline {section}{\numberline {5.2}Future Improvements}{38}{section.5.2}\protected@file@percent }
\newlabel{sec:futureimprov}{{5.2}{38}{Future Improvements}{section.5.2}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {5.2.1}Dependence on ACPI}{38}{subsection.5.2.1}\protected@file@percent }
\newlabel{subsec:acpidependance}{{5.2.1}{38}{Dependence on ACPI}{subsection.5.2.1}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {5.2.2}Discrete APIC and x2Apic}{39}{subsection.5.2.2}\protected@file@percent }
\newlabel{subsec:discretex2}{{5.2.2}{39}{Discrete APIC and x2Apic}{subsection.5.2.2}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {5.2.3}PCI Devices}{39}{subsection.5.2.3}\protected@file@percent }
\newlabel{subsec:pcidevices}{{5.2.3}{39}{PCI Devices}{subsection.5.2.3}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {5.2.4}Multiprocessor Systems}{39}{subsection.5.2.4}\protected@file@percent }
\newlabel{subsec:multiprocessor}{{5.2.4}{39}{Multiprocessor Systems}{subsection.5.2.4}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {5.2.5}UEFI Support}{40}{subsection.5.2.5}\protected@file@percent }
\newlabel{subsec:uefisupport}{{5.2.5}{40}{UEFI Support}{subsection.5.2.5}{}}
\@setckpt{chap/conclusion}{
\setcounter{page}{41}
\setcounter{equation}{0}
\setcounter{enumi}{9}
\setcounter{enumii}{0}
\setcounter{enumiii}{0}
\setcounter{enumiv}{0}
\setcounter{footnote}{5}
\setcounter{mpfootnote}{0}
\setcounter{part}{0}
\setcounter{chapter}{5}
\setcounter{section}{2}
\setcounter{subsection}{5}
\setcounter{subsubsection}{0}
\setcounter{paragraph}{0}
\setcounter{subparagraph}{0}
\setcounter{figure}{0}
\setcounter{table}{0}
\setcounter{parentequation}{0}
\setcounter{tcbbreakpart}{1}
\setcounter{tcblayer}{0}
\setcounter{tcolorbox@number}{59}
\setcounter{FancyVerbLine}{0}
\setcounter{linenumber}{1}
\setcounter{LN@truepage}{48}
\setcounter{FV@TrueTabGroupLevel}{0}
\setcounter{FV@TrueTabCounter}{0}
\setcounter{FV@HighlightLinesStart}{0}
\setcounter{FV@HighlightLinesStop}{0}
\setcounter{FancyVerbLineBreakLast}{0}
\setcounter{FV@BreakBufferDepth}{0}
\setcounter{float@type}{16}
\setcounter{minted@FancyVerbLineTemp}{0}
\setcounter{minted@pygmentizecounter}{0}
\setcounter{listing}{0}
\setcounter{tcblisting}{0}
\setcounter{caption@flags}{6}
\setcounter{continuedfloat}{0}
\setcounter{subfigure}{0}
\setcounter{subtable}{0}
\setcounter{section@level}{2}
\setcounter{Item}{46}
\setcounter{Hfootnote}{43}
\setcounter{bookmark@seq@number}{51}
\setcounter{AlgoLine}{0}
\setcounter{algocfline}{0}
\setcounter{algocfproc}{0}
\setcounter{algocf}{0}
\setcounter{lofdepth}{1}
\setcounter{lotdepth}{1}
\setcounter{svg@param@lastpage}{0}
\setcounter{svg@param@currpage}{-1}
\setcounter{su@anzahl}{0}
\setcounter{LT@tables}{0}
\setcounter{LT@chunks}{0}
\setcounter{@pps}{0}
\setcounter{@ppsavesec}{0}
\setcounter{@ppsaveapp}{0}
\setcounter{tabx@nest}{0}
\setcounter{listtotal}{0}
\setcounter{listcount}{0}
\setcounter{liststart}{0}
\setcounter{liststop}{0}
\setcounter{citecount}{0}
\setcounter{citetotal}{0}
\setcounter{multicitecount}{0}
\setcounter{multicitetotal}{0}
\setcounter{instcount}{89}
\setcounter{maxnames}{3}
\setcounter{minnames}{3}
\setcounter{maxitems}{3}
\setcounter{minitems}{1}
\setcounter{citecounter}{0}
\setcounter{maxcitecounter}{0}
\setcounter{savedcitecounter}{0}
\setcounter{uniquelist}{0}
\setcounter{uniquename}{0}
\setcounter{refsection}{0}
\setcounter{refsegment}{0}
\setcounter{maxextratitle}{0}
\setcounter{maxextratitleyear}{0}
\setcounter{maxextraname}{0}
\setcounter{maxextradate}{0}
\setcounter{maxextraalpha}{0}
\setcounter{abbrvpenalty}{50}
\setcounter{highnamepenalty}{50}
\setcounter{lownamepenalty}{25}
\setcounter{maxparens}{3}
\setcounter{parenlevel}{0}
\setcounter{blx@maxsection}{0}
\setcounter{mincomprange}{10}
\setcounter{maxcomprange}{100000}
\setcounter{mincompwidth}{1}
\setcounter{afterword}{0}
\setcounter{savedafterword}{0}
\setcounter{annotator}{0}
\setcounter{savedannotator}{0}
\setcounter{author}{0}
\setcounter{savedauthor}{0}
\setcounter{bookauthor}{0}
\setcounter{savedbookauthor}{0}
\setcounter{commentator}{0}
\setcounter{savedcommentator}{0}
\setcounter{editor}{0}
\setcounter{savededitor}{0}
\setcounter{editora}{0}
\setcounter{savededitora}{0}
\setcounter{editorb}{0}
\setcounter{savededitorb}{0}
\setcounter{editorc}{0}
\setcounter{savededitorc}{0}
\setcounter{foreword}{0}
\setcounter{savedforeword}{0}
\setcounter{holder}{0}
\setcounter{savedholder}{0}
\setcounter{introduction}{0}
\setcounter{savedintroduction}{0}
\setcounter{namea}{0}
\setcounter{savednamea}{0}
\setcounter{nameb}{0}
\setcounter{savednameb}{0}
\setcounter{namec}{0}
\setcounter{savednamec}{0}
\setcounter{translator}{0}
\setcounter{savedtranslator}{0}
\setcounter{shortauthor}{0}
\setcounter{savedshortauthor}{0}
\setcounter{shorteditor}{0}
\setcounter{savedshorteditor}{0}
\setcounter{labelname}{0}
\setcounter{savedlabelname}{0}
\setcounter{institution}{0}
\setcounter{savedinstitution}{0}
\setcounter{lista}{0}
\setcounter{savedlista}{0}
\setcounter{listb}{0}
\setcounter{savedlistb}{0}
\setcounter{listc}{0}
\setcounter{savedlistc}{0}
\setcounter{listd}{0}
\setcounter{savedlistd}{0}
\setcounter{liste}{0}
\setcounter{savedliste}{0}
\setcounter{listf}{0}
\setcounter{savedlistf}{0}
\setcounter{location}{0}
\setcounter{savedlocation}{0}
\setcounter{organization}{0}
\setcounter{savedorganization}{0}
\setcounter{origlocation}{0}
\setcounter{savedoriglocation}{0}
\setcounter{origpublisher}{0}
\setcounter{savedorigpublisher}{0}
\setcounter{publisher}{0}
\setcounter{savedpublisher}{0}
\setcounter{language}{0}
\setcounter{savedlanguage}{0}
\setcounter{origlanguage}{0}
\setcounter{savedoriglanguage}{0}
\setcounter{pageref}{0}
\setcounter{savedpageref}{0}
\setcounter{textcitecount}{0}
\setcounter{textcitetotal}{0}
\setcounter{textcitemaxnames}{0}
\setcounter{biburlbigbreakpenalty}{100}
\setcounter{biburlbreakpenalty}{200}
\setcounter{biburlnumpenalty}{0}
\setcounter{biburlucpenalty}{0}
\setcounter{biburllcpenalty}{0}
\setcounter{smartand}{1}
\setcounter{bbx:relatedcount}{0}
\setcounter{bbx:relatedtotal}{0}
\setcounter{cbx@tempcnta}{0}
\setcounter{cbx@tempcntb}{19}
\setcounter{cbx@tempcntc}{0}
\setcounter{cbx@tempcntd}{-1}
\setcounter{tcb@cnt@codeblock}{0}
}

View File

@ -1,191 +0,0 @@
\relax
\providecommand{\transparent@use}[1]{}
\providecommand\hyper@newdestlabel[2]{}
\@writefile{listings}{\addvspace {10pt}}
\@writefile{toc}{\contentsline {chapter}{\numberline {B}Figures}{59}{appendix.1.B}\protected@file@percent }
\@writefile{lof}{\addvspace {10\p@ }}
\@writefile{lot}{\addvspace {10\p@ }}
\@writefile{loa}{\addvspace {10\p@ }}
\newlabel{ch:figures}{{B}{59}{Figures}{appendix.1.B}{}}
\@writefile{lof}{\contentsline {figure}{\numberline {B.1}{\ignorespaces Enabling the APIC Subsystem.\relax }}{60}{figure.1.B.1}\protected@file@percent }
\newlabel{fig:apicenable}{{B.1}{60}{Enabling the APIC Subsystem.\relax }{figure.1.B.1}{}}
\@writefile{lof}{\contentsline {figure}{\numberline {B.2}{\ignorespaces Starting SMP Operation.\relax }}{61}{figure.1.B.2}\protected@file@percent }
\newlabel{fig:smpenable}{{B.2}{61}{Starting SMP Operation.\relax }{figure.1.B.2}{}}
\@setckpt{chap/figures}{
\setcounter{page}{63}
\setcounter{equation}{0}
\setcounter{enumi}{4}
\setcounter{enumii}{0}
\setcounter{enumiii}{0}
\setcounter{enumiv}{0}
\setcounter{footnote}{0}
\setcounter{mpfootnote}{0}
\setcounter{part}{0}
\setcounter{chapter}{2}
\setcounter{section}{0}
\setcounter{subsection}{0}
\setcounter{subsubsection}{0}
\setcounter{paragraph}{0}
\setcounter{subparagraph}{0}
\setcounter{figure}{2}
\setcounter{table}{0}
\setcounter{parentequation}{0}
\setcounter{tcbbreakpart}{1}
\setcounter{tcblayer}{0}
\setcounter{tcolorbox@number}{184}
\setcounter{FancyVerbLine}{12}
\setcounter{linenumber}{1}
\setcounter{LN@truepage}{70}
\setcounter{FV@TrueTabGroupLevel}{0}
\setcounter{FV@TrueTabCounter}{0}
\setcounter{FV@HighlightLinesStart}{0}
\setcounter{FV@HighlightLinesStop}{0}
\setcounter{FancyVerbLineBreakLast}{1}
\setcounter{FV@BreakBufferDepth}{0}
\setcounter{float@type}{16}
\setcounter{minted@FancyVerbLineTemp}{0}
\setcounter{minted@pygmentizecounter}{47}
\setcounter{listing}{0}
\setcounter{tcblisting}{0}
\setcounter{caption@flags}{6}
\setcounter{continuedfloat}{0}
\setcounter{subfigure}{0}
\setcounter{subtable}{0}
\setcounter{section@level}{2}
\setcounter{Item}{50}
\setcounter{Hfootnote}{45}
\setcounter{bookmark@seq@number}{73}
\setcounter{AlgoLine}{0}
\setcounter{algocfline}{0}
\setcounter{algocfproc}{0}
\setcounter{algocf}{0}
\setcounter{lofdepth}{1}
\setcounter{lotdepth}{1}
\setcounter{svg@param@lastpage}{0}
\setcounter{svg@param@currpage}{-1}
\setcounter{su@anzahl}{0}
\setcounter{LT@tables}{0}
\setcounter{LT@chunks}{0}
\setcounter{@pps}{1}
\setcounter{@ppsavesec}{5}
\setcounter{@ppsaveapp}{0}
\setcounter{tabx@nest}{0}
\setcounter{listtotal}{0}
\setcounter{listcount}{0}
\setcounter{liststart}{0}
\setcounter{liststop}{0}
\setcounter{citecount}{0}
\setcounter{citetotal}{0}
\setcounter{multicitecount}{0}
\setcounter{multicitetotal}{0}
\setcounter{instcount}{96}
\setcounter{maxnames}{3}
\setcounter{minnames}{3}
\setcounter{maxitems}{3}
\setcounter{minitems}{1}
\setcounter{citecounter}{0}
\setcounter{maxcitecounter}{0}
\setcounter{savedcitecounter}{0}
\setcounter{uniquelist}{0}
\setcounter{uniquename}{0}
\setcounter{refsection}{0}
\setcounter{refsegment}{0}
\setcounter{maxextratitle}{0}
\setcounter{maxextratitleyear}{0}
\setcounter{maxextraname}{0}
\setcounter{maxextradate}{0}
\setcounter{maxextraalpha}{0}
\setcounter{abbrvpenalty}{50}
\setcounter{highnamepenalty}{50}
\setcounter{lownamepenalty}{25}
\setcounter{maxparens}{3}
\setcounter{parenlevel}{0}
\setcounter{blx@maxsection}{0}
\setcounter{mincomprange}{10}
\setcounter{maxcomprange}{100000}
\setcounter{mincompwidth}{1}
\setcounter{afterword}{0}
\setcounter{savedafterword}{0}
\setcounter{annotator}{0}
\setcounter{savedannotator}{0}
\setcounter{author}{0}
\setcounter{savedauthor}{0}
\setcounter{bookauthor}{0}
\setcounter{savedbookauthor}{0}
\setcounter{commentator}{0}
\setcounter{savedcommentator}{0}
\setcounter{editor}{0}
\setcounter{savededitor}{0}
\setcounter{editora}{0}
\setcounter{savededitora}{0}
\setcounter{editorb}{0}
\setcounter{savededitorb}{0}
\setcounter{editorc}{0}
\setcounter{savededitorc}{0}
\setcounter{foreword}{0}
\setcounter{savedforeword}{0}
\setcounter{holder}{0}
\setcounter{savedholder}{0}
\setcounter{introduction}{0}
\setcounter{savedintroduction}{0}
\setcounter{namea}{0}
\setcounter{savednamea}{0}
\setcounter{nameb}{0}
\setcounter{savednameb}{0}
\setcounter{namec}{0}
\setcounter{savednamec}{0}
\setcounter{translator}{0}
\setcounter{savedtranslator}{0}
\setcounter{shortauthor}{0}
\setcounter{savedshortauthor}{0}
\setcounter{shorteditor}{0}
\setcounter{savedshorteditor}{0}
\setcounter{labelname}{0}
\setcounter{savedlabelname}{0}
\setcounter{institution}{0}
\setcounter{savedinstitution}{0}
\setcounter{lista}{0}
\setcounter{savedlista}{0}
\setcounter{listb}{0}
\setcounter{savedlistb}{0}
\setcounter{listc}{0}
\setcounter{savedlistc}{0}
\setcounter{listd}{0}
\setcounter{savedlistd}{0}
\setcounter{liste}{0}
\setcounter{savedliste}{0}
\setcounter{listf}{0}
\setcounter{savedlistf}{0}
\setcounter{location}{0}
\setcounter{savedlocation}{0}
\setcounter{organization}{0}
\setcounter{savedorganization}{0}
\setcounter{origlocation}{0}
\setcounter{savedoriglocation}{0}
\setcounter{origpublisher}{0}
\setcounter{savedorigpublisher}{0}
\setcounter{publisher}{0}
\setcounter{savedpublisher}{0}
\setcounter{language}{0}
\setcounter{savedlanguage}{0}
\setcounter{origlanguage}{0}
\setcounter{savedoriglanguage}{0}
\setcounter{pageref}{0}
\setcounter{savedpageref}{0}
\setcounter{textcitecount}{0}
\setcounter{textcitetotal}{0}
\setcounter{textcitemaxnames}{0}
\setcounter{biburlbigbreakpenalty}{100}
\setcounter{biburlbreakpenalty}{200}
\setcounter{biburlnumpenalty}{0}
\setcounter{biburlucpenalty}{0}
\setcounter{biburllcpenalty}{0}
\setcounter{smartand}{1}
\setcounter{bbx:relatedcount}{0}
\setcounter{bbx:relatedtotal}{0}
\setcounter{cbx@tempcnta}{0}
\setcounter{cbx@tempcntb}{20}
\setcounter{cbx@tempcntc}{0}
\setcounter{cbx@tempcntd}{-1}
\setcounter{tcb@cnt@codeblock}{0}
}

View File

@ -22,5 +22,6 @@
\end{figure}
Note that this diagram is slightly misleading, because the application processor runs in parallel and is not susceptible to delays on the BSP\@.
Initialization of the AP's local APIC follows the sequence described by \autoref{fig:apicenable} (starting at "Actual Component Initialization", excluding the I/O APIC, error handler instantiation and timer calibration).
\cleardoublepage

View File

@ -1,237 +0,0 @@
\relax
\providecommand{\transparent@use}[1]{}
\providecommand\hyper@newdestlabel[2]{}
\@writefile{listings}{\addvspace {10pt}}
\@writefile{toc}{\contentsline {chapter}{\numberline {3}Implementation}{15}{chapter.3}\protected@file@percent }
\@writefile{lof}{\addvspace {10\p@ }}
\@writefile{lot}{\addvspace {10\p@ }}
\@writefile{loa}{\addvspace {10\p@ }}
\newlabel{ch:implementation}{{3}{15}{Implementation}{chapter.3}{}}
\@writefile{toc}{\contentsline {section}{\numberline {3.1}Design Decisions and Scope}{16}{section.3.1}\protected@file@percent }
\newlabel{sec:design}{{3.1}{16}{Design Decisions and Scope}{section.3.1}{}}
\@writefile{lof}{\contentsline {figure}{\numberline {3.1}{\ignorespaces Caller Hierarchy of the Main Components.\relax }}{16}{figure.3.1}\protected@file@percent }
\newlabel{fig:implarch}{{3.1}{16}{Caller Hierarchy of the Main Components.\relax }{figure.3.1}{}}
\@writefile{toc}{\contentsline {section}{\numberline {3.2}Local APIC}{19}{section.3.2}\protected@file@percent }
\newlabel{sec:lapicinit}{{3.2}{19}{Local APIC}{section.3.2}{}}
\@writefile{lof}{\contentsline {figure}{\numberline {3.2}{\ignorespaces The Local APIC Block Diagram~\blx@tocontentsinit {0}\autocite [sec.~3.11.4.1]{ia32}.\relax }}{20}{figure.3.2}\protected@file@percent }
\newlabel{fig:localapicblock}{{3.2}{20}{The Local APIC Block Diagram~\autocite [sec.~3.11.4.1]{ia32}.\relax }{figure.3.2}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {3.2.1}Accessing Local APIC Registers in xApic Mode}{21}{subsection.3.2.1}\protected@file@percent }
\newlabel{subsec:xapicregacc}{{3.2.1}{21}{Accessing Local APIC Registers in xApic Mode}{subsection.3.2.1}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {3.2.2}Enabling the Local APIC}{21}{subsection.3.2.2}\protected@file@percent }
\newlabel{subsec:lapicenable}{{3.2.2}{21}{Enabling the Local APIC}{subsection.3.2.2}{}}
\@writefile{lof}{\contentsline {figure}{\numberline {3.3}{\ignorespaces The IA32\textunderscore {}APIC\textunderscore {}BASE MSR~\blx@tocontentsinit {0}\autocite [sec.~3.11.4.4]{ia32}.\relax }}{21}{figure.3.3}\protected@file@percent }
\newlabel{fig:ia32apicbasemsr}{{3.3}{21}{The IA32\textunderscore {}APIC\textunderscore {}BASE MSR~\autocite [sec.~3.11.4.4]{ia32}.\relax }{figure.3.3}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {3.2.3}Handling Local Interrupts}{22}{subsection.3.2.3}\protected@file@percent }
\newlabel{subsec:lapiclvtinit}{{3.2.3}{22}{Handling Local Interrupts}{subsection.3.2.3}{}}
\@writefile{lof}{\contentsline {figure}{\numberline {3.4}{\ignorespaces The Local Vector Table~\blx@tocontentsinit {0}\autocite [sec.~3.11.5.1]{ia32}.\relax }}{22}{figure.3.4}\protected@file@percent }
\newlabel{fig:localapiclvt}{{3.4}{22}{The Local Vector Table~\autocite [sec.~3.11.5.1]{ia32}.\relax }{figure.3.4}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {3.2.4}Allowing Interrupt Processing}{23}{subsection.3.2.4}\protected@file@percent }
\newlabel{subsec:lapicsoftenable}{{3.2.4}{23}{Allowing Interrupt Processing}{subsection.3.2.4}{}}
\@writefile{lof}{\contentsline {figure}{\numberline {3.5}{\ignorespaces The Local APIC SVR Register~\blx@tocontentsinit {0}\autocite [sec.~3.11.9]{ia32}.\relax }}{23}{figure.3.5}\protected@file@percent }
\newlabel{fig:ia32apicsvr}{{3.5}{23}{The Local APIC SVR Register~\autocite [sec.~3.11.9]{ia32}.\relax }{figure.3.5}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {3.2.5}Local Interrupt EOI}{24}{subsection.3.2.5}\protected@file@percent }
\newlabel{subsec:lapiceoi}{{3.2.5}{24}{Local Interrupt EOI}{subsection.3.2.5}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {3.2.6}APIC Timer}{24}{subsection.3.2.6}\protected@file@percent }
\newlabel{subsec:lapictimer}{{3.2.6}{24}{APIC Timer}{subsection.3.2.6}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {3.2.7}APIC Error Interrupt}{25}{subsection.3.2.7}\protected@file@percent }
\newlabel{subsec:lapicerror}{{3.2.7}{25}{APIC Error Interrupt}{subsection.3.2.7}{}}
\@writefile{lof}{\contentsline {figure}{\numberline {3.6}{\ignorespaces Error Status Register~\blx@tocontentsinit {0}\autocite [sec.~3.11.5.3]{ia32}.\relax }}{25}{figure.3.6}\protected@file@percent }
\newlabel{fig:ia32esr}{{3.6}{25}{Error Status Register~\autocite [sec.~3.11.5.3]{ia32}.\relax }{figure.3.6}{}}
\@writefile{toc}{\contentsline {section}{\numberline {3.3}I/O APIC}{26}{section.3.3}\protected@file@percent }
\newlabel{sec:ioapicinit}{{3.3}{26}{I/O APIC}{section.3.3}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {3.3.1}Interrupt Overrides}{26}{subsection.3.3.1}\protected@file@percent }
\newlabel{subsec:ioapicpcat}{{3.3.1}{26}{Interrupt Overrides}{subsection.3.3.1}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {3.3.2}External Interrupt EOI}{27}{subsection.3.3.2}\protected@file@percent }
\newlabel{subsec:ioapiceoi}{{3.3.2}{27}{External Interrupt EOI}{subsection.3.3.2}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {3.3.3}Multiple I/O APICs}{28}{subsection.3.3.3}\protected@file@percent }
\newlabel{subsec:multiioapic}{{3.3.3}{28}{Multiple I/O APICs}{subsection.3.3.3}{}}
\@writefile{toc}{\contentsline {section}{\numberline {3.4}Symmetric Multiprocessing}{29}{section.3.4}\protected@file@percent }
\newlabel{sec:smpinit}{{3.4}{29}{Symmetric Multiprocessing}{section.3.4}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {3.4.1}Inter-Processor Interrupts}{29}{subsection.3.4.1}\protected@file@percent }
\newlabel{subsec:ipis}{{3.4.1}{29}{Inter-Processor Interrupts}{subsection.3.4.1}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {3.4.2}Universal Startup Algorithm}{29}{subsection.3.4.2}\protected@file@percent }
\newlabel{subsec:apstartup}{{3.4.2}{29}{Universal Startup Algorithm}{subsection.3.4.2}{}}
\@writefile{lof}{\contentsline {figure}{\numberline {3.7}{\ignorespaces Interrupt Command Register~\blx@tocontentsinit {0}\autocite [sec.~3.11.6.1]{ia32}.\relax }}{30}{figure.3.7}\protected@file@percent }
\newlabel{fig:ia32icr}{{3.7}{30}{Interrupt Command Register~\autocite [sec.~3.11.6.1]{ia32}.\relax }{figure.3.7}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {3.4.3}Application Processor Boot Routine}{31}{subsection.3.4.3}\protected@file@percent }
\newlabel{subsec:apboot}{{3.4.3}{31}{Application Processor Boot Routine}{subsection.3.4.3}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {3.4.4}Application Processor Post-Boot Routine}{32}{subsection.3.4.4}\protected@file@percent }
\newlabel{subsec:apsystementry}{{3.4.4}{32}{Application Processor Post-Boot Routine}{subsection.3.4.4}{}}
\@setckpt{chap/implementation}{
\setcounter{page}{33}
\setcounter{equation}{0}
\setcounter{enumi}{9}
\setcounter{enumii}{0}
\setcounter{enumiii}{0}
\setcounter{enumiv}{0}
\setcounter{footnote}{18}
\setcounter{mpfootnote}{0}
\setcounter{part}{0}
\setcounter{chapter}{3}
\setcounter{section}{4}
\setcounter{subsection}{4}
\setcounter{subsubsection}{0}
\setcounter{paragraph}{0}
\setcounter{subparagraph}{0}
\setcounter{figure}{7}
\setcounter{table}{0}
\setcounter{parentequation}{0}
\setcounter{tcbbreakpart}{1}
\setcounter{tcblayer}{0}
\setcounter{tcolorbox@number}{53}
\setcounter{FancyVerbLine}{0}
\setcounter{linenumber}{1}
\setcounter{LN@truepage}{40}
\setcounter{FV@TrueTabGroupLevel}{0}
\setcounter{FV@TrueTabCounter}{0}
\setcounter{FV@HighlightLinesStart}{0}
\setcounter{FV@HighlightLinesStop}{0}
\setcounter{FancyVerbLineBreakLast}{0}
\setcounter{FV@BreakBufferDepth}{0}
\setcounter{float@type}{16}
\setcounter{minted@FancyVerbLineTemp}{0}
\setcounter{minted@pygmentizecounter}{0}
\setcounter{listing}{0}
\setcounter{tcblisting}{0}
\setcounter{caption@flags}{6}
\setcounter{continuedfloat}{0}
\setcounter{subfigure}{0}
\setcounter{subtable}{0}
\setcounter{section@level}{2}
\setcounter{Item}{46}
\setcounter{Hfootnote}{35}
\setcounter{bookmark@seq@number}{40}
\setcounter{AlgoLine}{0}
\setcounter{algocfline}{0}
\setcounter{algocfproc}{0}
\setcounter{algocf}{0}
\setcounter{lofdepth}{1}
\setcounter{lotdepth}{1}
\setcounter{svg@param@lastpage}{0}
\setcounter{svg@param@currpage}{-1}
\setcounter{su@anzahl}{0}
\setcounter{LT@tables}{0}
\setcounter{LT@chunks}{0}
\setcounter{@pps}{0}
\setcounter{@ppsavesec}{0}
\setcounter{@ppsaveapp}{0}
\setcounter{tabx@nest}{0}
\setcounter{listtotal}{0}
\setcounter{listcount}{0}
\setcounter{liststart}{0}
\setcounter{liststop}{0}
\setcounter{citecount}{0}
\setcounter{citetotal}{0}
\setcounter{multicitecount}{0}
\setcounter{multicitetotal}{0}
\setcounter{instcount}{77}
\setcounter{maxnames}{3}
\setcounter{minnames}{3}
\setcounter{maxitems}{3}
\setcounter{minitems}{1}
\setcounter{citecounter}{0}
\setcounter{maxcitecounter}{0}
\setcounter{savedcitecounter}{0}
\setcounter{uniquelist}{0}
\setcounter{uniquename}{0}
\setcounter{refsection}{0}
\setcounter{refsegment}{0}
\setcounter{maxextratitle}{0}
\setcounter{maxextratitleyear}{0}
\setcounter{maxextraname}{0}
\setcounter{maxextradate}{0}
\setcounter{maxextraalpha}{0}
\setcounter{abbrvpenalty}{50}
\setcounter{highnamepenalty}{50}
\setcounter{lownamepenalty}{25}
\setcounter{maxparens}{3}
\setcounter{parenlevel}{0}
\setcounter{blx@maxsection}{0}
\setcounter{mincomprange}{10}
\setcounter{maxcomprange}{100000}
\setcounter{mincompwidth}{1}
\setcounter{afterword}{0}
\setcounter{savedafterword}{0}
\setcounter{annotator}{0}
\setcounter{savedannotator}{0}
\setcounter{author}{0}
\setcounter{savedauthor}{0}
\setcounter{bookauthor}{0}
\setcounter{savedbookauthor}{0}
\setcounter{commentator}{0}
\setcounter{savedcommentator}{0}
\setcounter{editor}{0}
\setcounter{savededitor}{0}
\setcounter{editora}{0}
\setcounter{savededitora}{0}
\setcounter{editorb}{0}
\setcounter{savededitorb}{0}
\setcounter{editorc}{0}
\setcounter{savededitorc}{0}
\setcounter{foreword}{0}
\setcounter{savedforeword}{0}
\setcounter{holder}{0}
\setcounter{savedholder}{0}
\setcounter{introduction}{0}
\setcounter{savedintroduction}{0}
\setcounter{namea}{0}
\setcounter{savednamea}{0}
\setcounter{nameb}{0}
\setcounter{savednameb}{0}
\setcounter{namec}{0}
\setcounter{savednamec}{0}
\setcounter{translator}{0}
\setcounter{savedtranslator}{0}
\setcounter{shortauthor}{0}
\setcounter{savedshortauthor}{0}
\setcounter{shorteditor}{0}
\setcounter{savedshorteditor}{0}
\setcounter{labelname}{0}
\setcounter{savedlabelname}{0}
\setcounter{institution}{0}
\setcounter{savedinstitution}{0}
\setcounter{lista}{0}
\setcounter{savedlista}{0}
\setcounter{listb}{0}
\setcounter{savedlistb}{0}
\setcounter{listc}{0}
\setcounter{savedlistc}{0}
\setcounter{listd}{0}
\setcounter{savedlistd}{0}
\setcounter{liste}{0}
\setcounter{savedliste}{0}
\setcounter{listf}{0}
\setcounter{savedlistf}{0}
\setcounter{location}{0}
\setcounter{savedlocation}{0}
\setcounter{organization}{0}
\setcounter{savedorganization}{0}
\setcounter{origlocation}{0}
\setcounter{savedoriglocation}{0}
\setcounter{origpublisher}{0}
\setcounter{savedorigpublisher}{0}
\setcounter{publisher}{0}
\setcounter{savedpublisher}{0}
\setcounter{language}{0}
\setcounter{savedlanguage}{0}
\setcounter{origlanguage}{0}
\setcounter{savedoriglanguage}{0}
\setcounter{pageref}{0}
\setcounter{savedpageref}{0}
\setcounter{textcitecount}{0}
\setcounter{textcitetotal}{0}
\setcounter{textcitemaxnames}{0}
\setcounter{biburlbigbreakpenalty}{100}
\setcounter{biburlbreakpenalty}{200}
\setcounter{biburlnumpenalty}{0}
\setcounter{biburlucpenalty}{0}
\setcounter{biburllcpenalty}{0}
\setcounter{smartand}{1}
\setcounter{bbx:relatedcount}{0}
\setcounter{bbx:relatedtotal}{0}
\setcounter{cbx@tempcnta}{0}
\setcounter{cbx@tempcntb}{6}
\setcounter{cbx@tempcntc}{0}
\setcounter{cbx@tempcntd}{-1}
\setcounter{tcb@cnt@codeblock}{0}
}

View File

@ -1,9 +1,8 @@
\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, details on the implementation source code are found in \autoref{ch:listings}.
\autoref{subsec:hhuosintegration} deals with the modifications done to the hhuOS system to integrate the APIC implementation.
This chapter describes the implementation of the APIC interrupt controller for hhuOS and the source code produced during this thesis.
Code examples are simplified and do not necessarily match the actual implementation completely, to allow for self-contained examples.
\clearpage
@ -59,7 +58,7 @@ A 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 Interrupts with logical destinations (flat/clustered) 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{
@ -70,7 +69,7 @@ A summary of features that are outside the scope of this thesis:
\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:
To be able to easily extend an APIC implementation for single-core systems to SMP systems, some things are taken into account:
\begin{itemize}
\item SMP systems need to manage multiple \code{LocalApic} and \code{ApicTimer} instances.
@ -98,400 +97,394 @@ To be able to easily extend an APIC implementation for single-core systems to SM
% classes only selectively expose their interfaces (by using the \code{friend} declaration) for the
% same reason.
\clearpage
\section{Integration into HhuOS}
\label{sec:apxhhuos}
\subsection{Interrupt Handling in HhuOS}
\label{subsec:apxcurrenthhuos}
In hhuOS, external interrupts are handled in two stages (see \autoref{subsec:apxcurrenthhuos} for code examples):
\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, 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, 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 to register itself to the correct vector number.
HhuOS supports assigning multiple interrupt handlers to a single interrupt vector and cascading interrupts.
\end{enumerate}
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, which in turn is used to trigger hhuOS' preemptive round-robin scheduler (the \code{Scheduler} class).
The PIT and other devices are initialized before the system entry point, in the \code{System::initializeSystem} function.
Devices that provide interrupts implement the \code{InterruptHandler} interface:
\begin{codeblock}{The InterruptHandler Interface (InterruptHandler.h)~\autocite{hhuos}}{C++}
\cppfile{code/interrupthandler_def.cpp}
\end{codeblock}
These interrupt handlers have to be registered to the appropriate interrupt vector:
\begin{codeblock}{Assigning an Interrupt Handler (InterruptDispatcher.cpp)~\autocite{hhuos}}{C++}
\cppfile{code/interruptdispatcher_assign.cpp}
\end{codeblock}
Multiple interrupt handlers can be registered to the same interrupt vector.
For every interrupt that arrives at a CPU, the first-stage interrupt handler (registered in the IDT for every vector) is called, which in turn calls the device-specific handlers:
\begin{codeblock}{Triggering an Interrupt Handler (InterruptDispatcher.cpp)~\autocite{hhuos}}{C++}
\cppfile{code/interruptdispatcher_dispatch.cpp}
\end{codeblock}
The PIT interrupt handler manages the system time and the scheduler:
\begin{codeblock}{The PIT Interrupt Handler (Pit.cpp)~\autocite{hhuos}}{C++}
\cppfile{code/pit_trigger.cpp}
\end{codeblock}
\subsection{Necessary Modifications to HhuOS}
\label{subsec:hhuosintegration}
To integrate the APIC implementation into hhuOS, some preexisting components of its interrupt infrastructure (see \autoref{sec:apxhhuos}) have to be modified:
\begin{enumerate}
\item The \code{InterruptService} has to forward calls 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}).
\item The existing devices using interrupts need to use the new \code{InterruptVector} and \code{InterruptRequest} enums.
\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]{Disabling PIT Preemption (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}
\subsection{Public Interface of the APIC Subsystem}
\label{subsec:hhuospublicinterface}
To interact with the APIC subsystem from the \textquote{outside}, the \code{Apic} class is used, which exposes the necessary functionality:
\begin{codeblock}{The APIC Public Interface (Apic.h)}{C++}
\cppfile{code/apic_def.cpp}
\end{codeblock}
Enabling the APIC subsystem is done by the \code{enable} function (see \autoref{fig:apicenable}).
\section{Local APIC}
\label{sec:lapicinit}
\label{sec:apxlocalapic}
The local APIC block diagram (see \autoref{fig:localapicblock}) shows a number of registers that are required for initialization\footnote{
Registers like the \textquote{Trigger Mode Register}, \textquote{Logical Destination Register} or \textquote{Destination Format Register} remain unused in this thesis.}:
\subsection{Disabling PIC Mode}
\label{subsec:apxdisablepic}
\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}
Setting the IMCR\footnote{
Writing the IMCR is detailed in the \textquote{MultiProcessor Specification}~\autocite[sec.~3.6.2.1]{mpspec}.}
\ using hhuOS' \code{IoPort} class:
\begin{figure}[h]
\centering
\begin{subfigure}[b]{0.9\textwidth}
\includesvg[width=1.0\linewidth]{img/ia32_manual_local_apic_blockdiagram.svg}
\end{subfigure}
\caption{The Local APIC Block Diagram~\autocite[sec.~3.11.4.1]{ia32}.}
\label{fig:localapicblock}
\end{figure}
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 \textit{LINT1}: The local APIC's NMI source.
\item \textit{Timer}: Periodic interrupt triggered by the APIC timer.
\item \textit{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 IA32\textunderscore{}APIC\textunderscore{}BASE MSR also requires initialization (described in \autoref{subsec:lapicenable}).
After system power-up, the local APIC is in the following state~\autocite[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, all performed before interrupt handling is enabled (see \autoref{fig:apicenable}):
\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 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.
\item Enable interrupts for the BSP and APs.
\end{enumerate}
\begin{codeblock}{Disabling PIC Mode (LocalApic.cpp)}{C++}
\cppfile{code/lapic_imcr.cpp}
\end{codeblock}
\subsection{Accessing Local APIC Registers in xApic Mode}
\label{subsec:xapicregacc}
\label{subsec:apxxapicregacc}
Accessing registers in xApic mode is done via MMIO and requires a single page (\SI{4}{\kilo\byte}) of memory, mapped to the \textquote{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 \textquote{strong uncachable}\footnote{
See IA-32 manual for information on this caching strategy~\autocite[sec.~3.12.3]{ia32}.}
~\autocite[sec.~3.11.4.1]{ia32} for this region (see \autoref{subsec:apxxapicregacc} for the example implementation).
The xApic register access requires a single page of strong uncachable memory, but since this requires setting attributes in the \textquote{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, which maps a physical address to the kernel heap, with hhuOS' \textquote{CACHE\textunderscore{}DISABLE} flag set in the kernel page table:
The address offsets (from the base address) for the local APIC registers are listed in the IA-32 manual~\autocite[sec.~3.11.4.1]{ia32} and in \autoref{tab:lapicregs}.
\begin{codeblock}{Allocating the Local APIC's MMIO Region (LocalApic.cpp)}{C++}
\cppfile{code/lapic_mmio_alloc.cpp}
\end{codeblock}
\subsection{Enabling the Local APIC}
\label{subsec:lapicenable}
A register can now be written as follows:
Because the system boots in PIC mode, \code{0x01} should be written to the IMCR~\autocite[sec.~3.6.2.1]{mpspec} to disconnect the PIC from the local APIC's LINT0 INTI (see \autoref{fig:integratedapic}, for the example implementation see \autoref{subsec:apxdisablepic}).
\begin{codeblock}[label=lst:lapicmmiowrite]{Writing a Local APIC MMIO Register (LocalApic.cpp)}{C++}
\cppfile{code/lapic_mmio_write.cpp}
\end{codeblock}
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~\autocite[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 \textquote{global enable/disable} (\textquote{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~\autocite[sec.~3.11.4.3]{ia32}.}.
Enabling x2Apic mode is done by setting the \textquote{EXTD} bit (see \autoref{fig:ia32apicbasemsr}/\autoref{tab:lapicregsmsr}) of the IA32\textunderscore{}APIC\textunderscore{}BASE MSR~\autocite[sec.~3.11.4.3]{ia32}.
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\footnote{
The usual approach of \textquote{adding} the different required flags together to obtain the desired register content was intentionally not used for the sake of expressiveness: This approach does not highlight which flags are available and which flags are \textit{not} chosen.}:
\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~\autocite[sec.~3.11.4.4]{ia32}.}
\label{fig:ia32apicbasemsr}
\end{figure}
\begin{codeblock}[label=lst:msrentry]{The MSREntry Structure (LocalApicRegisters.h)}{C++}
\cppfile{code/lapic_msr_entry.cpp}
\end{codeblock}
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.
\begin{codeblock}[label=lst:svrentry]{The SVREntry Structure (LocalApicRegisters.h)}{C++}
\cppfile{code/lapic_svr_entry.cpp}
\end{codeblock}
Besides the \textquote{global enable/disable} flag, the APIC can also be enabled/disabled by using the \textquote{software enable/disable} flag in the SVR, see \autoref{subsec:lapicsoftenable}.
\begin{codeblock}[label=lst:lvtentry]{The LVTEntry Structure (LocalApicRegisters.h)}{C++}
\cppfile{code/lapic_lvt_entry.cpp}
\end{codeblock}
\subsection{Handling Local Interrupts}
\label{subsec:lapiclvtinit}
\begin{codeblock}[label=lst:icrentry]{The ICREntry Structure (LocalApicRegisters.h)}{C++}
\cppfile{code/lapic_icr_entry.cpp}
\end{codeblock}
To configure how the local APIC handles the different local interrupts, the LVT registers are written (see \autoref{fig:localapiclvt}).
These can be used in combination with some convenience functions:
\begin{figure}[h]
\centering
\begin{subfigure}[b]{0.7\textwidth}
\includesvg[width=1.0\linewidth]{img/ia32_lvt.svg}
\end{subfigure}
\caption{The Local Vector Table~\autocite[sec.~3.11.5.1]{ia32}.}
\label{fig:localapiclvt}
\end{figure}
\begin{codeblock}{Writing the IA32\textunderscore{}APIC\textunderscore{}BASE MSR (LocalApic.cpp)}{C++}
\cppfile{code/lapic_write_msr.cpp}
\end{codeblock}
Local interrupts can be configured to use different delivery modes (excerpt)~\autocite[sec.~3.11.5.1]{ia32}:
\begin{codeblock}{Writing the SVR (LocalApic.cpp)}{C++}
\cppfile{code/lapic_write_svr.cpp}
\end{codeblock}
\begin{itemize}
\item \textit{Fixed}: Simply delivers the interrupt vector stored in the LVT register.
\item \textit{NMI}: Configures this interrupt as non-maskable, this ignores the stored vector number.
\item \textit{ExtINT}: The interrupt is treated as an external interrupt (instead of local interrupt), used e.g.\ in virtual wire mode for LINT0\@.
\end{itemize}
\begin{codeblock}{Writing the LVT (LocalApic.cpp)}{C++}
\cppfile{code/lapic_write_lvt.cpp}
\end{codeblock}
Initially, all local interrupts are initialized to PC/AT defaults: Masked, edge-triggered, active-high and with \textit{fixed} delivery mode.
Most importantly, the vector fields (bits 0:7 of each LVT register) are set to their corresponding interrupt vector (see \autoref{subsec:apxlvtinit} for an example implementation).
\begin{codeblock}{Writing the ICR (LocalApic.cpp)}{C++}
\cppfile{code/lapic_write_icr.cpp}
\end{codeblock}
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~\autocite{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 \textquote{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{Initializing the LVT}
\label{subsec:apxlvtinit}
\subsection{Allowing Interrupt Processing}
\label{subsec:lapicsoftenable}
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}):
To complete a minimal local APIC initialization, the \textquote{software enable/disable} flag and the spurious interrupt vector (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 four bits must be set (see \autoref{fig:ia32apicsvr}).
\begin{codeblock}{Configuring the Local Error Interrupt (LocalApic.cpp)}{C++}
\cppfile{code/lapic_lvt_example.cpp}
\end{codeblock}
\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~\autocite[sec.~3.11.9]{ia32}.}
\label{fig:ia32apicsvr}
\end{figure}
This process is repeated for each local interrupt, with variations for the NMI and timer interrupts.
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{subsec:apxsvr} for an implementation example).
\subsection{Handling the Spurious Interrupt}
\label{subsec:apxsvr}
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~\autocite[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.
This implementation sets the SVR by using the \code{SVREntry} struct (see \autoref{lst:svrentry}):
\subsection{Local Interrupt EOI}
\label{subsec:lapiceoi}
\begin{codeblock}{Setting the Spurious Interrupt Vector (LocalApic.cpp)}{C++}
\cppfile{code/lapic_svr_example.cpp}
\end{codeblock}
To notify the local APIC that a local interrupt is being handled, its EOI register (see \autoref{tab:lapicregseoi}) has to be written.
Not all local interrupts require EOIs: NMI, SMI, INIT, ExtINT, SIPI, or INIT-Deassert interrupts are excluded~\autocite[sec.~3.11.8.5]{ia32}.
Because hhuOS uses a two-stage interrupt handling approach (described in \autoref{subsec:apxcurrenthhuos}), the spurious interrupt does not receive its own interrupt handler.
Instead, it is ignored in the \code{dispatch} function, hhuOS' \textquote{first-stage} interrupt handler:
EOIs for external interrupts are also handled by the local APIC, further described in \autoref{subsec:ioapiceoi}.
\begin{codeblock}{Checking for Spurious Interrupts (InterruptDispatcher.cpp)}{C++}
\cppfile{code/interruptdispatcher_check_spurious.cpp}
\end{codeblock}
\subsection{APIC Timer}
\label{subsec:lapictimer}
\begin{codeblock}{Ignoring Spurious Interrupts (InterruptDispatcher.cpp)}{C++}
\cppfile{code/interruptdispatcher_ignore_spurious.cpp}
\end{codeblock}
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 does not 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.
\subsection{Using the APIC Timer}
\label{subsec:apxapictimer}
The APIC timer supports three different timer modes, that can be set in the timer's LVT register:
The timer frequency is determined by counting the ticks in one millisecond, using the PIT as calibration source:
\begin{enumerate}
\item \textit{Oneshot}: Trigger exactly one interrupt when the counter reaches zero.
\item \textit{Periodic}: Trigger an interrupt each time the counter reaches zero, on zero the counter reloads its initial value.
\item \textit{TSC-Deadline}: Trigger exactly one interrupt at an absolute time.
\end{enumerate}
\begin{codeblock}{Calibrating the APIC Timer (ApicTimer.cpp)}{C++}
\cppfile{code/apictimer_calibrate.cpp}
\end{codeblock}
This implementation uses the APIC timer in periodic mode, to trigger the scheduler preemption.
Initialization requires the following steps (order recommended by OSDev~\autocite{osdev}):
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 \textquote{Interrupt on Terminal Count} on channel zero and polls the channel's output status~\autocite{pit}:
\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}
\begin{codeblock}{Microsecond Delay without Interrupts (Pit.cpp)}{C++}
\cppfile{code/pit_early_delay.cpp}
\end{codeblock}
In this implementation, the APIC timer is calibrated by counting the amount of ticks in one millisecond using oneshot mode (see \autoref{subsec: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.
Furthermore, the calibration is only performed once, even if multiple APIC timers are used.
This has to be taken into account if multiple timers with different dividers are to be used.
To use the timer, an interrupt handler has to be registered to its interrupt vector (see \autoref{subsec:apxapictimer} for an example implementation).
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\@.
The handler belonging to the BSP's APIC timer also triggers the scheduler preemption (instead of the PIT):
\subsection{APIC Error Interrupt}
\label{subsec:lapicerror}
\begin{codeblock}{Handling the APIC Timer Interrupt (ApicTimer.cpp)}{C++}
\cppfile{code/apictimer_trigger.cpp}
\end{codeblock}
Errors can occur e.g.\ 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.
\subsection{Handling Local APIC Errors}
\label{subsec:apxhandlingerror}
\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~\autocite[sec.~3.11.5.3]{ia32}.}
\label{fig:ia32esr}
\end{figure}
The error interrupt handler obtains the ESR's contents by writing to it first:
The ESR is a \textquote{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, which doesn't happen automatically~\autocite[sec.~3.11.5.3]{ia32}.
\begin{codeblock}{The Local APIC Error Interrupt Handler (ApicErrorHandler.cpp)}{C++}
\cppfile{code/apicerror_trigger.cpp}
\end{codeblock}
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{subsec:apxhandlingerror} for an example implementation).
\clearpage
Because every CPU core can only access its own local APIC's registers, a single instance of this interrupt handler can be used for all AP's in the system.
\section{I/O APIC}
\label{sec:ioapicinit}
\label{sec:apxioapic}
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~\autocite[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}).
\subsection{Accessing I/O APIC Registers}
\label{subsec:iolistings}
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 \textit{physical} destination mode\footnote{
The alternative is \textit{logical} destination mode, which allows addressing individual or clusters of local APIC's in a larger volume of processors~\autocite[sec.~3.11.6.2.2]{ia32}.}
~\autocite[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 ISA bus defaults\footnote{
Edge-triggered, active-high.},
\ with \textit{fixed} delivery mode, masked, and the corresponding interrupt vector, as defined by the \code{InterruptVector} enum.
The I/O APIC's indirect register access requires two MMIO registers, that can be written similar to the local APIC's registers:
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\@.
\begin{codeblock}{Writing an I/O APIC MMIO Register (IoApic.h)}{C++}
\cppfile{code/ioapic_write_mmio.cpp}
\end{codeblock}
Unlike the local APIC's registers, the REDTBL registers are accessed indirectly: Two registers, the \textquote{Index} and \textquote{Data} register~\autocite[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{subsec: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~\autocite[sec.~9.5.7]{ich5}.}.
Using the \textquote{Index} and \textquote{Data} registers to access the I/O APIC's indirect registers:
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.
\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}
\subsection{Interrupt Overrides}
\label{subsec:ioapicpcat}
\label{subsec:apxirqoverrides}
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 INTIs used by each PC/AT compatible interrupt has to be determined by the OS at runtime, by using ACPI\@.
ACPI provides \textquote{Interrupt Source Override} structures~\autocite[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 customizing the pin polarity and trigger mode of PC/AT compatible interrupts.
This implementation represents an interrupt override using the following structure:
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} (see \autoref{fig:integratedapic}).
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{subsec:apxirqoverrides} for an example implementation).
\begin{codeblock}{The External Interrupt Override Structure (IoApic.h)}{C++}
\cppfile{code/ioapic_irqoverride.cpp}
\end{codeblock}
\subsection{External Interrupt EOI}
\label{subsec:ioapiceoi}
During initialization, the overrides 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\@:
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 \textquote{Remote IRR} bit in the corresponding REDTBL entry~\autocite[sec.~9.5.8]{ich5} (see \autoref{tab:ioapicregsredtbl}).
\begin{codeblock}{Initializing the REDTBL (IoApic.cpp)}{C++}
\cppfile{code/ioapic_redtbl_example.cpp}
\end{codeblock}
There are three possible ways to signal completion of a level-triggered external interrupt to clear the remote IRR bit:
During regular operation, the overrides are used to determine the correct REDTBL entries for e.g.\ unmasking an interrupt:
\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~\autocite[sec.~9.5.5]{ich5}.
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~\autocite[io\textunderscore{}apic.c]{linux}.
\end{enumerate}
\begin{codeblock}{Unmasking an IRQ (Apic.cpp)}{C++}
\cppfile{code/apic_allow.cpp}
\end{codeblock}
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~\autocite[sec.~3.11.8.5]{ia32}.}.
To convey this deviation between GSIs and PC/AT compatible IRQs very clearly, the public \code{Apic::allow} function accepts an \code{InterruptRequest} as an argument (that allows addressing the interrupt by name), while the internal \code{IoApic::allow} function only accepts a \code{GlobalSystemInterrupt} as argument:
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 \textquote{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.
\begin{codeblock}{Unmasking an IRQ Internally (IoApic.cpp)}{C++}
\cppfile{code/ioapic_allow.cpp}
\end{codeblock}
\subsection{Multiple I/O APICs}
\label{subsec:multiioapic}
Most consumer hardware, for example all IA processors~\autocite{ia32} and ICH hubs~\autocite{ich5}, only provide a single I/O APIC, although technically multiple I/O APICs are supported by the \textquote{MultiProcessor Specification}~\autocite[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~\autocite[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 \textquote{GSI Base}~\autocite[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~\autocite[sec.~9.5.7]{ich5} (see \autoref{tab:ioapicregsver})\footnote{
This approach was previously used in this implementation, but removed for simplicity.}.
\clearpage
The internal \code{IoApic::allow} function is hidden (\code{private}) from the OS, and gets only called by the exposed \code{Apic::allow} function.
This prevents accidentally setting the wrong REDTBL entry by not taking possible interrupt overrides into account.
The same principle is applied to the other operations concerning GSIs.
\section{Symmetric Multiprocessing}
\label{sec:smpinit}
\label{sec:apxsymmetric}
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.
An overview of the complete SMP startup process can be found in \autoref{fig:smpenable}.
To determine the number 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{Issuing Inter-Processor Interrupts}
\label{subsec:apxipis}
\subsection{Inter-Processor Interrupts}
\label{subsec:ipis}
To issue an IPI, the ICR is written by using the \code{ICREntry} struct (see \autoref{lst:icrentry}):
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{subsec:apxipis} for an example implementation).
\begin{codeblock}{Issuing an INIT IPI (LocalApic.cpp)}{C++}
\cppfile{code/lapic_initipi_example.cpp}
\end{codeblock}
Depending on the APIC architecture, two different IPIs are required: The \textit{INIT IPI} for systems using a discrete APIC, and the \textbf{\gls{sipi}} for systems using the xApic or x2Apic architectures:
\begin{codeblock}{Issuing a SIPI (LocalApic.cpp)}{C++}
\cppfile{code/lapic_sipi_example.cpp}
\end{codeblock}
\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~\autocite[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~\autocite[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}
It is important to note that the SIPI does not receive the startup address, but the page number.
For this reason, the startup routine must be relocated starting at a page boundary.
The \code{page} argument can be determined by removing the page offset from the linear address, which is done by right-shifting the address by the offset length (\SI{12}{\bit} for \SI{4}{\kilo\byte} pages).
For the physical memory location used in this implementation (\code{0x8000}) this yields page number \code{8}.
To wait until the IPI is sent, the ICR's delivery status bit can be polled.
\subsection{Preparing Symmetric Multiprocessing Startup}
\label{subsec:apxpreparesmp}
\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~\autocite[sec.~3.11.6.1]{ia32}.}
\label{fig:ia32icr}
\end{figure}
Before executing the \textquote{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 do not change after enabling paging in protected mode.
To keep the required variables available to the startup code, these are located in the routines \textquote{TEXT} section:
\begin{codeblock}{The Boot Routine's Variables (smp\textunderscore{}boot.asm)}{nasm}
\cppfile{code/ap_boot_variables.asm}
\end{codeblock}
The variables are initialized during runtime:
\begin{codeblock}{Preparing the Boot Routine's Variables (ApicSmp.cpp)}{C++}
\cppfile{code/ap_boot_variables.cpp}
\end{codeblock}
This approach was taken from SerenityOS~\autocite[APIC.cpp]{serenity}:
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{subsec:apxapboot}.
\subsection{Universal Startup Algorithm}
\label{subsec:apstartup}
\label{subsec:apxmpusa}
SMP initialization is performed differently on various processors.
Intel's \textquote{MultiProcessor Specification} defines a \textquote{Universal Startup Algorithm} for multiprocessor systems~\autocite[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\@.
The \textquote{INIT-SIPI-SIPI} sequence, or \textquote{Universal Startup Algorithm} is performed by issuing IPIs as described in \autoref{subsec:apxipis} and using the PIT as time source (see \autoref{subsec:apxapictimer}):
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}~\autocite[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 \SI{32}{\bit} field, located at physical address \code{40:67}~\autocite[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, see \autoref{subsec:apxapictimer}.}.
\begin{codeblock}{The Universal Startup Algorithm (ApicSmp.cpp)}{C++}
\cppfile{code/ap_boot_usa.cpp}
\end{codeblock}
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~\autocite[lapic.c]{xv6}.
Boot completion is signaled in the AP's entry function:
After preparation, the universal startup algorithm is now performed as follows, for each AP sequentially (see \autoref{subsec:apxmpusa} for an example implementation and \autoref{fig:smpenable}):
\begin{enumerate}
\item Assert and de-assert the level-triggered INIT IPI\@.
\item Delay for \SI{10}{\milli\second}.
\item Send the SIPI\@.
\item Delay for \SI{200}{\micro\second}.
\item Send the SIPI again.
\item Delay for \SI{200}{\micro\second} 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.
\begin{codeblock}{Signaling AP Boot Completion (smp\textunderscore{}entry.cpp)}{C++}
\cppfile{code/smp_entry.cpp}
\end{codeblock}
\subsection{Application Processor Boot Routine}
\label{subsec:apboot}
\label{subsec:apxapboot}
After executing the \textquote{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{subsec:apxapboot} for an example implementation):
Because like the BSP, every AP is initialized in real mode, it has to be switched to protected mode first:
\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}
\begin{codeblock}{Preparing the Switch to Protected Mode (smp\textunderscore{}boot.asm)}{nasm}
\nasmfile{code/ap_boot_real_prepare.asm}
\end{codeblock}
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 hardware context switching, e.g.\ when interrupt-based system calls are used on all CPUs.
Then, by enabling protected mode, setting the segment registers and far-jumping to the \SI{32}{\bit} code segment, the switch is performed:
Because it is relocated into lower physical memory, 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 \textquote{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{subsec:apxpreparesmp} for an example implementation).
\begin{codeblock}{Switching from Real Mode to Protected Mode (smp\textunderscore{}boot.asm)}{nasm}
\nasmfile{code/ap_boot_real.asm}
\end{codeblock}
In \SI{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}{Reusing Values 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 stack. If hardware context switching is to be used, the AP additionally requires its own GDT and TSS\@:
\begin{codeblock}{Calling the Entry Function (smp\textunderscore{}boot.asm)}{nasm}
\nasmfile{code/ap_boot_protected_ap.asm}
\end{codeblock}
\subsection{Application Processor Post-Boot Routine}
\label{subsec:apsystementry}
\label{subsec:apxappostboot}
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.}.
When the AP has booted, it initializes its own APIC, including the APIC timer and error handler:
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~\autocite[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{subsec:apxappostboot} for an example implementation).
\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 \textquote{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.
\cleardoublepage

409
chap/interrupthandling.tex Normal file
View File

@ -0,0 +1,409 @@
\chapter{Using the APIC}
\label{ch:interrupthandling}
This chapter will detail the general requirements to integrate APIC support into an operating system.
Details on the implementation in hhuOS are found in \autoref{ch:implementation}.
\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 APIC usage\footnote{
Registers like the \textquote{Trigger Mode Register}, \textquote{Logical Destination Register} or \textquote{Destination Format Register} remain unused in this thesis.}:
\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}
\begin{figure}[h]
\centering
\begin{subfigure}[b]{0.9\textwidth}
\includesvg[width=1.0\linewidth]{img/ia32_manual_local_apic_blockdiagram.svg}
\end{subfigure}
\caption{The Local APIC Block Diagram~\autocite[sec.~3.11.4.1]{ia32}.}
\label{fig:localapicblock}
\end{figure}
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 \textit{LINT1}: The local APIC's NMI source.
\item \textit{Timer}: Periodic interrupt triggered by the APIC timer.
\item \textit{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 IA32\textunderscore{}APIC\textunderscore{}BASE MSR also require initialization (described in \autoref{subsec:lapicenable}).
After system power-up, the local APIC is in the following state~\autocite[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, all performed before interrupt handling is enabled (see \autoref{fig:apicenable} for the full initialization sequence including all components):
\begin{enumerate}
\item Enable symmetric I/O mode and set the APIC operating mode.
\item Allocate MMIO memory for register access.
\item Initialize the LVT and NMI\@.
\item Initialize the SVR\@.
\item Initialize the TPR\@.
\item Initialize the APIC timer and error handler.
\item Synchronize the arbitration ID\@.
\item Enable interrupts.
\end{enumerate}
\subsection{Enabling the Local APIC}
\label{subsec:lapicenable}
Because the system boots in PIC mode, \code{0x01} should be written to the IMCR~\autocite[sec.~3.6.2.1]{mpspec} to disconnect the PIC from the local APIC's LINT0 INTI (see \autoref{fig:integratedapic}, for the example implementation see \autoref{subsec:apxdisablepic}).
To set the operating mode, it is first determined which modes are supported by executing the \code{cpuid}~\autocite{x86isa} 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~\autocite[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 \textquote{global enable/disable} (\textquote{EN}) bit in the IA32\textunderscore{}APIC\textunderscore{}BASE MSR (see \autoref{fig:ia32apicbasemsr}/\autoref{tab:lapicregsmsr}) allows disabling xApic mode globally\footnote{
If the system uses the discrete APIC bus, xApic mode cannot be re-enabled without a system reset~\autocite[sec.~3.11.4.3]{ia32}.}.
Enabling x2Apic mode is done by setting the \textquote{EXTD} bit (see \autoref{fig:ia32apicbasemsr}/\autoref{tab:lapicregsmsr}) of the IA32\textunderscore{}APIC\textunderscore{}BASE MSR~\autocite[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~\autocite[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 \textquote{global enable/disable} flag, the APIC can also be enabled/disabled by using the \textquote{software enable/disable} flag in the SVR, see \autoref{subsec:lapicsoftenable}.
\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 (\SI{4}{\kilo\byte}) of memory, mapped to the \textquote{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 \textquote{strong uncachable}\footnote{
See IA-32 manual for information on this caching strategy~\autocite[sec.~3.12.3]{ia32}.}
~\autocite[sec.~3.11.4.1]{ia32} for this region.
The address offsets (from the base address) for the local APIC registers are listed in the IA-32 manual~\autocite[sec.~3.11.4.1]{ia32} and in \autoref{tab:lapicregs}.
For a short note on x2Apic register access, see \autoref{subsec:usingx2apic}.
\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}).
\begin{figure}[h]
\centering
\begin{subfigure}[b]{0.7\textwidth}
\includesvg[width=1.0\linewidth]{img/ia32_lvt.svg}
\end{subfigure}
\caption{The Local Vector Table~\autocite[sec.~3.11.5.1]{ia32}.}
\label{fig:localapiclvt}
\end{figure}
Local interrupts can be configured to use different delivery modes (excerpt)~\autocite[sec.~3.11.5.1]{ia32}:
\begin{itemize}
\item \textit{Fixed}: Simply delivers the interrupt vector stored in the LVT register.
\item \textit{NMI}: Configures this interrupt as non-maskable, this ignores the stored vector number.
\item \textit{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 \textit{fixed} delivery mode.
Most importantly, the vector fields (bits 0:7 of each LVT register) are set to their corresponding interrupt vector (see \autoref{subsec: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~\autocite{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 \textit{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 \textquote{software enable/disable} flag and the spurious interrupt vector (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 four bits must always 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~\autocite[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{subsec: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~\autocite[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 is being handled, its EOI register (see \autoref{tab:lapicregseoi}) has to be written.
Not all local interrupts require EOIs: NMI, SMI, INIT, ExtINT, SIPI, or INIT-Deassert interrupts are excluded~\autocite[sec.~3.11.8.5]{ia32}.
EOIs for external interrupts are also handled by the local APIC, further 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 does not 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 (see \autoref{fig:localapiclvt}):
\begin{enumerate}
\item \textit{Oneshot}: Trigger exactly one interrupt when the counter reaches zero.
\item \textit{Periodic}: Trigger an interrupt each time the counter reaches zero, on zero the counter reloads its initial value.
\item \textit{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 on OSDev~\autocite{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.
Setting the initial counter activates the timer.
\end{enumerate}
In this implementation, the APIC timer is calibrated by counting the amount of ticks in one millisecond using oneshot mode.
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.
\subsection{APIC Error Interrupt}
\label{subsec:lapicerror}
Errors can occur e.g.\ 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~\autocite[sec.~3.11.5.3]{ia32}.}
\label{fig:ia32esr}
\end{figure}
The ESR is a \textquote{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, which does not happen automatically~\autocite[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{subsec:apxhandlingerror} for an example implementation).
\subsection{Using x2Apic Mode}
\label{subsec:usingx2apic}
% TODO
\section{I/O APIC}
\label{sec:ioapicinit}
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~\autocite[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 \textit{physical} destination mode\footnote{
The alternative is \textit{logical} destination mode, which allows addressing individual or clusters of local APIC's in a larger volume of processors~\autocite[sec.~3.11.6.2.2]{ia32}.}
~\autocite[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 ISA bus defaults\footnote{
Edge-triggered, active-high.},
\ with \textit{fixed} delivery mode, masked, and the corresponding interrupt vector.
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 \textquote{Index} and \textquote{Data} register~\autocite[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{subsec: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~\autocite[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 INTI used by each PC/AT compatible interrupt has to be determined by the OS at runtime, by using ACPI\@.
ACPI provides \textquote{Interrupt Source Override} structures~\autocite[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 customizing 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} (see \autoref{fig:integratedapic}).
Thus, to allow the PIT interrupt in those systems, the REDTBL entry belonging to \code{GSI2} instead of \code{GSI0} has to be written.
\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 \textquote{Remote IRR} bit in the corresponding REDTBL entry~\autocite[sec.~9.5.8]{ich5} (see \autoref{tab:ioapicregsredtbl}).
This is required to not redirect the level-triggered interrupt to the local APIC multiple times, while the INTI is asserted.
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~\autocite[sec.~9.5.5]{ich5}.
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~\autocite[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~\autocite[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 \textquote{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~\autocite{ia32} and ICH hubs~\autocite{ich5}, only provide a single I/O APIC, although technically multiple I/O APICs are supported by the \textquote{MultiProcessor Specification}~\autocite[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~\autocite[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 \textquote{GSI Base}~\autocite[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~\autocite[sec.~9.5.7]{ich5} (see \autoref{tab:ioapicregsver})\footnote{
This approach was previously used in this implementation, but removed for simplicity.}.
For many I/O APICs, replacing the local APIC's EOI broadcasting with a directed external EOI could be useful, because EOIs are broadcast to each I/O APIC\@.
\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 number 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.
Depending on the APIC architecture, two different IPIs are required: The \textit{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~\autocite[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~\autocite[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~\autocite[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 \textquote{MultiProcessor Specification} defines a \textquote{Universal Startup Algorithm} for multiprocessor systems~\autocite[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\@.
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 pre-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}~\autocite[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 \SI{32}{\bit} field, located at physical address \code{40:67}~\autocite[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, see \autoref{subsec:apxapictimer}.}.
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~\autocite[lapic.c]{xv6}.
After preparation, the universal startup algorithm is now performed as follows, for each AP sequentially (see \autoref{fig:smpenable} for the full SMP startup sequence):
\begin{enumerate}
\item Assert and de-assert the level-triggered INIT IPI\@.
\item Delay for \SI{10}{\milli\second}.
\item Send the SIPI\@.
\item Delay for \SI{200}{\micro\second}.
\item Send the SIPI again.
\item Delay for \SI{200}{\micro\second} 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 \textquote{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:
\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 hardware context switching, e.g.\ when interrupt-based system calls are used on all CPUs.
Because it is relocated into lower physical memory, 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 \textquote{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.
\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~\autocite[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.}.
\cleardoublepage

View File

@ -1,187 +0,0 @@
\relax
\providecommand{\transparent@use}[1]{}
\providecommand\hyper@newdestlabel[2]{}
\@writefile{listings}{\addvspace {10pt}}
\@writefile{toc}{\contentsline {chapter}{\numberline {1}Introduction}{1}{chapter.1}\protected@file@percent }
\@writefile{lof}{\addvspace {10\p@ }}
\@writefile{lot}{\addvspace {10\p@ }}
\@writefile{loa}{\addvspace {10\p@ }}
\newlabel{ch:introduction}{{1}{1}{Introduction}{chapter.1}{}}
\@setckpt{chap/introduction}{
\setcounter{page}{3}
\setcounter{equation}{0}
\setcounter{enumi}{0}
\setcounter{enumii}{0}
\setcounter{enumiii}{0}
\setcounter{enumiv}{0}
\setcounter{footnote}{0}
\setcounter{mpfootnote}{0}
\setcounter{part}{0}
\setcounter{chapter}{1}
\setcounter{section}{0}
\setcounter{subsection}{0}
\setcounter{subsubsection}{0}
\setcounter{paragraph}{0}
\setcounter{subparagraph}{0}
\setcounter{figure}{0}
\setcounter{table}{0}
\setcounter{parentequation}{0}
\setcounter{tcbbreakpart}{0}
\setcounter{tcblayer}{0}
\setcounter{tcolorbox@number}{0}
\setcounter{FancyVerbLine}{0}
\setcounter{linenumber}{1}
\setcounter{LN@truepage}{10}
\setcounter{FV@TrueTabGroupLevel}{0}
\setcounter{FV@TrueTabCounter}{0}
\setcounter{FV@HighlightLinesStart}{0}
\setcounter{FV@HighlightLinesStop}{0}
\setcounter{FancyVerbLineBreakLast}{0}
\setcounter{FV@BreakBufferDepth}{0}
\setcounter{float@type}{16}
\setcounter{minted@FancyVerbLineTemp}{0}
\setcounter{minted@pygmentizecounter}{0}
\setcounter{listing}{0}
\setcounter{tcblisting}{0}
\setcounter{caption@flags}{0}
\setcounter{continuedfloat}{0}
\setcounter{subfigure}{0}
\setcounter{subtable}{0}
\setcounter{section@level}{0}
\setcounter{Item}{0}
\setcounter{Hfootnote}{0}
\setcounter{bookmark@seq@number}{1}
\setcounter{AlgoLine}{0}
\setcounter{algocfline}{0}
\setcounter{algocfproc}{0}
\setcounter{algocf}{0}
\setcounter{lofdepth}{1}
\setcounter{lotdepth}{1}
\setcounter{svg@param@lastpage}{0}
\setcounter{svg@param@currpage}{-1}
\setcounter{su@anzahl}{0}
\setcounter{LT@tables}{0}
\setcounter{LT@chunks}{0}
\setcounter{@pps}{0}
\setcounter{@ppsavesec}{0}
\setcounter{@ppsaveapp}{0}
\setcounter{tabx@nest}{0}
\setcounter{listtotal}{0}
\setcounter{listcount}{0}
\setcounter{liststart}{0}
\setcounter{liststop}{0}
\setcounter{citecount}{0}
\setcounter{citetotal}{0}
\setcounter{multicitecount}{0}
\setcounter{multicitetotal}{0}
\setcounter{instcount}{1}
\setcounter{maxnames}{3}
\setcounter{minnames}{3}
\setcounter{maxitems}{3}
\setcounter{minitems}{1}
\setcounter{citecounter}{0}
\setcounter{maxcitecounter}{0}
\setcounter{savedcitecounter}{0}
\setcounter{uniquelist}{0}
\setcounter{uniquename}{0}
\setcounter{refsection}{0}
\setcounter{refsegment}{0}
\setcounter{maxextratitle}{0}
\setcounter{maxextratitleyear}{0}
\setcounter{maxextraname}{0}
\setcounter{maxextradate}{0}
\setcounter{maxextraalpha}{0}
\setcounter{abbrvpenalty}{50}
\setcounter{highnamepenalty}{50}
\setcounter{lownamepenalty}{25}
\setcounter{maxparens}{3}
\setcounter{parenlevel}{0}
\setcounter{blx@maxsection}{0}
\setcounter{mincomprange}{10}
\setcounter{maxcomprange}{100000}
\setcounter{mincompwidth}{1}
\setcounter{afterword}{0}
\setcounter{savedafterword}{0}
\setcounter{annotator}{0}
\setcounter{savedannotator}{0}
\setcounter{author}{0}
\setcounter{savedauthor}{0}
\setcounter{bookauthor}{0}
\setcounter{savedbookauthor}{0}
\setcounter{commentator}{0}
\setcounter{savedcommentator}{0}
\setcounter{editor}{0}
\setcounter{savededitor}{0}
\setcounter{editora}{0}
\setcounter{savededitora}{0}
\setcounter{editorb}{0}
\setcounter{savededitorb}{0}
\setcounter{editorc}{0}
\setcounter{savededitorc}{0}
\setcounter{foreword}{0}
\setcounter{savedforeword}{0}
\setcounter{holder}{0}
\setcounter{savedholder}{0}
\setcounter{introduction}{0}
\setcounter{savedintroduction}{0}
\setcounter{namea}{0}
\setcounter{savednamea}{0}
\setcounter{nameb}{0}
\setcounter{savednameb}{0}
\setcounter{namec}{0}
\setcounter{savednamec}{0}
\setcounter{translator}{0}
\setcounter{savedtranslator}{0}
\setcounter{shortauthor}{0}
\setcounter{savedshortauthor}{0}
\setcounter{shorteditor}{0}
\setcounter{savedshorteditor}{0}
\setcounter{labelname}{0}
\setcounter{savedlabelname}{0}
\setcounter{institution}{0}
\setcounter{savedinstitution}{0}
\setcounter{lista}{0}
\setcounter{savedlista}{0}
\setcounter{listb}{0}
\setcounter{savedlistb}{0}
\setcounter{listc}{0}
\setcounter{savedlistc}{0}
\setcounter{listd}{0}
\setcounter{savedlistd}{0}
\setcounter{liste}{0}
\setcounter{savedliste}{0}
\setcounter{listf}{0}
\setcounter{savedlistf}{0}
\setcounter{location}{0}
\setcounter{savedlocation}{0}
\setcounter{organization}{0}
\setcounter{savedorganization}{0}
\setcounter{origlocation}{0}
\setcounter{savedoriglocation}{0}
\setcounter{origpublisher}{0}
\setcounter{savedorigpublisher}{0}
\setcounter{publisher}{0}
\setcounter{savedpublisher}{0}
\setcounter{language}{0}
\setcounter{savedlanguage}{0}
\setcounter{origlanguage}{0}
\setcounter{savedoriglanguage}{0}
\setcounter{pageref}{0}
\setcounter{savedpageref}{0}
\setcounter{textcitecount}{0}
\setcounter{textcitetotal}{0}
\setcounter{textcitemaxnames}{0}
\setcounter{biburlbigbreakpenalty}{100}
\setcounter{biburlbreakpenalty}{200}
\setcounter{biburlnumpenalty}{0}
\setcounter{biburlucpenalty}{0}
\setcounter{biburllcpenalty}{0}
\setcounter{smartand}{1}
\setcounter{bbx:relatedcount}{0}
\setcounter{bbx:relatedtotal}{0}
\setcounter{cbx@tempcnta}{0}
\setcounter{cbx@tempcntb}{1}
\setcounter{cbx@tempcntc}{0}
\setcounter{cbx@tempcntd}{-1}
\setcounter{tcb@cnt@codeblock}{0}
}

View File

@ -13,8 +13,6 @@ With modern standards like multicore processors, peripheral extendability, great
In this thesis, support for the \textquote{Advanced Programmable Interrupt Controller}, a modern, multiprocessing capable and widely used interrupt controller architecture, introduced by Intel for the x86 \textquote{i486} processor, will be implemented into hhuOS, \textquote{A small operating system for learning purposes}~\autocite{hhuos}.
This support will cover a complete replacement of the older Programmable 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.
The following chapter explains important background concepts, \autoref{ch:interrupthandling} describes how to use the APIC to handle local and external interrupts in singlecore and multicore systems based on the \textquote{IA-32 Architecture Software Developers Manual}~\autocite{ia32}, in \autoref{ch:implementation} the implementation and integration into hhuOS are explained, \autoref{ch:verification} deals with the testing process of the developed software on emulated and real hardware, and \autoref{ch:conclusion} draws conclusions regarding the previous implementation and future improvements.
\cleardoublepage

View File

@ -1,284 +0,0 @@
\relax
\providecommand{\transparent@use}[1]{}
\providecommand\hyper@newdestlabel[2]{}
\@writefile{listings}{\addvspace {10pt}}
\@writefile{toc}{\contentsline {chapter}{\numberline {A}Listings}{43}{appendix.1.A}\protected@file@percent }
\@writefile{lof}{\addvspace {10\p@ }}
\@writefile{lot}{\addvspace {10\p@ }}
\@writefile{loa}{\addvspace {10\p@ }}
\newlabel{ch:listings}{{A}{43}{Listings}{appendix.1.A}{}}
\@writefile{toc}{\contentsline {section}{\numberline {A.1}Integration into HhuOS}{44}{section.1.A.1}\protected@file@percent }
\newlabel{sec:apxhhuos}{{A.1}{44}{Integration into HhuOS}{section.1.A.1}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {A.1.1}Interrupt Handling in HhuOS}{44}{subsection.1.A.1.1}\protected@file@percent }
\newlabel{subsec:apxcurrenthhuos}{{A.1.1}{44}{Interrupt Handling in HhuOS}{subsection.1.A.1.1}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.1\hskip 1em\relax \texttt {The InterruptHandler Interface (InterruptHandler.h)~\blx@tocontentsinit {0}\autocite {hhuos}}}{44}{tcb@cnt@codeblock.1.A.1}\protected@file@percent }
\@writefile{listings}{\contentsline {tcolorbox}{A.2\hskip 1em\relax \texttt {Assigning an Interrupt Handler (InterruptDispatcher.cpp)~\blx@tocontentsinit {0}\autocite {hhuos}}}{44}{tcb@cnt@codeblock.1.A.2}\protected@file@percent }
\@writefile{listings}{\contentsline {tcolorbox}{A.3\hskip 1em\relax \texttt {Triggering an Interrupt Handler (InterruptDispatcher.cpp)~\blx@tocontentsinit {0}\autocite {hhuos}}}{44}{tcb@cnt@codeblock.1.A.3}\protected@file@percent }
\@writefile{listings}{\contentsline {tcolorbox}{A.4\hskip 1em\relax \texttt {The PIT Interrupt Handler (Pit.cpp)~\blx@tocontentsinit {0}\autocite {hhuos}}}{44}{tcb@cnt@codeblock.1.A.4}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {A.1.2}Necessary Modifications to HhuOS}{45}{subsection.1.A.1.2}\protected@file@percent }
\newlabel{subsec:hhuosintegration}{{A.1.2}{45}{Necessary Modifications to HhuOS}{subsection.1.A.1.2}{}}
\newlabel{lst:interruptserviceafter}{{A.5}{45}{Necessary Modifications to HhuOS}{tcb@cnt@codeblock.1.A.5}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.5\hskip 1em\relax \texttt {Using the Correct Interrupt Controller (InterruptService.cpp)}}{45}{tcb@cnt@codeblock.1.A.5}\protected@file@percent }
\newlabel{lst:pithandlerafter}{{A.6}{45}{Necessary Modifications to HhuOS}{tcb@cnt@codeblock.1.A.6}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.6\hskip 1em\relax \texttt {Disabling PIT Preemption (Pit.cpp)}}{45}{tcb@cnt@codeblock.1.A.6}\protected@file@percent }
\newlabel{lst:systemafter}{{A.7}{45}{Necessary Modifications to HhuOS}{tcb@cnt@codeblock.1.A.7}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.7\hskip 1em\relax \texttt {Enabling the APIC System (System.cpp)}}{45}{tcb@cnt@codeblock.1.A.7}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {A.1.3}Public Interface of the APIC Subsystem}{46}{subsection.1.A.1.3}\protected@file@percent }
\newlabel{subsec:hhuospublicinterface}{{A.1.3}{46}{Public Interface of the APIC Subsystem}{subsection.1.A.1.3}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.8\hskip 1em\relax \texttt {The APIC Public Interface (Apic.h)}}{46}{tcb@cnt@codeblock.1.A.8}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {A.2}Local APIC}{47}{section.1.A.2}\protected@file@percent }
\newlabel{sec:apxlocalapic}{{A.2}{47}{Local APIC}{section.1.A.2}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {A.2.1}Accessing Local APIC Registers in xApic Mode}{47}{subsection.1.A.2.1}\protected@file@percent }
\newlabel{subsec:apxxapicregacc}{{A.2.1}{47}{Accessing Local APIC Registers in xApic Mode}{subsection.1.A.2.1}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.9\hskip 1em\relax \texttt {Allocating the Local APIC's MMIO Region (LocalApic.cpp)}}{47}{tcb@cnt@codeblock.1.A.9}\protected@file@percent }
\newlabel{lst:lapicmmiowrite}{{A.10}{47}{Accessing Local APIC Registers in xApic Mode}{tcb@cnt@codeblock.1.A.10}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.10\hskip 1em\relax \texttt {Writing a Local APIC MMIO Register (LocalApic.cpp)}}{47}{tcb@cnt@codeblock.1.A.10}\protected@file@percent }
\newlabel{lst:msrentry}{{A.11}{47}{Accessing Local APIC Registers in xApic Mode}{tcb@cnt@codeblock.1.A.11}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.11\hskip 1em\relax \texttt {The MSREntry Structure (LocalApicRegisters.h)}}{47}{tcb@cnt@codeblock.1.A.11}\protected@file@percent }
\newlabel{lst:svrentry}{{A.12}{47}{Accessing Local APIC Registers in xApic Mode}{tcb@cnt@codeblock.1.A.12}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.12\hskip 1em\relax \texttt {The SVREntry Structure (LocalApicRegisters.h)}}{47}{tcb@cnt@codeblock.1.A.12}\protected@file@percent }
\newlabel{lst:lvtentry}{{A.13}{48}{Accessing Local APIC Registers in xApic Mode}{tcb@cnt@codeblock.1.A.13}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.13\hskip 1em\relax \texttt {The LVTEntry Structure (LocalApicRegisters.h)}}{48}{tcb@cnt@codeblock.1.A.13}\protected@file@percent }
\newlabel{lst:icrentry}{{A.14}{48}{Accessing Local APIC Registers in xApic Mode}{tcb@cnt@codeblock.1.A.14}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.14\hskip 1em\relax \texttt {The ICREntry Structure (LocalApicRegisters.h)}}{48}{tcb@cnt@codeblock.1.A.14}\protected@file@percent }
\@writefile{listings}{\contentsline {tcolorbox}{A.15\hskip 1em\relax \texttt {Writing the IA32\textunderscore {}APIC\textunderscore {}BASE MSR (LocalApic.cpp)}}{48}{tcb@cnt@codeblock.1.A.15}\protected@file@percent }
\@writefile{listings}{\contentsline {tcolorbox}{A.16\hskip 1em\relax \texttt {Writing the SVR (LocalApic.cpp)}}{48}{tcb@cnt@codeblock.1.A.16}\protected@file@percent }
\@writefile{listings}{\contentsline {tcolorbox}{A.17\hskip 1em\relax \texttt {Writing the LVT (LocalApic.cpp)}}{48}{tcb@cnt@codeblock.1.A.17}\protected@file@percent }
\@writefile{listings}{\contentsline {tcolorbox}{A.18\hskip 1em\relax \texttt {Writing the ICR (LocalApic.cpp)}}{48}{tcb@cnt@codeblock.1.A.18}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {A.2.2}Disabling PIC Mode}{49}{subsection.1.A.2.2}\protected@file@percent }
\newlabel{subsec:apxdisablepic}{{A.2.2}{49}{Disabling PIC Mode}{subsection.1.A.2.2}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.19\hskip 1em\relax \texttt {Disabling PIC Mode (LocalApic.cpp)}}{49}{tcb@cnt@codeblock.1.A.19}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {A.2.3}Initializing the LVT}{49}{subsection.1.A.2.3}\protected@file@percent }
\newlabel{subsec:apxlvtinit}{{A.2.3}{49}{Initializing the LVT}{subsection.1.A.2.3}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.20\hskip 1em\relax \texttt {Configuring the LINT0 Local Interrupt (LocalApic.cpp)}}{49}{tcb@cnt@codeblock.1.A.20}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {A.2.4}Handling the Spurious Interrupt}{49}{subsection.1.A.2.4}\protected@file@percent }
\newlabel{subsec:apxsvr}{{A.2.4}{49}{Handling the Spurious Interrupt}{subsection.1.A.2.4}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.21\hskip 1em\relax \texttt {Setting the Spurious Interrupt Vector (LocalApic.cpp)}}{49}{tcb@cnt@codeblock.1.A.21}\protected@file@percent }
\@writefile{listings}{\contentsline {tcolorbox}{A.22\hskip 1em\relax \texttt {Checking for Spurious Interrupts (InterruptDispatcher.cpp)}}{49}{tcb@cnt@codeblock.1.A.22}\protected@file@percent }
\@writefile{listings}{\contentsline {tcolorbox}{A.23\hskip 1em\relax \texttt {Ignoring Spurious Interrupts (InterruptDispatcher.cpp)}}{50}{tcb@cnt@codeblock.1.A.23}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {A.2.5}Using the APIC Timer}{50}{subsection.1.A.2.5}\protected@file@percent }
\newlabel{subsec:apxapictimer}{{A.2.5}{50}{Using the APIC Timer}{subsection.1.A.2.5}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.24\hskip 1em\relax \texttt {Calibrating the APIC Timer (ApicTimer.cpp)}}{50}{tcb@cnt@codeblock.1.A.24}\protected@file@percent }
\@writefile{listings}{\contentsline {tcolorbox}{A.25\hskip 1em\relax \texttt {Microsecond Delay without Interrupts (Pit.cpp)}}{50}{tcb@cnt@codeblock.1.A.25}\protected@file@percent }
\@writefile{listings}{\contentsline {tcolorbox}{A.26\hskip 1em\relax \texttt {Handling the APIC Timer Interrupt (ApicTimer.cpp)}}{51}{tcb@cnt@codeblock.1.A.26}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {A.2.6}Handling Local APIC Errors}{51}{subsection.1.A.2.6}\protected@file@percent }
\newlabel{subsec:apxhandlingerror}{{A.2.6}{51}{Handling Local APIC Errors}{subsection.1.A.2.6}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.27\hskip 1em\relax \texttt {The Local APIC Error Interrupt Handler (ApicErrorHandler.cpp)}}{51}{tcb@cnt@codeblock.1.A.27}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {A.3}I/O APIC}{52}{section.1.A.3}\protected@file@percent }
\newlabel{sec:apxioapic}{{A.3}{52}{I/O APIC}{section.1.A.3}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {A.3.1}Accessing I/O APIC Registers}{52}{subsection.1.A.3.1}\protected@file@percent }
\newlabel{subsec:iolistings}{{A.3.1}{52}{Accessing I/O APIC Registers}{subsection.1.A.3.1}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.28\hskip 1em\relax \texttt {Writing an I/O APIC MMIO Register (IoApic.h)}}{52}{tcb@cnt@codeblock.1.A.28}\protected@file@percent }
\@writefile{listings}{\contentsline {tcolorbox}{A.29\hskip 1em\relax \texttt {Writing an I/O APIC Indirect Register (IoApic.cpp)}}{52}{tcb@cnt@codeblock.1.A.29}\protected@file@percent }
\newlabel{lst:redtblentry}{{A.30}{52}{Accessing I/O APIC Registers}{tcb@cnt@codeblock.1.A.30}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.30\hskip 1em\relax \texttt {The REDTBLEntry Structure (IoApicRegisters.h)}}{52}{tcb@cnt@codeblock.1.A.30}\protected@file@percent }
\newlabel{lst:writeredtbl}{{A.31}{52}{Accessing I/O APIC Registers}{tcb@cnt@codeblock.1.A.31}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.31\hskip 1em\relax \texttt {Writing the REDTBL (IoApic.cpp)}}{52}{tcb@cnt@codeblock.1.A.31}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {A.3.2}Interrupt Overrides}{52}{subsection.1.A.3.2}\protected@file@percent }
\newlabel{subsec:apxirqoverrides}{{A.3.2}{52}{Interrupt Overrides}{subsection.1.A.3.2}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.32\hskip 1em\relax \texttt {The External Interrupt Override Structure (IoApic.h)}}{53}{tcb@cnt@codeblock.1.A.32}\protected@file@percent }
\@writefile{listings}{\contentsline {tcolorbox}{A.33\hskip 1em\relax \texttt {Initializing the REDTBL (IoApic.cpp)}}{53}{tcb@cnt@codeblock.1.A.33}\protected@file@percent }
\@writefile{listings}{\contentsline {tcolorbox}{A.34\hskip 1em\relax \texttt {Unmasking an IRQ (Apic.cpp)}}{53}{tcb@cnt@codeblock.1.A.34}\protected@file@percent }
\@writefile{listings}{\contentsline {tcolorbox}{A.35\hskip 1em\relax \texttt {Unmasking an IRQ Internally (IoApic.cpp)}}{54}{tcb@cnt@codeblock.1.A.35}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {A.4}Symmetric Multiprocessing}{55}{section.1.A.4}\protected@file@percent }
\newlabel{sec:apxsymmetric}{{A.4}{55}{Symmetric Multiprocessing}{section.1.A.4}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {A.4.1}Issuing Inter-Processor Interrupts}{55}{subsection.1.A.4.1}\protected@file@percent }
\newlabel{subsec:apxipis}{{A.4.1}{55}{Issuing Inter-Processor Interrupts}{subsection.1.A.4.1}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.36\hskip 1em\relax \texttt {Issuing an INIT IPI (LocalApic.cpp)}}{55}{tcb@cnt@codeblock.1.A.36}\protected@file@percent }
\@writefile{listings}{\contentsline {tcolorbox}{A.37\hskip 1em\relax \texttt {Issuing a SIPI (LocalApic.cpp)}}{55}{tcb@cnt@codeblock.1.A.37}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {A.4.2}Preparing Symmetric Multiprocessing Startup}{55}{subsection.1.A.4.2}\protected@file@percent }
\newlabel{subsec:apxpreparesmp}{{A.4.2}{55}{Preparing Symmetric Multiprocessing Startup}{subsection.1.A.4.2}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.38\hskip 1em\relax \texttt {Preparing the Boot Routine's Variables (ApicSmp.cpp)}}{55}{tcb@cnt@codeblock.1.A.38}\protected@file@percent }
\@writefile{listings}{\contentsline {tcolorbox}{A.39\hskip 1em\relax \texttt {Relocating the Boot Routine (ApicSmp.cpp)}}{56}{tcb@cnt@codeblock.1.A.39}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {A.4.3}Universal Startup Algorithm}{56}{subsection.1.A.4.3}\protected@file@percent }
\newlabel{subsec:apxmpusa}{{A.4.3}{56}{Universal Startup Algorithm}{subsection.1.A.4.3}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.40\hskip 1em\relax \texttt {The Universal Startup Algorithm (ApicSmp.cpp)}}{56}{tcb@cnt@codeblock.1.A.40}\protected@file@percent }
\@writefile{listings}{\contentsline {tcolorbox}{A.41\hskip 1em\relax \texttt {Signaling AP Boot Completion (smp\textunderscore {}entry.cpp)}}{56}{tcb@cnt@codeblock.1.A.41}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {A.4.4}Application Processor Boot Routine}{57}{subsection.1.A.4.4}\protected@file@percent }
\newlabel{subsec:apxapboot}{{A.4.4}{57}{Application Processor Boot Routine}{subsection.1.A.4.4}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.42\hskip 1em\relax \texttt {Preparing the Switch to Protected Mode (smp\textunderscore {}boot.asm)}}{57}{tcb@cnt@codeblock.1.A.42}\protected@file@percent }
\@writefile{listings}{\contentsline {tcolorbox}{A.43\hskip 1em\relax \texttt {Switching from Real Mode to Protected Mode (smp\textunderscore {}boot.asm)}}{57}{tcb@cnt@codeblock.1.A.43}\protected@file@percent }
\@writefile{listings}{\contentsline {tcolorbox}{A.44\hskip 1em\relax \texttt {Reusing Values from the BSP (smp\textunderscore {}boot.asm)}}{57}{tcb@cnt@codeblock.1.A.44}\protected@file@percent }
\@writefile{listings}{\contentsline {tcolorbox}{A.45\hskip 1em\relax \texttt {Calling the Entry Function (smp\textunderscore {}boot.asm)}}{58}{tcb@cnt@codeblock.1.A.45}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {A.4.5}Application Processor Post-Boot Routine}{58}{subsection.1.A.4.5}\protected@file@percent }
\newlabel{subsec:apxappostboot}{{A.4.5}{58}{Application Processor Post-Boot Routine}{subsection.1.A.4.5}{}}
\@writefile{listings}{\contentsline {tcolorbox}{A.46\hskip 1em\relax \texttt {Initializing the Core's Local APIC (LocalApic.cpp)}}{58}{tcb@cnt@codeblock.1.A.46}\protected@file@percent }
\@writefile{listings}{\contentsline {tcolorbox}{A.47\hskip 1em\relax \texttt {Synchronizing the Arbitration IDs (LocalApic.cpp)}}{58}{tcb@cnt@codeblock.1.A.47}\protected@file@percent }
\@setckpt{chap/listings}{
\setcounter{page}{59}
\setcounter{equation}{0}
\setcounter{enumi}{4}
\setcounter{enumii}{0}
\setcounter{enumiii}{0}
\setcounter{enumiv}{0}
\setcounter{footnote}{2}
\setcounter{mpfootnote}{0}
\setcounter{part}{0}
\setcounter{chapter}{1}
\setcounter{section}{4}
\setcounter{subsection}{5}
\setcounter{subsubsection}{0}
\setcounter{paragraph}{0}
\setcounter{subparagraph}{0}
\setcounter{figure}{0}
\setcounter{table}{0}
\setcounter{parentequation}{0}
\setcounter{tcbbreakpart}{1}
\setcounter{tcblayer}{0}
\setcounter{tcolorbox@number}{184}
\setcounter{FancyVerbLine}{12}
\setcounter{linenumber}{1}
\setcounter{LN@truepage}{66}
\setcounter{FV@TrueTabGroupLevel}{0}
\setcounter{FV@TrueTabCounter}{0}
\setcounter{FV@HighlightLinesStart}{0}
\setcounter{FV@HighlightLinesStop}{0}
\setcounter{FancyVerbLineBreakLast}{1}
\setcounter{FV@BreakBufferDepth}{0}
\setcounter{float@type}{16}
\setcounter{minted@FancyVerbLineTemp}{0}
\setcounter{minted@pygmentizecounter}{47}
\setcounter{listing}{0}
\setcounter{tcblisting}{0}
\setcounter{caption@flags}{6}
\setcounter{continuedfloat}{0}
\setcounter{subfigure}{0}
\setcounter{subtable}{0}
\setcounter{section@level}{2}
\setcounter{Item}{50}
\setcounter{Hfootnote}{45}
\setcounter{bookmark@seq@number}{72}
\setcounter{AlgoLine}{0}
\setcounter{algocfline}{0}
\setcounter{algocfproc}{0}
\setcounter{algocf}{0}
\setcounter{lofdepth}{1}
\setcounter{lotdepth}{1}
\setcounter{svg@param@lastpage}{0}
\setcounter{svg@param@currpage}{-1}
\setcounter{su@anzahl}{0}
\setcounter{LT@tables}{0}
\setcounter{LT@chunks}{0}
\setcounter{@pps}{1}
\setcounter{@ppsavesec}{5}
\setcounter{@ppsaveapp}{0}
\setcounter{tabx@nest}{0}
\setcounter{listtotal}{0}
\setcounter{listcount}{0}
\setcounter{liststart}{0}
\setcounter{liststop}{0}
\setcounter{citecount}{0}
\setcounter{citetotal}{0}
\setcounter{multicitecount}{0}
\setcounter{multicitetotal}{0}
\setcounter{instcount}{96}
\setcounter{maxnames}{3}
\setcounter{minnames}{3}
\setcounter{maxitems}{3}
\setcounter{minitems}{1}
\setcounter{citecounter}{0}
\setcounter{maxcitecounter}{0}
\setcounter{savedcitecounter}{0}
\setcounter{uniquelist}{0}
\setcounter{uniquename}{0}
\setcounter{refsection}{0}
\setcounter{refsegment}{0}
\setcounter{maxextratitle}{0}
\setcounter{maxextratitleyear}{0}
\setcounter{maxextraname}{0}
\setcounter{maxextradate}{0}
\setcounter{maxextraalpha}{0}
\setcounter{abbrvpenalty}{50}
\setcounter{highnamepenalty}{50}
\setcounter{lownamepenalty}{25}
\setcounter{maxparens}{3}
\setcounter{parenlevel}{0}
\setcounter{blx@maxsection}{0}
\setcounter{mincomprange}{10}
\setcounter{maxcomprange}{100000}
\setcounter{mincompwidth}{1}
\setcounter{afterword}{0}
\setcounter{savedafterword}{0}
\setcounter{annotator}{0}
\setcounter{savedannotator}{0}
\setcounter{author}{0}
\setcounter{savedauthor}{0}
\setcounter{bookauthor}{0}
\setcounter{savedbookauthor}{0}
\setcounter{commentator}{0}
\setcounter{savedcommentator}{0}
\setcounter{editor}{0}
\setcounter{savededitor}{0}
\setcounter{editora}{0}
\setcounter{savededitora}{0}
\setcounter{editorb}{0}
\setcounter{savededitorb}{0}
\setcounter{editorc}{0}
\setcounter{savededitorc}{0}
\setcounter{foreword}{0}
\setcounter{savedforeword}{0}
\setcounter{holder}{0}
\setcounter{savedholder}{0}
\setcounter{introduction}{0}
\setcounter{savedintroduction}{0}
\setcounter{namea}{0}
\setcounter{savednamea}{0}
\setcounter{nameb}{0}
\setcounter{savednameb}{0}
\setcounter{namec}{0}
\setcounter{savednamec}{0}
\setcounter{translator}{0}
\setcounter{savedtranslator}{0}
\setcounter{shortauthor}{0}
\setcounter{savedshortauthor}{0}
\setcounter{shorteditor}{0}
\setcounter{savedshorteditor}{0}
\setcounter{labelname}{0}
\setcounter{savedlabelname}{0}
\setcounter{institution}{0}
\setcounter{savedinstitution}{0}
\setcounter{lista}{0}
\setcounter{savedlista}{0}
\setcounter{listb}{0}
\setcounter{savedlistb}{0}
\setcounter{listc}{0}
\setcounter{savedlistc}{0}
\setcounter{listd}{0}
\setcounter{savedlistd}{0}
\setcounter{liste}{0}
\setcounter{savedliste}{0}
\setcounter{listf}{0}
\setcounter{savedlistf}{0}
\setcounter{location}{0}
\setcounter{savedlocation}{0}
\setcounter{organization}{0}
\setcounter{savedorganization}{0}
\setcounter{origlocation}{0}
\setcounter{savedoriglocation}{0}
\setcounter{origpublisher}{0}
\setcounter{savedorigpublisher}{0}
\setcounter{publisher}{0}
\setcounter{savedpublisher}{0}
\setcounter{language}{0}
\setcounter{savedlanguage}{0}
\setcounter{origlanguage}{0}
\setcounter{savedoriglanguage}{0}
\setcounter{pageref}{0}
\setcounter{savedpageref}{0}
\setcounter{textcitecount}{0}
\setcounter{textcitetotal}{0}
\setcounter{textcitemaxnames}{0}
\setcounter{biburlbigbreakpenalty}{100}
\setcounter{biburlbreakpenalty}{200}
\setcounter{biburlnumpenalty}{0}
\setcounter{biburlucpenalty}{0}
\setcounter{biburllcpenalty}{0}
\setcounter{smartand}{1}
\setcounter{bbx:relatedcount}{0}
\setcounter{bbx:relatedtotal}{0}
\setcounter{cbx@tempcnta}{0}
\setcounter{cbx@tempcntb}{20}
\setcounter{cbx@tempcntc}{0}
\setcounter{cbx@tempcntd}{-1}
\setcounter{tcb@cnt@codeblock}{47}
}

View File

@ -1,378 +0,0 @@
\chapter{Listings}
\label{ch:listings}
This chapter contains concrete implementation examples for concepts mentioned in \autoref{ch:implementation}, demonstrated on the example of hhuOS\@.
The code is simplified and not necessarily identical to the actual implementation, to allow for a self-contained demonstration.
Names and namespaces were adjusted especially.
\clearpage
\section{Integration into HhuOS}
\label{sec:apxhhuos}
\subsection{Interrupt Handling in HhuOS}
\label{subsec:apxcurrenthhuos}
Devices that provide interrupts implement the \code{InterruptHandler} interface:
\begin{codeblock}{The InterruptHandler Interface (InterruptHandler.h)~\autocite{hhuos}}{C++}
\cppfile{code/interrupthandler_def.cpp}
\end{codeblock}
These interrupt handlers have to be registered to the appropriate interrupt vector:
\begin{codeblock}{Assigning an Interrupt Handler (InterruptDispatcher.cpp)~\autocite{hhuos}}{C++}
\cppfile{code/interruptdispatcher_assign.cpp}
\end{codeblock}
Multiple interrupt handlers can be registered to the same interrupt vector.
For every interrupt that arrives at a CPU, the first-stage interrupt handler (registered in the IDT for every vector) is called, which in turn calls the device-specific handlers:
\begin{codeblock}{Triggering an Interrupt Handler (InterruptDispatcher.cpp)~\autocite{hhuos}}{C++}
\cppfile{code/interruptdispatcher_dispatch.cpp}
\end{codeblock}
The PIT interrupt handler manages the system time and the scheduler:
\begin{codeblock}{The PIT Interrupt Handler (Pit.cpp)~\autocite{hhuos}}{C++}
\cppfile{code/pit_trigger.cpp}
\end{codeblock}
\clearpage
\subsection{Necessary Modifications to HhuOS}
\label{subsec:hhuosintegration}
To integrate the APIC implementation into hhuOS, some preexisting components of its interrupt infrastructure (see \autoref{sec:apxhhuos}) have to be modified:
\begin{enumerate}
\item The \code{InterruptService} has to forward calls 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}).
\item The existing devices using interrupts need to use the new \code{InterruptVector} and \code{InterruptRequest} enums.
\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]{Disabling PIT Preemption (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}
\subsection{Public Interface of the APIC Subsystem}
\label{subsec:hhuospublicinterface}
To interact with the APIC subsystem from the \textquote{outside}, the \code{Apic} class is used, which exposes the necessary functionality:
\begin{codeblock}{The APIC Public Interface (Apic.h)}{C++}
\cppfile{code/apic_def.cpp}
\end{codeblock}
Enabling the APIC subsystem is done by the \code{enable} function (see \autoref{fig:apicenable}).
\clearpage
\section{Local APIC}
\label{sec:apxlocalapic}
\subsection{Accessing Local APIC Registers in xApic Mode}
\label{subsec:apxxapicregacc}
The xApic register access requires a single page of strong uncachable memory, but since this requires setting attributes in the \textquote{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, which maps a physical address to the kernel heap, with hhuOS' \textquote{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}
\subsection{Disabling PIC Mode}
\label{subsec:apxdisablepic}
Setting the IMCR\footnote{
Writing the IMCR is detailed in the \textquote{MultiProcessor Specification}~\autocite[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}
\subsection{Initializing the LVT}
\label{subsec: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.
\subsection{Handling the Spurious Interrupt}
\label{subsec: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' \textquote{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}
\subsection{Using the APIC Timer}
\label{subsec: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 \textquote{Interrupt on Terminal Count} on channel zero and polls the channel's output status~\autocite{pit}:
\begin{codeblock}{Microsecond Delay without Interrupts (Pit.cpp)}{C++}
\cppfile{code/pit_early_delay.cpp}
\end{codeblock}
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\@.
The handler belonging to the BSP's APIC timer also triggers the scheduler preemption (instead of the PIT):
\begin{codeblock}{Handling the APIC Timer Interrupt (ApicTimer.cpp)}{C++}
\cppfile{code/apictimer_trigger.cpp}
\end{codeblock}
\subsection{Handling Local APIC Errors}
\label{subsec: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{I/O APIC}
\label{sec:apxioapic}
\subsection{Accessing I/O APIC Registers}
\label{subsec: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 \textquote{Index} and \textquote{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}
\subsection{Interrupt Overrides}
\label{subsec: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, the overrides 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 operation, the overrides 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 public \code{Apic::allow} function accepts an \code{InterruptRequest} as an argument (that allows addressing the interrupt by name), while the internal \code{IoApic::allow} function only accepts a \code{GlobalSystemInterrupt} as argument:
\begin{codeblock}{Unmasking an IRQ Internally (IoApic.cpp)}{C++}
\cppfile{code/ioapic_allow.cpp}
\end{codeblock}
The internal \code{IoApic::allow} function is hidden (\code{private}) from the OS, and gets only called by the exposed \code{Apic::allow} function.
This prevents accidentally setting the wrong REDTBL entry by not taking possible interrupt overrides into account.
The same principle is applied to the other operations concerning GSIs.
\clearpage
\section{Symmetric Multiprocessing}
\label{sec:apxsymmetric}
An overview of the complete SMP startup process can be found in \autoref{fig:smpenable}.
\subsection{Issuing Inter-Processor Interrupts}
\label{subsec: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}
\subsection{Preparing Symmetric Multiprocessing Startup}
\label{subsec:apxpreparesmp}
Before executing the \textquote{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 do not change after enabling paging in protected mode.
To keep the required variables available to the startup code, these are located in the routines \textquote{TEXT} section and initialized during runtime.
This approach was taken from SerenityOS~\autocite[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{subsec:apxapboot}.
\subsection{Universal Startup Algorithm}
\label{subsec:apxmpusa}
The \textquote{INIT-SIPI-SIPI} sequence, or \textquote{Universal Startup Algorithm} is performed by issuing IPIs as described in \autoref{subsec:apxipis} and using the PIT as time source (see \autoref{subsec: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}
\subsection{Application Processor Boot Routine}
\label{subsec: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 \SI{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 \SI{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}{Reusing Values 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 stack. If hardware context switching is to be used, the AP additionally requires its own GDT and TSS\@:
\begin{codeblock}{Calling the Entry Function (smp\textunderscore{}boot.asm)}{nasm}
\nasmfile{code/ap_boot_protected_ap.asm}
\end{codeblock}
\subsection{Application Processor Post-Boot Routine}
\label{subsec: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 \textquote{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.
\cleardoublepage

View File

@ -1,249 +0,0 @@
\relax
\providecommand{\transparent@use}[1]{}
\providecommand\hyper@newdestlabel[2]{}
\@writefile{listings}{\addvspace {10pt}}
\@writefile{toc}{\contentsline {chapter}{\numberline {C}Tables}{63}{appendix.1.C}\protected@file@percent }
\@writefile{lof}{\addvspace {10\p@ }}
\@writefile{lot}{\addvspace {10\p@ }}
\@writefile{loa}{\addvspace {10\p@ }}
\newlabel{ch:tables}{{C}{63}{Tables}{appendix.1.C}{}}
\@writefile{toc}{\contentsline {section}{\numberline {C.1}Local APIC Registers}{64}{section.1.C.1}\protected@file@percent }
\newlabel{sec:localapicregisters}{{C.1}{64}{Local APIC Registers}{section.1.C.1}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.1}{\ignorespaces Local APIC Registers used in this Implementation~\blx@tocontentsinit {0}\autocite [sec.~3.11.4.1]{ia32}.\relax }}{64}{table.caption.5}\protected@file@percent }
\newlabel{tab:lapicregs}{{C.1}{64}{Local APIC Registers used in this Implementation~\autocite [sec.~3.11.4.1]{ia32}.\relax }{table.caption.5}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.2}{\ignorespaces Local APIC ID Register (xApic since Pentium 4)~\blx@tocontentsinit {0}\autocite [sec.~3.11.4.6]{ia32}.\relax }}{64}{table.caption.6}\protected@file@percent }
\newlabel{tab:lapicregsid}{{C.2}{64}{Local APIC ID Register (xApic since Pentium 4)~\autocite [sec.~3.11.4.6]{ia32}.\relax }{table.caption.6}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.3}{\ignorespaces Local APIC Version Register~\blx@tocontentsinit {0}\autocite [sec.~3.11.4.8]{ia32}.\relax }}{64}{table.caption.7}\protected@file@percent }
\newlabel{tab:lapicregsver}{{C.3}{64}{Local APIC Version Register~\autocite [sec.~3.11.4.8]{ia32}.\relax }{table.caption.7}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.4}{\ignorespaces Task Priority Register~\blx@tocontentsinit {0}\autocite [sec.~3.11.8.3.1]{ia32}.\relax }}{65}{table.caption.8}\protected@file@percent }
\newlabel{tab:lapicregstpr}{{C.4}{65}{Task Priority Register~\autocite [sec.~3.11.8.3.1]{ia32}.\relax }{table.caption.8}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.5}{\ignorespaces Local APIC EOI Register~\blx@tocontentsinit {0}\autocite [sec.~3.11.8.5]{ia32}.\relax }}{65}{table.caption.9}\protected@file@percent }
\newlabel{tab:lapicregseoi}{{C.5}{65}{Local APIC EOI Register~\autocite [sec.~3.11.8.5]{ia32}.\relax }{table.caption.9}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.6}{\ignorespaces Spurious Interrupt Vector Register~\blx@tocontentsinit {0}\autocite [sec.~3.11.9]{ia32}.\relax }}{65}{table.caption.10}\protected@file@percent }
\newlabel{tab:lapicregssvr}{{C.6}{65}{Spurious Interrupt Vector Register~\autocite [sec.~3.11.9]{ia32}.\relax }{table.caption.10}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.7}{\ignorespaces Error Status Register (Pentium 4)~\blx@tocontentsinit {0}\autocite [sec.~3.11.5.3]{ia32}.\relax }}{65}{table.caption.11}\protected@file@percent }
\newlabel{tab:lapicregsesr}{{C.7}{65}{Error Status Register (Pentium 4)~\autocite [sec.~3.11.5.3]{ia32}.\relax }{table.caption.11}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.8}{\ignorespaces Interrupt Command Register~\blx@tocontentsinit {0}\autocite [sec.~3.11.6.1]{ia32}.\relax }}{66}{table.caption.12}\protected@file@percent }
\newlabel{tab:lapicregsicr}{{C.8}{66}{Interrupt Command Register~\autocite [sec.~3.11.6.1]{ia32}.\relax }{table.caption.12}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.9}{\ignorespaces LVT Timer Register~\blx@tocontentsinit {0}\autocite [sec.~3.11.5.1]{ia32}.\relax }}{66}{table.caption.13}\protected@file@percent }
\newlabel{tab:lapicregslvtt}{{C.9}{66}{LVT Timer Register~\autocite [sec.~3.11.5.1]{ia32}.\relax }{table.caption.13}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.10}{\ignorespaces LVT Error Register~\blx@tocontentsinit {0}\autocite [sec.~3.11.5.1]{ia32}.\relax }}{66}{table.caption.14}\protected@file@percent }
\newlabel{tab:lapicregslvterr}{{C.10}{66}{LVT Error Register~\autocite [sec.~3.11.5.1]{ia32}.\relax }{table.caption.14}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.11}{\ignorespaces LVT LINT1 Register~\blx@tocontentsinit {0}\autocite [sec.~3.11.5.1]{ia32}.\relax }}{67}{table.caption.15}\protected@file@percent }
\newlabel{tab:lapicregslvtlint}{{C.11}{67}{LVT LINT1 Register~\autocite [sec.~3.11.5.1]{ia32}.\relax }{table.caption.15}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.12}{\ignorespaces Timer Initial Count Register~\blx@tocontentsinit {0}\autocite [sec.~3.11.5.4]{ia32}.\relax }}{67}{table.caption.16}\protected@file@percent }
\newlabel{tab:lapicregstimerinit}{{C.12}{67}{Timer Initial Count Register~\autocite [sec.~3.11.5.4]{ia32}.\relax }{table.caption.16}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.13}{\ignorespaces Timer Divide Configuration Register~\blx@tocontentsinit {0}\autocite [sec.~3.11.5.4]{ia32}.\relax }}{67}{table.caption.17}\protected@file@percent }
\newlabel{tab:lapicregstimerdiv}{{C.13}{67}{Timer Divide Configuration Register~\autocite [sec.~3.11.5.4]{ia32}.\relax }{table.caption.17}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.14}{\ignorespaces IA32\textunderscore {} APIC\textunderscore {}BASE MSR~\blx@tocontentsinit {0}\autocite [sec.~3.11.12.1]{ia32}. \relax }}{67}{table.caption.18}\protected@file@percent }
\newlabel{tab:lapicregsmsr}{{C.14}{67}{IA32\textunderscore {} APIC\textunderscore {}BASE MSR~\autocite [sec.~3.11.12.1]{ia32}. \relax }{table.caption.18}{}}
\@writefile{toc}{\contentsline {section}{\numberline {C.2}I/O APIC Registers}{68}{section.1.C.2}\protected@file@percent }
\newlabel{sec:ioapicregs}{{C.2}{68}{I/O APIC Registers}{section.1.C.2}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.15}{\ignorespaces I/O APIC Registers used in this Implementation~\blx@tocontentsinit {0}\autocite [sec.~9.5]{ich5}.\relax }}{68}{table.caption.19}\protected@file@percent }
\newlabel{tab:ioapicregs}{{C.15}{68}{I/O APIC Registers used in this Implementation~\autocite [sec.~9.5]{ich5}.\relax }{table.caption.19}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.16}{\ignorespaces I/O APIC Index Register~\blx@tocontentsinit {0}\autocite [sec.~9.5.2]{ich5}.\relax }}{68}{table.caption.20}\protected@file@percent }
\newlabel{tab:ioapicregsidx}{{C.16}{68}{I/O APIC Index Register~\autocite [sec.~9.5.2]{ich5}.\relax }{table.caption.20}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.17}{\ignorespaces I/O APIC Data Register~\blx@tocontentsinit {0}\autocite [sec.~9.5.3]{ich5}.\relax }}{68}{table.caption.21}\protected@file@percent }
\newlabel{tab:ioapicregsdat}{{C.17}{68}{I/O APIC Data Register~\autocite [sec.~9.5.3]{ich5}.\relax }{table.caption.21}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.18}{\ignorespaces I/O APIC ID Register~\blx@tocontentsinit {0}\autocite [sec.~9.5.6]{ich5}.\relax }}{68}{table.caption.22}\protected@file@percent }
\newlabel{tab:ioapicregsid}{{C.18}{68}{I/O APIC ID Register~\autocite [sec.~9.5.6]{ich5}.\relax }{table.caption.22}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.19}{\ignorespaces I/O APIC Version Register~\blx@tocontentsinit {0}\autocite [sec.~9.5.7]{ich5}.\relax }}{69}{table.caption.23}\protected@file@percent }
\newlabel{tab:ioapicregsver}{{C.19}{69}{I/O APIC Version Register~\autocite [sec.~9.5.7]{ich5}.\relax }{table.caption.23}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.20}{\ignorespaces I/O APIC REDTBL Register~\blx@tocontentsinit {0}\autocite [sec.~9.5.8]{ich5}.\relax }}{69}{table.caption.24}\protected@file@percent }
\newlabel{tab:ioapicregsredtbl}{{C.20}{69}{I/O APIC REDTBL Register~\autocite [sec.~9.5.8]{ich5}.\relax }{table.caption.24}{}}
\@writefile{toc}{\contentsline {section}{\numberline {C.3}System Description Tables}{70}{section.1.C.3}\protected@file@percent }
\newlabel{sec:sdts}{{C.3}{70}{System Description Tables}{section.1.C.3}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.21}{\ignorespaces ACPI MADT~\blx@tocontentsinit {0}\autocite [sec.~5.2.8]{acpi1}.\relax }}{70}{table.caption.25}\protected@file@percent }
\newlabel{tab:madt}{{C.21}{70}{ACPI MADT~\autocite [sec.~5.2.8]{acpi1}.\relax }{table.caption.25}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.22}{\ignorespaces MADT Processor Local APIC Structure~\blx@tocontentsinit {0}\autocite [sec.~5.2.8.1]{acpi1}.\relax }}{70}{table.caption.26}\protected@file@percent }
\newlabel{tab:madtlapic}{{C.22}{70}{MADT Processor Local APIC Structure~\autocite [sec.~5.2.8.1]{acpi1}.\relax }{table.caption.26}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.23}{\ignorespaces Local APIC Flags~\blx@tocontentsinit {0}\autocite [sec.~5.2.8.1]{acpi1}.\relax }}{70}{table.caption.27}\protected@file@percent }
\newlabel{tab:madtlapicflags}{{C.23}{70}{Local APIC Flags~\autocite [sec.~5.2.8.1]{acpi1}.\relax }{table.caption.27}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.24}{\ignorespaces MADT I/O APIC Structure~\blx@tocontentsinit {0}\autocite [sec.~5.2.8.2]{acpi1}.\relax }}{70}{table.caption.28}\protected@file@percent }
\newlabel{tab:madtioapic}{{C.24}{70}{MADT I/O APIC Structure~\autocite [sec.~5.2.8.2]{acpi1}.\relax }{table.caption.28}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.25}{\ignorespaces MADT Interrupt Source Override Structure~\blx@tocontentsinit {0}\autocite [sec.~5.2.8.3.1]{acpi1}.\relax }}{71}{table.caption.29}\protected@file@percent }
\newlabel{tab:madtirqoverride}{{C.25}{71}{MADT Interrupt Source Override Structure~\autocite [sec.~5.2.8.3.1]{acpi1}.\relax }{table.caption.29}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.26}{\ignorespaces INTI Flags~\blx@tocontentsinit {0}\autocite [sec.~5.2.8.3.1]{acpi1}.\relax }}{71}{table.caption.30}\protected@file@percent }
\newlabel{tab:madtintiflags}{{C.26}{71}{INTI Flags~\autocite [sec.~5.2.8.3.1]{acpi1}.\relax }{table.caption.30}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.27}{\ignorespaces MADT I/O APIC NMI Source~\blx@tocontentsinit {0}\autocite [sec.~5.2.8.3.2]{acpi1}.\relax }}{71}{table.caption.31}\protected@file@percent }
\newlabel{tab:madtionmi}{{C.27}{71}{MADT I/O APIC NMI Source~\autocite [sec.~5.2.8.3.2]{acpi1}.\relax }{table.caption.31}{}}
\@writefile{lot}{\contentsline {table}{\numberline {C.28}{\ignorespaces MADT Local APIC NMI Source~\blx@tocontentsinit {0}\autocite [sec.~5.2.8.3.3]{acpi1}.\relax }}{71}{table.caption.32}\protected@file@percent }
\newlabel{tab:madtlnmi}{{C.28}{71}{MADT Local APIC NMI Source~\autocite [sec.~5.2.8.3.3]{acpi1}.\relax }{table.caption.32}{}}
\@setckpt{chap/tables}{
\setcounter{page}{73}
\setcounter{equation}{0}
\setcounter{enumi}{4}
\setcounter{enumii}{0}
\setcounter{enumiii}{0}
\setcounter{enumiv}{0}
\setcounter{footnote}{0}
\setcounter{mpfootnote}{0}
\setcounter{part}{0}
\setcounter{chapter}{3}
\setcounter{section}{3}
\setcounter{subsection}{0}
\setcounter{subsubsection}{0}
\setcounter{paragraph}{0}
\setcounter{subparagraph}{0}
\setcounter{figure}{0}
\setcounter{table}{28}
\setcounter{parentequation}{0}
\setcounter{tcbbreakpart}{1}
\setcounter{tcblayer}{0}
\setcounter{tcolorbox@number}{184}
\setcounter{FancyVerbLine}{12}
\setcounter{linenumber}{1}
\setcounter{LN@truepage}{80}
\setcounter{FV@TrueTabGroupLevel}{0}
\setcounter{FV@TrueTabCounter}{0}
\setcounter{FV@HighlightLinesStart}{0}
\setcounter{FV@HighlightLinesStop}{0}
\setcounter{FancyVerbLineBreakLast}{1}
\setcounter{FV@BreakBufferDepth}{0}
\setcounter{float@type}{16}
\setcounter{minted@FancyVerbLineTemp}{0}
\setcounter{minted@pygmentizecounter}{47}
\setcounter{listing}{0}
\setcounter{tcblisting}{0}
\setcounter{caption@flags}{2}
\setcounter{continuedfloat}{0}
\setcounter{subfigure}{0}
\setcounter{subtable}{0}
\setcounter{section@level}{1}
\setcounter{Item}{50}
\setcounter{Hfootnote}{45}
\setcounter{bookmark@seq@number}{77}
\setcounter{AlgoLine}{0}
\setcounter{algocfline}{0}
\setcounter{algocfproc}{0}
\setcounter{algocf}{0}
\setcounter{lofdepth}{1}
\setcounter{lotdepth}{1}
\setcounter{svg@param@lastpage}{0}
\setcounter{svg@param@currpage}{-1}
\setcounter{su@anzahl}{0}
\setcounter{LT@tables}{0}
\setcounter{LT@chunks}{0}
\setcounter{@pps}{1}
\setcounter{@ppsavesec}{5}
\setcounter{@ppsaveapp}{0}
\setcounter{tabx@nest}{0}
\setcounter{listtotal}{0}
\setcounter{listcount}{0}
\setcounter{liststart}{0}
\setcounter{liststop}{0}
\setcounter{citecount}{0}
\setcounter{citetotal}{0}
\setcounter{multicitecount}{0}
\setcounter{multicitetotal}{0}
\setcounter{instcount}{152}
\setcounter{maxnames}{3}
\setcounter{minnames}{3}
\setcounter{maxitems}{3}
\setcounter{minitems}{1}
\setcounter{citecounter}{0}
\setcounter{maxcitecounter}{0}
\setcounter{savedcitecounter}{0}
\setcounter{uniquelist}{0}
\setcounter{uniquename}{0}
\setcounter{refsection}{0}
\setcounter{refsegment}{0}
\setcounter{maxextratitle}{0}
\setcounter{maxextratitleyear}{0}
\setcounter{maxextraname}{0}
\setcounter{maxextradate}{0}
\setcounter{maxextraalpha}{0}
\setcounter{abbrvpenalty}{50}
\setcounter{highnamepenalty}{50}
\setcounter{lownamepenalty}{25}
\setcounter{maxparens}{3}
\setcounter{parenlevel}{0}
\setcounter{blx@maxsection}{0}
\setcounter{mincomprange}{10}
\setcounter{maxcomprange}{100000}
\setcounter{mincompwidth}{1}
\setcounter{afterword}{0}
\setcounter{savedafterword}{0}
\setcounter{annotator}{0}
\setcounter{savedannotator}{0}
\setcounter{author}{0}
\setcounter{savedauthor}{0}
\setcounter{bookauthor}{0}
\setcounter{savedbookauthor}{0}
\setcounter{commentator}{0}
\setcounter{savedcommentator}{0}
\setcounter{editor}{0}
\setcounter{savededitor}{0}
\setcounter{editora}{0}
\setcounter{savededitora}{0}
\setcounter{editorb}{0}
\setcounter{savededitorb}{0}
\setcounter{editorc}{0}
\setcounter{savededitorc}{0}
\setcounter{foreword}{0}
\setcounter{savedforeword}{0}
\setcounter{holder}{0}
\setcounter{savedholder}{0}
\setcounter{introduction}{0}
\setcounter{savedintroduction}{0}
\setcounter{namea}{0}
\setcounter{savednamea}{0}
\setcounter{nameb}{0}
\setcounter{savednameb}{0}
\setcounter{namec}{0}
\setcounter{savednamec}{0}
\setcounter{translator}{0}
\setcounter{savedtranslator}{0}
\setcounter{shortauthor}{0}
\setcounter{savedshortauthor}{0}
\setcounter{shorteditor}{0}
\setcounter{savedshorteditor}{0}
\setcounter{labelname}{0}
\setcounter{savedlabelname}{0}
\setcounter{institution}{0}
\setcounter{savedinstitution}{0}
\setcounter{lista}{0}
\setcounter{savedlista}{0}
\setcounter{listb}{0}
\setcounter{savedlistb}{0}
\setcounter{listc}{0}
\setcounter{savedlistc}{0}
\setcounter{listd}{0}
\setcounter{savedlistd}{0}
\setcounter{liste}{0}
\setcounter{savedliste}{0}
\setcounter{listf}{0}
\setcounter{savedlistf}{0}
\setcounter{location}{0}
\setcounter{savedlocation}{0}
\setcounter{organization}{0}
\setcounter{savedorganization}{0}
\setcounter{origlocation}{0}
\setcounter{savedoriglocation}{0}
\setcounter{origpublisher}{0}
\setcounter{savedorigpublisher}{0}
\setcounter{publisher}{0}
\setcounter{savedpublisher}{0}
\setcounter{language}{0}
\setcounter{savedlanguage}{0}
\setcounter{origlanguage}{0}
\setcounter{savedoriglanguage}{0}
\setcounter{pageref}{0}
\setcounter{savedpageref}{0}
\setcounter{textcitecount}{0}
\setcounter{textcitetotal}{0}
\setcounter{textcitemaxnames}{0}
\setcounter{biburlbigbreakpenalty}{100}
\setcounter{biburlbreakpenalty}{200}
\setcounter{biburlnumpenalty}{0}
\setcounter{biburlucpenalty}{0}
\setcounter{biburllcpenalty}{0}
\setcounter{smartand}{1}
\setcounter{bbx:relatedcount}{0}
\setcounter{bbx:relatedtotal}{0}
\setcounter{cbx@tempcnta}{0}
\setcounter{cbx@tempcntb}{4}
\setcounter{cbx@tempcntc}{0}
\setcounter{cbx@tempcntd}{-1}
\setcounter{tcb@cnt@codeblock}{0}
}

View File

@ -1,4 +1,4 @@
\chapter{Verification}
\chapter{Testing}
\label{ch:verification}
Common techniques for testing software include component-based tests, like \textquote{unit tests}, and \textquote{end-to-end tests}, where the complete functionality of a software system with all its parts is tested.
@ -8,7 +8,7 @@ This chapter deals with the process and results of testing hhuOS with the APIC i
\clearpage
\section{Methods of Verification}
\section{Methodology}
\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{

View File

@ -1,191 +0,0 @@
\relax
\providecommand{\transparent@use}[1]{}
\providecommand\hyper@newdestlabel[2]{}
\@writefile{listings}{\addvspace {10pt}}
\@writefile{toc}{\contentsline {chapter}{\numberline {4}Verification}{33}{chapter.4}\protected@file@percent }
\@writefile{lof}{\addvspace {10\p@ }}
\@writefile{lot}{\addvspace {10\p@ }}
\@writefile{loa}{\addvspace {10\p@ }}
\newlabel{ch:verification}{{4}{33}{Verification}{chapter.4}{}}
\@writefile{toc}{\contentsline {section}{\numberline {4.1}Methods of Verification}{34}{section.4.1}\protected@file@percent }
\newlabel{sec:verificationmethods}{{4.1}{34}{Methods of Verification}{section.4.1}{}}
\@writefile{toc}{\contentsline {section}{\numberline {4.2}Results}{34}{section.4.2}\protected@file@percent }
\newlabel{sec:verificationresults}{{4.2}{34}{Results}{section.4.2}{}}
\@setckpt{chap/verification}{
\setcounter{page}{37}
\setcounter{equation}{0}
\setcounter{enumi}{9}
\setcounter{enumii}{0}
\setcounter{enumiii}{0}
\setcounter{enumiv}{0}
\setcounter{footnote}{3}
\setcounter{mpfootnote}{0}
\setcounter{part}{0}
\setcounter{chapter}{4}
\setcounter{section}{2}
\setcounter{subsection}{0}
\setcounter{subsubsection}{0}
\setcounter{paragraph}{0}
\setcounter{subparagraph}{0}
\setcounter{figure}{0}
\setcounter{table}{0}
\setcounter{parentequation}{0}
\setcounter{tcbbreakpart}{1}
\setcounter{tcblayer}{0}
\setcounter{tcolorbox@number}{59}
\setcounter{FancyVerbLine}{0}
\setcounter{linenumber}{1}
\setcounter{LN@truepage}{44}
\setcounter{FV@TrueTabGroupLevel}{0}
\setcounter{FV@TrueTabCounter}{0}
\setcounter{FV@HighlightLinesStart}{0}
\setcounter{FV@HighlightLinesStop}{0}
\setcounter{FancyVerbLineBreakLast}{0}
\setcounter{FV@BreakBufferDepth}{0}
\setcounter{float@type}{16}
\setcounter{minted@FancyVerbLineTemp}{0}
\setcounter{minted@pygmentizecounter}{0}
\setcounter{listing}{0}
\setcounter{tcblisting}{0}
\setcounter{caption@flags}{6}
\setcounter{continuedfloat}{0}
\setcounter{subfigure}{0}
\setcounter{subtable}{0}
\setcounter{section@level}{1}
\setcounter{Item}{46}
\setcounter{Hfootnote}{38}
\setcounter{bookmark@seq@number}{43}
\setcounter{AlgoLine}{0}
\setcounter{algocfline}{0}
\setcounter{algocfproc}{0}
\setcounter{algocf}{0}
\setcounter{lofdepth}{1}
\setcounter{lotdepth}{1}
\setcounter{svg@param@lastpage}{0}
\setcounter{svg@param@currpage}{-1}
\setcounter{su@anzahl}{0}
\setcounter{LT@tables}{0}
\setcounter{LT@chunks}{0}
\setcounter{@pps}{0}
\setcounter{@ppsavesec}{0}
\setcounter{@ppsaveapp}{0}
\setcounter{tabx@nest}{0}
\setcounter{listtotal}{0}
\setcounter{listcount}{0}
\setcounter{liststart}{0}
\setcounter{liststop}{0}
\setcounter{citecount}{0}
\setcounter{citetotal}{0}
\setcounter{multicitecount}{0}
\setcounter{multicitetotal}{0}
\setcounter{instcount}{78}
\setcounter{maxnames}{3}
\setcounter{minnames}{3}
\setcounter{maxitems}{3}
\setcounter{minitems}{1}
\setcounter{citecounter}{0}
\setcounter{maxcitecounter}{0}
\setcounter{savedcitecounter}{0}
\setcounter{uniquelist}{0}
\setcounter{uniquename}{0}
\setcounter{refsection}{0}
\setcounter{refsegment}{0}
\setcounter{maxextratitle}{0}
\setcounter{maxextratitleyear}{0}
\setcounter{maxextraname}{0}
\setcounter{maxextradate}{0}
\setcounter{maxextraalpha}{0}
\setcounter{abbrvpenalty}{50}
\setcounter{highnamepenalty}{50}
\setcounter{lownamepenalty}{25}
\setcounter{maxparens}{3}
\setcounter{parenlevel}{0}
\setcounter{blx@maxsection}{0}
\setcounter{mincomprange}{10}
\setcounter{maxcomprange}{100000}
\setcounter{mincompwidth}{1}
\setcounter{afterword}{0}
\setcounter{savedafterword}{0}
\setcounter{annotator}{0}
\setcounter{savedannotator}{0}
\setcounter{author}{0}
\setcounter{savedauthor}{0}
\setcounter{bookauthor}{0}
\setcounter{savedbookauthor}{0}
\setcounter{commentator}{0}
\setcounter{savedcommentator}{0}
\setcounter{editor}{0}
\setcounter{savededitor}{0}
\setcounter{editora}{0}
\setcounter{savededitora}{0}
\setcounter{editorb}{0}
\setcounter{savededitorb}{0}
\setcounter{editorc}{0}
\setcounter{savededitorc}{0}
\setcounter{foreword}{0}
\setcounter{savedforeword}{0}
\setcounter{holder}{0}
\setcounter{savedholder}{0}
\setcounter{introduction}{0}
\setcounter{savedintroduction}{0}
\setcounter{namea}{0}
\setcounter{savednamea}{0}
\setcounter{nameb}{0}
\setcounter{savednameb}{0}
\setcounter{namec}{0}
\setcounter{savednamec}{0}
\setcounter{translator}{0}
\setcounter{savedtranslator}{0}
\setcounter{shortauthor}{0}
\setcounter{savedshortauthor}{0}
\setcounter{shorteditor}{0}
\setcounter{savedshorteditor}{0}
\setcounter{labelname}{0}
\setcounter{savedlabelname}{0}
\setcounter{institution}{0}
\setcounter{savedinstitution}{0}
\setcounter{lista}{0}
\setcounter{savedlista}{0}
\setcounter{listb}{0}
\setcounter{savedlistb}{0}
\setcounter{listc}{0}
\setcounter{savedlistc}{0}
\setcounter{listd}{0}
\setcounter{savedlistd}{0}
\setcounter{liste}{0}
\setcounter{savedliste}{0}
\setcounter{listf}{0}
\setcounter{savedlistf}{0}
\setcounter{location}{0}
\setcounter{savedlocation}{0}
\setcounter{organization}{0}
\setcounter{savedorganization}{0}
\setcounter{origlocation}{0}
\setcounter{savedoriglocation}{0}
\setcounter{origpublisher}{0}
\setcounter{savedorigpublisher}{0}
\setcounter{publisher}{0}
\setcounter{savedpublisher}{0}
\setcounter{language}{0}
\setcounter{savedlanguage}{0}
\setcounter{origlanguage}{0}
\setcounter{savedoriglanguage}{0}
\setcounter{pageref}{0}
\setcounter{savedpageref}{0}
\setcounter{textcitecount}{0}
\setcounter{textcitetotal}{0}
\setcounter{textcitemaxnames}{0}
\setcounter{biburlbigbreakpenalty}{100}
\setcounter{biburlbreakpenalty}{200}
\setcounter{biburlnumpenalty}{0}
\setcounter{biburlucpenalty}{0}
\setcounter{biburllcpenalty}{0}
\setcounter{smartand}{1}
\setcounter{bbx:relatedcount}{0}
\setcounter{bbx:relatedtotal}{0}
\setcounter{cbx@tempcnta}{0}
\setcounter{cbx@tempcntb}{13}
\setcounter{cbx@tempcntc}{0}
\setcounter{cbx@tempcntd}{-1}
\setcounter{tcb@cnt@codeblock}{0}
}

View File

@ -75,6 +75,8 @@
\restylefloat{figure}
\DeclareFontSeriesDefault[rm]{bf}{sbc} % beton Computer Concrete does not have bold font
\pretocmd{\chapter}{\addtocontents{listings}{\protect\addvspace{10pt}}}{}{} % Group listings by chap
\setlength{\cftfignumwidth}{3em} % Modify number width in LoF
\setlength{\cfttabnumwidth}{3em} % Modify number width in LoT
\sisetup{detect-all}
% \renewcommand{\baselinestretch}{0.95}
@ -483,6 +485,7 @@
fonttitle=\footnotesize,
adjusted title=\thetcbcounter\quad\texttt{#2},
list entry=\thetcbcounter\quad\texttt{#2},
list text={\hspace*{1ex}#2}, % Chapter - Caption spacing in list of listings
after title={%
\hfill\setlength{\fboxsep}{2pt}
\codelang{#3}

View File

@ -4,8 +4,8 @@ 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);
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));

View File

@ -6,18 +6,18 @@
mov edi, ebx ; Now the ID is in EDI
; Load the AP's prepared GDT and TSS
mov ebx, [boot_ap_gdts - boot_ap + startup_address]
mov eax, [ebx + edi * 0x4]
mov ebx, [boot_ap_gdts - boot_ap + 0x8000]
mov eax, [ebx + edi * 0x4] ; Select the GDT
lgdt [eax]
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 ebx, [boot_ap_stacks - boot_ap + 0x8000]
mov esp, [ebx + edi * 0x4] ; Select the stack
add esp, 0x1000 ; Stack starts at the bottom
mov ebp, esp
; Call the entry function
; Call the entry function smpEntry(uint8_t cpuid)
push edi
call [boot_ap_entry - boot_ap + startup_address]
call [boot_ap_entry - boot_ap + 0x8000]

View File

@ -1,12 +1,13 @@
; This section has to be compiled for 32-bit protected mode
bits 32
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 eax, [boot_ap_cr3 - boot_ap + 0x8000]
mov cr3, eax
mov eax, [boot_ap_cr0 - boot_ap + startup_address]
mov eax, [boot_ap_cr0 - boot_ap + 0x8000]
mov cr0, eax
mov eax, [boot_ap_cr4 - boot_ap + startup_address]
mov eax, [boot_ap_cr4 - boot_ap + 0x8000]
mov cr4, eax
; Load the system IDT
lidt [boot_ap_idtr - boot_ap + startup_address]
lidt [boot_ap_idtr - boot_ap + 0x8000]

View File

@ -1,4 +1,6 @@
; This section has to be compiled for 16-bit real mode
[SECTION .text]
bits 16
boot_ap:
; Disable interrupts
cli

View File

@ -0,0 +1,43 @@
; Export the variables to allow initialization by C++ code
global boot_ap_idtr
global boot_ap_cr0
global boot_ap_cr3
global boot_ap_cr4
global boot_ap_gdts
global boot_ap_stacks
global boot_ap_entry
[SECTION .text]
align 8
bits 16
boot_ap:
; [...] boot_ap 16-bit
; The variables initialized during runtime
align 8
boot_ap_idtr:
dw 0x0
dd 0x0
align 8
boot_ap_cr0:
dd 0x0
align 8
boot_ap_cr3:
dd 0x0
align 8
boot_ap_cr4:
dd 0x0
align 8
boot_ap_gdts:
dd 0x0
align 8
boot_ap_stacks:
dd 0x0
align 8
boot_ap_entry:
dd 0x0
bits 32
align 8
boot_ap_32:
; [...] boot_ap_32 32-bit

View File

@ -13,7 +13,7 @@ void ApicTimer::trigger(const InterruptFrame &frame) {
return;
}
// Trigger preemption
// BSP triggers preemption
if (time.toMilliseconds() % yieldInterval == 0) {
System::getService<SchedulerService>().yield();
}

View File

@ -2,7 +2,6 @@
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;
@ -10,6 +9,7 @@ void IoApic::initializeREDTBL() {
redtblEntry.isMasked = true;
redtblEntry.destination = LocalApic::getId(); // Redirect to BSP
IrqOverride *override = getOverride(gsi);
if (override != nullptr) {
// Apply any information provided by an interrupt override
redtblEntry.vector = override->source + 32;

View File

@ -1,7 +1,10 @@
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);
// Excerpt from the initializeLVT function
void LocalApic::initializeLVT() {
LVTEntry lvtEntry{};
lvtEntry.deliveryMode = LVTEntry::DeliveryMode::FIXED;
lvtEntry.pinPolarity = LVTEntry::PinPolarity::HIGH;
lvtEntry.triggerMode = LVTEntry::TriggerMode::EDGE;
lvtEntry.isMasked = true;
lvtEntry.vector = InterruptVector::ERROR;
writeLVT(ERROR, lvtEntry);
}

View File

@ -1,4 +1,7 @@
SVREntry svrEntry{};
svrEntry.vector = InterruptVector::SPURIOUS;
svrEntry.isSWEnabled = true; // Keep the APIC software enabled
writeSVR(svrEntry);
// Excerpt from the initialize function
void LocalApic::initialize() {
SVREntry svrEntry{};
svrEntry.vector = InterruptVector::SPURIOUS;
svrEntry.isSWEnabled = true; // Keep the APIC software enabled
writeSVR(svrEntry);
}

View File

@ -2,7 +2,7 @@
void Pit::earlyDelay(uint16_t us) {
uint32_t counter = (static_cast<double>(BASE_FREQUENCY) / 1'000'000) * us;
controlPort.writeByte(0b110000); // Channel 0, mode 0
controlPort.writeByte(0b110000); // Channel 0, mode 0
dataPort0.writeByte(static_cast<uint8_t>(counter & 0xFF)); // Low byte
dataPort0.writeByte(static_cast<uint8_t>((counter >> 8) & 0xFF)); // High byte

View File

@ -31,11 +31,11 @@
% Chapters
\include{chap/introduction}
\include{chap/background}
\include{chap/interrupthandling}
\include{chap/implementation}
\include{chap/verification}
\include{chap/testing}
\include{chap/conclusion}
\begin{appendices}
\include{chap/listings}
\include{chap/figures}
\include{chap/tables}
\end{appendices}