%*
%* Copyright (c) 2007 by Lukas Ruf (lukas.ruf@lpr.ch)
%*
%* Create: 2007-01-30:1627
%* Modify: 2007-01-30:1634
%* Commit: $Id: implementation.tex 3053 2007-08-20 19:32:27Z sryffel $
%*

\chapter{Implementation}
\label{implementation}

% The implementation chapter documents the concepts and mechanisms
% \emph{you} have developed and implemented as part of your thesis.

Dieses Kapitel dokumentiert die Umsetzung des im Kapitel \ref{arch} 
aufgezeigten Designs. Zur besseren Lesbarkeit sind die zwei Kapitel gleich 
strukturiert. Die wichtigsten Konzepte werden hier erläutert, für eine 
abschliessende Referenz sei aber auf den kommentierten Quelltext verwiesen 
\cite{bib:topsyv3p4svn}.



\section{Übersicht}
\label{implementation:overview}

% Since it is important to be concise, avoid all pitfalls and
% fallacies that may lead you into troubles: Introduce and specify
% clearly, what and \emph{why} you are going to present something.
% 
% Avoid presenting tons of code\dots  it's just not useful!
% \verb+grep+ is much more than searching by hand\ldots

Als Einleitung in das folgende Kapitel
beschreibe ich das Setup mit allen verwendeten Programmen und Tools. Im
Unterkapitel `Vorgehen' folgt ein kurzer Abriss des Ablaufs der
Implementationsphase. Zuletzt will ich auf die Organisation des Quelltextes
von Topsy v3 im Allgemeinen und der ia32-Portierung im Speziellen eingehen.


\subsection{Setup}

Auf meiner Entwicklungs- und Testmaschine lief Gentoo Linux\footnote{Gentoo 
Linux: http://www.gentoo.org}  2007.0 mit gcc\footnote{GNU Compiler Collection: 
http://gcc.gnu.org} in der Version 4.1.2, binutils\footnote{GNU Binutils: 
http://www.gnu.org/software/binutils} v2.17 und make\footnote{GNU Make: 
http://www.gnu.org/software/make} v3.81.

Zum Testen des Codes verwendete ich primär bochs\footnote{Bochs: 
http://bochs.sourceforge.net/} (v2.3), da dieser einen sehr mächtigen Debugger 
integriert. Ich testete Topsy aber auch mit QEMU\footnote{QEMU: 
http://www.qemu.org/} (v0.9) und vor allem mit dem VMPlayer\footnote{VMWare 
Player: http://www.vmware.com/products/player/} (v1.1.2). Der VMPlayer ist 
gratis erhältlich und kann die gleichen Images abspielen wie die VMWare Workstation und 
alle anderen VMWare Produkte. Es fehlen ihm aber die Entwicklertools und die 
Möglichkeit, Images zu erstellen.

Genauere Infos zum Setup und eine Installationsanleitung finden sich im File
\code{README.txt}\footnote{\code{README.txt} auf der beiliegenden CD}.

\subsection{Vorgehen}

Nach der Einarbeitungszeit, welche ich vor allem für das Lesen der
ia32-Spezifikationen \cite{bib:ia32spec} und das Vertrautwerden mit dem
Topsy-Code (\cite{bib:topsy}, \cite{bib:topsyi386}, \cite{bib:topsyv3}) verwendete, begann
ich mit der Arbeit an Topsy i386. 

Zuerst waren Anpassungen nötig, dass es überhaupt mit
den neuen GNU-Tools kompiliert. Nachher debuggte ich den Startup-Prozess, bis
dieser wieder den architektur-unabhängigen Teil erreichte. 

Um nicht zu viel Zeit mit der alten Codebasis aufzuwenden, arbeitete ich dann
an Topsy v3 weiter. Der Boot-Code konnte beinahe unverändert übernommen
und weiter debugged werden. Dann musste das alte Memory Management entfernt und
der HAL des neuen implementiert werden.

Dann kümmerte ich mich um den lokalen APIC, die Ersetzung des alten Timers durch
denjenigen des lokalen APICs und schliesslich noch um den I/O-APIC. 

Die meiste Arbeit dann in die Überarbeitung des Thread Management, das
neue Stacklayout, den reentranten Interrupt Handler und die entsprechenden
Anpassungen der Interprozesskommunikation und des Schedulers ein.


 
\subsection{Organisation des Quelltextes}

Der Quelltext von Topsy ist nach den Subsystemen organisiert. Abbildung
\ref{fig:codetoplevel} zeigt den Inhalt des Verzeichnisses \code{Topsy-v3\_P4}. 

\begin{figure}[H]
	\centering
 \begin{boxedverbatim}
Topsy-v3_P4
|-- Boot            : Architektur-abhängige Boot-Prozesse
|-- Config          : verschiedene Konfigurationsfiles (d)
|-- Docu            : Dokumentation (d)
|-- IO              : Input/Output
|-- Makefiles       : Makefiles (d)
|-- Memory          : Altes Memory Management (Topsy v1)
|-- Net             : Netzwerk-Stack (*)
|-- Startup         : Architektur-unabhängiger Topsy-Startup
|-- Threads         : Thread-Management 
|-- ThreadsLight    : Lightweight Threads (*)
|-- Tools           : Tools fürs Builden von Topsy
|-- Topsy           : Konfiguration und Libraries
|-- User            : User Applikationen, zB die Shell
`-- VMemory         : Neues Virtual-Memory Management
\end{boxedverbatim}

\verb+(*)+: Nicht Gegenstand dieser Arbeit

\verb+(d)+: Enthält keinen Code

	\caption{Organisation des Quelltextes: \code{Topsy-v3\_P4}}
	\label{fig:codetoplevel}
\end{figure}

Alle in der Abbildung \ref{fig:codetoplevel} aufgeführten Verzeichnisse mit 
Code, enthalten die architektur-unabhängigen Files und für jede Architektur ein 
Unterverzeichnis mit den architektur-abhängigen Files. Im Folgenden ist jeweils 
nur das diese Arbeit betreffende Unterverzeichnis \code{ia32} aufgeführt.

\newpage

\subsubsection{Boot}

\begin{figure}[H]
    \centering
\begin{boxedverbatim}
Topsy-v3_P4/Boot/
`-- ia32                    
    |-- LowCore             : Boot-Code
    |   |-- CoreBoot        : Code des MBRs, springt in CoreLoad
    |   |   `-- ...
    |   |-- CoreLoad        : Initialisiert HW und lädt Topsy
    |   |   `-- ...
    |   `-- Include         : Includes
    |       `-- ...
    |-- Tools
    |   |-- CreateNetImg
    |   |   `-- ...
    |   |-- KernPatch       : Alter Binary-Patcher
    |   |   `-- ...
    |   |-- Keyboard        : Erstellt Tabelle für Keyboard-Treiber
    |   |   `-- ...
    |   `-- ToolLib
    |       `-- ...
    `-- link.ia32.scr       : Linkskript für Kernel Image
\end{boxedverbatim}
    \caption{Organisation des Quelltextes: \code{Topsy-v3\_P4/Boot/}}
    \label{fig:codeboot}
\end{figure}

Das Verzeichnis \code{Boot} (Abb. \ref{fig:codeboot}) enthält den
architektur-abhängigen Bootloader und das Linkskript für das Kernel Image. 

\vspace{\stretch{1}}

\newpage

\subsubsection{IO}

\begin{figure}[H]
    \centering
\begin{boxedverbatim}
Topsy-v3_P4/IO/
|-- Drivers                 : Architektur-unabhängige Treiber
|   |-- Ethertap.{c,h}      : 
|   `-- Loopback.{c,h}      : Loopback-Treiber
|-- IO.h                    : Include
|-- IOConsole.{c,h}         : Textausgabe auf Konsole
|-- IODevTable.h            : Struktur der Device-Tabelle
|-- IODevice.{c,h}          : Main der Device-Threads
|-- IOMain.{c,h}            : IO-Thread
`-- ia32
    |-- Debug.{c,h}         : Debug
    |-- Drivers             : Architektur-abhängige Treiber
    |   |-- HWKeyTable.S
    |   |-- IOPci*.c        : PCI-Treiber
    |   |-- KeyCodeTable.S
    |   |-- Keyboard.{c,h}
    |   |-- TTY.{c,h}       : Konsolen-Treiber
    |   |-- Video.{c,h}     : Video-Treiber
    |   |-- classlist.h
    |   |-- devlist.h
    |   |-- keyboard.{S,h}
    |   |-- names.c
    |   |-- pci.ids
    |   |-- performanceTest.{c,h}
    |   `-- video.{S,h}
    |-- IODevTable.c        : Tabelle der Geräte-Konfigurationen
    |-- IOHal.{c,h}
    `-- Tools
        `-- gen-devlist.c
\end{boxedverbatim}
    \caption{Organisation des Quelltextes: \code{Topsy-v3\_P4/IO/}}
    \label{fig:codeio} 
\end{figure}

Im Verzeichnis \code{IO} (Abb. \ref{fig:codeio}) sind alle Gerätetreiber und der
IO Kernel Thread gespeichert. 

\subsubsection{Memory}

\begin{figure}[H]
    \centering
\begin{boxedverbatim}
Topsy-v3_P4/Memory/
|-- MMHeapMemory.{c,h}
|-- MMHeapMemory_new.c
|-- MMInit.{c,h}
|-- MMMain.{c,h}
|-- MMVirtualMemory.{c,h}
|-- Memory.h
`-- ia32
    |-- MMDirectMapping.c
    |-- MMError.{c,h}
    |-- MMHal.{c,h}         : GDT-, IDT-, TSS-Verwaltung 
    |-- MMMapping.h
    |-- MemoryLayout.h      : Konfiguration des Memory-Management
    `-- mmHalAsm.{S,h}      : Diverse Assembler-Routinen
\end{boxedverbatim}
    \caption{Organisation des Quelltextes: \code{Topsy-v3\_P4/Memory/}}
    \label{fig:codemm}
\end{figure}

Das Memory Management von Topsy v1 wird bis auf die beschriebenen Files nicht
mehr verwendet. Es ist im Verzeichnis \code{Memory} (Abb. \ref{fig:codemm}).

\subsubsection{Startup}

\begin{figure}[H]
    \centering
\begin{boxedverbatim}
Topsy-v3_P4/Startup/
|-- Startup.{c,h}       : topsyMain(), erste arch-unabhängige Funktion
|-- headerLayout.h      : Topsyheader
`-- ia32
    |-- BinaryFile.h    : Alter BinFileDesc, abgelöst durch topsyheader
    |-- Init.{c,h}      : Initialisiert HAL und springt in topsyMain()
    `-- start.S         : Bildet topsyheader des Binary
\end{boxedverbatim}
    \caption{Organisation des Quelltextes: \code{Topsy-v3\_P4/Startup/}}
    \label{fig:codestartup}
\end{figure}

\code{topsyMain()} und der architektur-unabhängige Startupcode befinden sich im
Verzeichnis \code{Startup} (Abb. \ref{fig:codestartup}). 

\vspace{\stretch{1}}

\subsubsection{Threads}

\begin{figure}[H]
    \centering
\begin{boxedverbatim}
Topsy-v3_P4/Threads
|-- TMIPC.{c,h}                 : IPC Funktionen für Kernel 
|-- TMInit.{c,h}                : Initialisiert TM und startet 
|                                   die Kernel Threads
|-- TMMain.{c,h}                : Thread-Management-Thread
|-- TMProtectionDomain.{c,h}    : Protection Domain
|-- TMScheduler.{c,h}           : Scheduler
|-- TMThread.{c,h}              : Erstellen, Verwalten und Löschen 
|                                   von Threads
|-- TMTime.{c,h}                 
|-- TMTimer.{c,h}               : Alter Timer
|-- TMTimerNG.{c,h}             : Sendet Nachricht, wenn bestimmte 
|                                   Zeit abgelaufen
|-- Threads.h                   
|-- config.in
|-- ia32
|   |-- TM8254Timer.c           : Funktionen des alten Timers
|   |-- TM8254TimerAsm.S        : Assembler Routinen 
|   |-- TMClock.{c,h}           : Verwaltet Echtzeit-Uhr 
|   |-- TMClockAsm.S            : Assembler-Routinen der RTC
|   |-- TMError.{c,h}           : Error- und Exception-Handler
|   |-- TMHal.{c,h}             : HAL des Thread Management
|   |-- TMHalApic.{c,h}         : APIC und I/O-APIC Implementation
|   |-- TMHalApicAsm.{S,h}      : Assembler Routinen 
|   |-- TMHalAsm.{S,h}          : Assembler Routinen
|   `-- TMSMPHal.{c,h}          : Stubs für SMP
`-- tm-include.h                : Strukturen des Thread Managements
\end{boxedverbatim}
    \caption{Organisation des Quelltextes: \code{Topsy-v3\_P4/Threads}}
    \label{fig:codetm}
\end{figure}

Die gesamte Thread Verwaltung, der Scheduler und der Interrupt Handling Code
sind im Verzeichnis \code{Threads} (Abb. \ref{fig:codetm}). 

\vspace{\stretch{1}}
\newpage


\subsubsection{Topsy}

\begin{figure}[H]
    \centering
\begin{boxedverbatim}
Topsy-v3_P4/Topsy/
|-- Assert.{c,h}            : Assert-Makros
|-- Configuration.h         : Konfiguriert Topsy
|-- Error.{c,h}             : Error Handling
|-- HashList.{c,h}
|-- Lifo.{c,h}
|-- List.{c,h}
|-- Lock.{c,h}              : Lock Implementation
|-- Messages.h              : Alle Nachrichtenformate
|-- Socket.{c,h}
|-- Support.{c,h}           : Diverses
|-- Syscall.{c,h}           : Syscalls
|-- SyscallMsg.h
|-- System.{c,h}
|-- Topsy.h
|-- Version.h
|-- doubleq.h
`-- ia32
    |-- CoreLoad.h
    |-- Endian.h
    |-- Exception.{c,h}
    |-- Limits.h
    |-- PrintReg.c
    |-- SupportAsm.{S,h}    : Assembler Routinen für Support.c
    |-- SyscallMsg.S        : Implementiert Syscall zum Senden
    |                           und Empfangen von Nachrichten
    |-- Tools.{c,h}
    |-- asm.h
    |-- cpu.h               : Arch-abhängige Konfiguration
    `-- limits.h
\end{boxedverbatim}
    \caption{Organisation des Quelltextes: \code{Topsy-v3\_P4/Topsy/}}
    \label{fig:codetopsy}
\end{figure}

Das Verzeichnis \code{Topsy} (Abb. \ref{fig:codetopsy}) beinhaltet diverse
Headerfiles mit Konfigurationsoptionen, Datenstrukturen wie Listen und Locks
und die Kernel Library.

\vspace{\stretch{1}}
\newpage


\subsubsection{User}

\begin{figure}[H]
    \centering
\begin{boxedverbatim}
Topsy-v3_P4/User/
|-- CrashMe.{c,h}                   : Crash-Tests
|-- Demo.{c,h}                      : Demo 
|-- HeapAllocator.{c,h}             : Heap Allocator für User Threads
|-- HeapFreeTree.{c,h}
|-- HelloWorld.{c,h}                : Hello World
|-- IRQControl.{c,h}
|-- Licence.{c,h}                   : Zeigt GPL
|-- Lock.{c,h}
|-- PacketDriverTest.{c,h}
|-- PacketFraming.{c,h}
|-- PacketStackControl.{c,h}
|-- PacketStackControl_loopback.c
|-- PacketStackGlobals.h
|-- Packetizer.{c,h}
|-- SeatReservation.{c,h}           : Demo Reservationssystem
|-- Shell.{c,h}                     : Shell
|-- StartMeFirstUser.c              : Initialisiert und startet Shell
|-- ThreadsDemo.{c,h}               : Thread Demo
|-- UserSupport.{c,h}               
|-- datafile.{c,h}
|-- ia32
|   `-- userStart.S                 : topsyheader, ia32-Start
|-- link.ia32.scr                   : Link-Skript des User Images
|-- link.ixp2400.scr
|-- link.linux.scr
|-- link.mips.scr
|-- link.mips.simos.scr
|-- link.sa1100.scr
|-- link.solaris.scr
|-- malloc_api.{c,h}                : malloc
|-- testtimer.{c,h}
|-- tmTimerTest.{c,h}
`-- ualloc_api.c
\end{boxedverbatim}
    \caption{Organisation des Quelltextes: \code{Topsy-v3\_P4/User/}}
    \label{fig:codeuser}
\end{figure}

Der gesamte Code des User Images wie die Shell und die Applikationen sind im
Verzeichnis \code{User} (Abb. \ref{fig:codeuser}). Auch das Linkskript des User
Images und \code{userStart.S}, welches den Topsyheader des User Images bildet,
sind dort gespeichert.

\vspace{\stretch{1}}
\newpage

\subsubsection{VMemory} 

\begin{figure}[H]
    \centering
\begin{boxedverbatim}
Topsy-v3_P4/VMemory/
|-- HeapAllocator.{c,h}         : Heap Implementation
|-- HeapFreeTree.{c,h}
|-- ia32
|   |-- vm_bootup_hal.c         : Initialisiert HAL-Layer
|   |-- vm_hal.{c,h}            : Hilfsfunktionen des HAL-Layer
|   |-- vm_pmap.c               : Implementiert pmap-Layer
|   |-- vm_pmap_asm.{S,h}       : Assembler Routinen
|   |-- vm_pmap_exc.c           : Exception-Management 
|   `-- vm_pmap_hal.h           : Strukturen des HAL-Layers
|-- kalloc_api.{c,h}
|-- steal_alloc.{c,h}
|-- vm.h
|-- vm_alloc.{c,h}
|-- vm_anon.{c,h}
|-- vm_bootup.{c,h}             : Initialisiert VM
|-- vm_calls.{c,h}              : Implementiert VM-Interface
|-- vm_dmap.{c,h}
|-- vm_domain.{c,h}
|-- vm_extern.h
|-- vm_file.{c,h}
|-- vm_hash.{c,h}
|-- vm_loader.{c,h}
|-- vm_loan.{c,h}
|-- vm_main.{c,h}               : Memory Management Thread
|-- vm_map.{c,h}
|-- vm_object.{c,h}
|-- vm_page.{c,h}
|-- vm_pmap.h                   : PMap Interface
`-- vm_region.h
\end{boxedverbatim}
    \caption{Organisation des Quelltextes: \code{Topsy-v3\_P4/VMemory/}}
    \label{fig:codevm}
\end{figure}

Das Memory Management von Topsy v3 und der MM-Thread befinden sich im
Verzeichnis \code{VMemory} (Abb. \ref{fig:codevm}).

\vspace{\stretch{1}}

\newpage

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Memory Management}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{implementation:memorymanagement}

Alle am Memory Management vorgenommenen Änderungen konzentrieren sich, abgesehen
von Bugfixes, auf die Files im Verzeichnis \code{Topsy-v3\_P4/VMemory/ia32}
(Abb. \ref{fig:codevm}). 


\subsection{Memory Management in Topsy v3}

\begin{figure}[!ht]
	\centering
	\includegraphics[width=0.5\textwidth]{topsy-v3-mm.png}
	\caption{Aufbau des Memory Management in Topsy v3 (aus \cite{bib:topsyv3})}
	\label{fig:topsyv3-mm}
\end{figure}

Abbildung \ref{fig:topsyv3-mm} zeigt den Aufbau des objektorientierten
Memory Management von Topsy v3. Die Threads der verschiedenen Protection Domains
greifen über die Bibliotheken des Heap Allocators oder des IPCs mittels Syscalls
auf den Memory Management Threads zu. 

Der MM-Thread benützt dann den pmap-Layer des HALs. Dieser kümmert sich um das
Mapping der Pages von virtuellen auf physikalische Adressen. Diese
Funktionalität braucht auch der Exception Handler, dessen Architektur im Kapitel
\ref{arch:threadmanagement} genauer beschrieben ist.

In \cite{bib:topsyv3} ist das pmap-Interface beschrieben. Es besteht aus 12
Funktionen, welche für die ia32-Architektur implementiert werden mussten. 


\subsection{Paging}

Die Implementation des eigentlichen Paging beinhaltet die Verwaltung der Page
Directories und der Page Tables, Funktionen zur Aktualisierung des Page-Caches
(Translation Lookaside Buffer, TLB) und der Page Fault Handler.

Die ia32-Architektur kennt sowohl 4KB als auch 4MB grosse Pages. Da Topsy
relativ wenig Memory braucht, habe ich mich für die 4KB-Option entschieden. 

\subsubsection{Verwaltung der Page Directories und Page Tables}

\begin{figure}[!ht]
	\centering
	\includegraphics[width=0.75\textwidth]{paging-translation.png}
	\caption{Lineare Adressübersetzung für 4KB grosse Pages (aus \cite{bib:ia32spec})}
	\label{fig:ia32pagingtranslation}
\end{figure}


Wie in den Abbildungen \ref{fig:segnpaging} und \ref{fig:ia32pagingtranslation}
ersichtlich, sind die Page Directories
und Page Tables im Wesentlichen 4KB grosse Tabellen mit 1024 Pointern auf Page Tables
respektive physikalische Pages. Die Tabellen werden bei Bedarf dynamisch
alloziert und wieder freigegeben.

Dafür wird beim Startup mittels \code{vm\_allocate\_bootup\_memory()} ein direkt
gemappter Bereich der Grösse \code{pmap\_buf\_size} alloziert. Dessen virtuelle
beziehungsweise physikalische Anfangsadresse wird in \code{pmap\_vbase}
respektive \code{pmap\_pbase} gespeichert.  

\begin{figure}[!ht]
	\centering
 \begin{boxedverbatim}
     +-------------+  TOP = pmap_vbase + pmap_buf_size  
 12  |  PTbl 1     | 
 11  |  PTbl 2     |
 10  | ->next free |  pmap_free_ptbl = 10
  9  |  PTbl 3     |  pmap_ptbl_seg_bottom = 9
  8  |             |
  7  :             :
  6  :             :
  5  |             | 
  4  |  PDir 3     |  pmap_pdir_seg_top = 4
  3  |  PDir 2     |
  2  | ->next free |  pmap_free_pdir = 2
  1  |  PDir 1     |
     +-------------+  BOTTOM = pmap_vbase (pmap_pbase)  
\end{boxedverbatim}
	\caption{Beispiel der Benutzung des pmap-Buffers}
	\label{fig:ia32pagingpmapbuffer}
\end{figure}

Dieser Bereich wird nun `von oben' mit Page Tables und `von unten' mit Page
Directories gefüllt. Der Füllstand wird mit den Variablen
\code{pmap\_ptbl\_seg\_bottom} und \code{pmap\_pdir\_seg\_top} nachgeführt. Wenn
innerhalb der Bereiche eine Tabelle entfernt wird, wird sie in die entsprechende
Freelist eingetragen. Die Abbildung \ref{fig:ia32pagingpmapbuffer} zeigt
beispielhaft eine mögliche Belegung und die dazugehörigen Werte der Variablen.
Der Buffer hat zwölf Slots à 4KB, wobei sechs davon belegt sind.


\begin{figure}[!ht]
	\centering
	\includegraphics[width=0.75\textwidth]{paging-entries.png}
	\caption{Format der Page-Directory und Page-Table Einträge (aus \cite{bib:ia32spec})}
	\label{fig:ia32pagingentries}
\end{figure}

Da sowohl Page Tables als auch die Pages selber an der 4KB-Grenze ausgerichtet sein
müssen, können die niederwertigen 12Bits der 32Bit grossen Einträge für
Flags verwendet werden. Deren Format ist in der Abbildung \ref{fig:ia32pagingentries}
dargestellt.

Topsy kennt Flags für lesbar, schreibbar, ausführbar, cachbar und bufferbar. 
Diese können eins zu eins auf die verfügbaren Flags gemappt werden. Die einzige 
Ausnahme sind Pages, die laut den Topsy Flags weder lesbar noch schreibbar sind. 
Solche werden als Supervisor-Pages gemappt, welche nur im Kernel Modus 
lesbar und schreibbar sind. Diese Praxis ist konsistent mit den anderen 
Architekturen, es wäre dennoch sinnvoll, ein zusätzliches Flag für Pages
einzuführen, welche nur vom Kernel Mode aus lesbar und schreibbar sein dürfen. 

Die Tabelle \ref{tab:ia32pagingpriv} listet den kombinierten Effekt der 
Berechtigungs-Flags des Page Directory und der Page Table auf. Die 
Implementation kennzeichnet alle Page Directory Einträge als lesbar, schreibbar 
und User. Die effektiven Berechtigungen der Pages können so vom Page Table 
Eintrag gesetzt werden.


\begin{table}[!ht]
	\centering
	\includegraphics[width=0.75\textwidth]{paging-privileges.png}
	\caption{Kombination von Page Table und Page Flags (aus \cite{bib:ia32spec})}
	\label{tab:ia32pagingpriv}
\end{table}


\subsubsection{Exception Handler}

Die Exception Handler befinden sich im File 
\code{Topsy-v3\_P4/VMemory/ia32/vm\_pmap\_exc.c}.


Der prominenteste Vertreter ist der Page Fault Handler, er führt folgende Aktionen
aus:
\begin{enumerate}
  \item Er findet die Adresse, welche die Ausnahmebedingung verursachte. Sie
  steht im Register \code{\%cr2} der CPU. 
  \item Er ermittelt die Art des Fehlers. Die Flags des Fehlercodes auf dem
  Stack weisen auf die Ursache hin. 
  \item Er blockiert den Thread und sendet die gesammelten Daten an den MM-Thread.
  \item Der MM-Thread mappt dann die Page, sofern der Zugriff gültig war. Andernfalls
  beendet er den fehlerhaften Thread.
\end{enumerate}

\begin{table}[!ht]
\centering
\begin{tabular}{|llp{6cm}|}
\hline
\bfseries Nummer & \bfseries Name & \bfseries Ursache \\
\hline 
T\_EX\_05 & BOUND Range Exceeded Exception & Array-Index ausserhalb des gültigen
Bereichs \\
T\_EX\_09 & Coprocessor Segment Overrun & Page- oder Segment-Fehler im Intel 387
Mathematik Coprozessor, nur in Intel386-CPU basierten Systemen \\
T\_EX\_0A & Invalid TSS Exception & Problem mit Task State Segment \\
T\_EX\_0B & Segment Not Present & Segment nicht vorhanden \\
T\_EX\_0C & Stack Fault Exception & Limit überschritten oder Stack Segment ist
nicht verfügbar \\
T\_EX\_0E & Page Fault & Page Fault \\
T\_EX\_11 & Alignment Check Exception  & Wenn Alignment Check aktiviert ist \\
\hline
\end{tabular}
\caption{Memory-Exceptions}
\label{tab:mmexc}
\end{table}

Die anderen Memory-Exceptions sind in der Tabelle \ref{tab:mmexc} aufgeführt und
beenden den verursachenden Thread sofort.


\subsection{Segmente}

Auch wenn Segmente in Topsy v3 nicht mehr zur Partitionierung des Speichers und 
zum Speicherschutz verwendet werden, sind sie wichtig. Das Privilegien-Feld des 
aktuellen Code-Segments definiert, mit welchen Privilegien der Code läuft. Aus 
diesem Grund benötigen Kernel und User Threads verschiedene Code-Segmente.

In Assembler-Code werden gerne Segmente zur vereinfachten und sichereren
Programmierung verwendet, wenn nur in einem bestimmten Bereich operiert wird.
Dazu dienen die Segmente `OS Video', welches das VGA-Memory umfasst, `OS
GDT', mit der Global Descriptor Table und `IDT Alias', welches die Interrupt
Descriptor Table beinhaltet. 

Die dritte Kategorie sind die speziellen Segmente. Das `BSP TSS' beinhaltet
das Task State Segment des Bootstrapprocessors. Dieses Segment wird für
Kontextwechsel des Prozessors verwendet, welcher das System bootet. Im Multicore
Betrieb muss für jede weitere CPU ein eigenes TSS angelegt werden. Dafür kann
die Funktion \code{int pmap\_get\_new\_tss(unsigned short *tss\_sel, unsigned short
*tss\_alias, struct protection\_domain *d) } verwendet werden.



\begin{table}[!ht]
\centering
\begin{tabular}{|llll|}
\hline
\bfseries Selektor & \bfseries Verwendung & \bfseries Start & \bfseries Grösse \\
\hline
\code{0x00} & Dummy & \code{-} & \code{-} \\
\code{0x08} & OS Code& \code{0x0} & \code{4GB} \\
\code{0x10} & OS Daten& \code{0x0} & \code{4GB} \\
\code{0x18} & OS Global& \code{0x0} & \code{4GB} \\
\code{0x20} & OS Video& \code{0xB8000} & \code{0xFBF} \\
\code{0x28} & OS GDT & \code{0x1000} & \code{64KB} \\
\code{0x30} & IDT Alias & \code{0x10000} & \code{4KB} \\
\code{0x38} & BSP TSS & \code{0x1E000} & \code{104B} \\
\code{0x40} & BSP TSS Alias& \code{0x1E000} & \code{104B} \\
\code{0x48} & User Code & \code{0x0} & \code{4GB} \\
\code{0x50} & User Data & \code{0x0} & \code{4GB} \\
\hline
\end{tabular}
\caption{Segmente in Topsy v3}
\label{tab:seg}
\end{table}


\subsection{Syscalls}

Es war nötig, einige neue Syscalls zu implementieren und alte zu
erweitern. Die Änderungen betreffen den MM-Thread und wurden in
\code{VMemory/vm\_main.c} vorgenommen.

Der MM-Thread unterstützt folgende neuen Nachrichtentypen:
\begin{itemize}
  \item \codebf{VM\_MAP\_FIND\_NEAR} \\ 
  Findet im PD mit der Id \code{pdId} eine Region \code{region} der Grösse \code{size} in der
  Nähe des Pointers \code{hint}. 
  
  \emph{Aufruf:} In der Enveloppe müssen folgende Argumente gespeichert werden:
  \code{ThreadId pdId, address\_t hint size\_t size, Region\_t region} und \code{int
  direction}.
  
  \emph{Rückgabe:} Die Rückgabe enthält einen Fehlercode. Wenn der Aufruf
  erfolgreich war, ist dieser gleich \code{VM\_OK} und die Pointer zeigen auf den
  Start und das Ende der gefundenen Region:
  \code{id = VM\_REPLY \\
        reply.msg.vm\_reply.err  : Fehlercode \\
        reply.msg.vm\_reply.ptr1 : region.start \\
        reply.msg.vm\_reply.ptr2 : region.end
        }
  
  \item \codebf{VM\_REGION\_SHARE} \\
  Macht die Region \code{region} aus dem PD \code{sourcePdId} auch im PD
  \code{destPdId} in der Nähe von \code{hint} verfügbar.
  
  \emph{Aufruf:} In der Enveloppe müssen folgende Argumente gespeichert werden:
  \code{ThreadId sourcePdId, ThreadId destPdId, Region\_t region,
  address\_t hint, int flags} und \code{int direction}
  
  \emph{Rückgabe:} wie oben.
  
  \item \codebf{VM\_REGION\_ADD\_NEAR} \\
  Fügt dem PD \code{pdId} die Region \code{region} in der Nähe von \code{hint} hinzu.
  
  \emph{Aufruf:} In der Enveloppe müssen folgende Argumente gespeichert werden:
  \code{ThreadId pdId, Region\_t region} und \code{ address\_t hint}
  
  \emph{Rückgabe:} wie oben.
  
  \item \codebf{VM\_REGION\_ENTER} \\
  Stellt sicher, dass die Region, in welchem \code{hint} im PD \code{pdId}
  liegt, im pmap-Layer eingetragen ist. Operationen auf der Region können dann
  keine Page Faults mehr provozieren.
  
  \emph{Aufruf:} Der gewünschte PD wird in \code{msg.msg.vm\_get.pdId} und der
  Pointer in \code{msg.msg.vm\_get.hint} gespeichert.
  
  \emph{Rückgabe:} Fehlercode in \code{VM\_REPY}.

\end{itemize}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Thread Management}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{implementation:threadmanagement}

Beim Thread Management mussten nicht nur die HAL-Files in
\code{Topsy-v3\_P4/Threads/ia32}, sondern auch architektur-unabhängige Files
verändert werden. Nachfolgend werden die Implementationen des Stackmanagements,
des Interrupt Handlers und der APICs erklärt.


\subsection{Stacks}
\label{implementation:threadmanagement:stacks}

Das Stackmanagement von User  und Kernel Threads unterscheidet sich fundamental.
User Threads besitzen zwei Stacks, zwischen denen bei Privilegienänderungen
gewechselt wird. Kernel Threads laufen immer im Kernel Mode und benötigen daher
nur einen Stack. In diesem Unterkapitel wird deshalb zuerst das
Stackmanagement der User Threads und nachher das der Kernel Threads beschrieben.


\subsubsection{User Threads}

Die Abbildung \ref{fig:stacksutsimpl} zeigt die Stacks eines User Threads und
sinnbildlich für seinen Ablauf den Verlauf des Stackpointers. Auf der linken Hälfte
befindet sich der 265KB grosse User Mode Stack (UMS) und auf der anderen Seite
der viel kleinere, 8KB grosse Kernel Mode Stack (KMS). Zudem besitzt die CPU ein
Task Register, über welches das Task State Segment (TSS) referenziert wird. Dies
speichert das Stacksegment \code{ss0} und den Stackpointer \code{esp0} des KMS
des aktuellen Threads.

\begin{figure}[!ht]
    \centering
    \includegraphics[width=1\textwidth]{stacks-uts-impl.pdf}
    \caption{User Mode- und Kernel Mode Stack eines User Threads}
    \label{fig:stacksutsimpl}
\end{figure}


\paragraph{Ablauf eines User Threads:} Die Nummerierung entspricht derjenigen der
Abbildung \ref{fig:stacksutsimpl}.
\begin{enumerate}
  \item Wenn der Thread im User Mode gestartet wird, zeigt sein Stack-Pointer auf
  die Position \code{(1)}. Dort steht eine Rücksprungadresse (mehr dazu unter
  Punkt 6.). Dem Thread können zwei 4 Byte grosse Argumente übergeben werden.
  
  \item Der Thread startet seine Ausführung, wobei der UMS wächst. Bei der
  Position \code{(2)} wird er durch einen Interrupt unterbrochen. 
  
  Auf Grund des Privilegienwechsels benützt die CPU nun automatisch den im
  TSS angegebenen KMS und speichert dort die Position des alten Stacks und den
  Zustand, genannt \code{Stack Frame}, des eben unterbrochenen Threads.
  
  Die Funktion \code{\_\_get\_thread\_from\_esp()} liefert im Kernel Mode 
  jederzeit die Thread-Struktur des aktuell laufenden Threads. Da alle Kernel
  Stacks an der 8KB-Grenze ausgerichtet sind, muss dafür nur der Stackpointer
  abgerundet werden. Dieser Mechanismus wurde von Linux entlehnt.
  
  Der Interrupt Handler läuft nun im Kernel Mode und wechselt in den
  Protection Domain des TM-Threads. Interrupts sollten möglichst schnell
  abgearbeitet werden, da sonst nachfolgende verzögert werden können. Deshalb
  erhöht der Handler seine Scheduling Priorität auf \code{INTHANDLER\_PRIORITY},
  was typischerweise die höchste verfügbare ist.
  
  \item Sobald das Stack Frame vollständig aufgebaut ist, können weitere Interrupts
  zugelassen werden. Der Interrupt Handler bearbeitet den Interrupt, bis er im
  Punkt \code{(3)} wieder unterbrochen wird. 
  
  Nun findet kein Privilegien- und deshalb auch kein Stack-Wechsel statt. Aus diesem
  Grund muss
  auch keine alte Stack-Position gespeichert werden. Das neue Stack Frame wird
  wie vorher aufgebaut, es fehlen aber die Werte \code{ss} und
  \code{esp}. Ansonsten unterscheiden sich verschachtelte Unterbrechungen nicht
  von gewöhnlichen.
  
  \emph{Anmerkung:} Bei Unterbrechungen, welche keinen Privilegienwechsel nach
  sich ziehen, fehlen \code{ss} und \code{esp} im Stack Frame. Dies ist
  namentlich bei Nested Exceptions und Unterbrechungen von Kernel Threads der
  Fall. Deshalb kann im Allgemeinen nicht davon ausgegangen werden, dass diese
  zwei Felder der zugehörigen Datenstruktur \code{ProcStackFrame} auf gültige
  Werte zeigen.
  
  \item Der Interrupt Handler ist beim Punkt \code{(4)} fertig. Er prüft nun
  die Lauffähigkeit des Stack Frames 1 anhand der darin enthaltenen Scheduling
  Informationen und aktualisiert die Scheduling Informationen des Threads.
  
  Der Scheduler bestimmt nun den nächsten Thread, welcher die CPU bekommt.
  Sobald der hier besprochene Thread an der Reihe ist, wird sein Stack Frame 1
  wieder hergestellt, Interrupt Return (\code{iret}) ausgeführt und der erste Interrupt
  Handler läuft weiter.
  
  \item An der Position \code{(5)} passiert genau dasselbe wie bei \code{(4)}.
  Insbesondere wird die alte Priorität wieder hergestellt.
  Die \code{iret} Instruktion erkennt anhand des Codesegments im Stack Frame, dass
  ein Privilegienwechsel ausgeführt wird, und popt dann auch \code{ss} und
  \code{esp} vom Stack. 
  
  Der User Thread fährt nun an der gleichen Stelle weiter, an der er
  unterbrochen wurde.
  
  \item Wenn die Hauptfunktion des Threads zurückkehrt (Punkt \code{(6)}),
  springt das Programm in den \code{Exit Code}, welcher ebenfalls auf dem Stack des
  Threads liegt. In diesem wird  die \code{Exit Nachricht} an den TM-Thread
  gesendet, welcher den Thread aus dem System entfernt. 
  
\end{enumerate}




\subsubsection{Kernel Threads}

Kernel Threads unterscheiden sich von User Threads nur durch ihren Aufbau. Beim
Erstellen von Threads muss zwischen User und Kernel Threads unterschieden
werden. Während der Laufzeit ist dies aber transparent, die Abläufe sind genau
gleich. 


\begin{figure}[!ht]
	\centering
	\includegraphics[width=0.35\textwidth]{stacks-kts-impl.pdf}
	\caption{Kernel Thread-Stack eines Kernel Threads}
	\label{fig:stacksktsimpl}
\end{figure}

\paragraph{Ablauf eines Kernel Threads:} (siehe Abbildung \ref{fig:stacksktsimpl})
\begin{enumerate}
  \item Auch den Kernel Threads können zwei Argumente übergeben werden, und der
  Stack Pointer zeigt beim Start auf die Rücksprungadresse bei Position
  \code{(1)}. Wie schon angedeutet, besitzen Kernel Threads aber nur einen
  Stack, den Kernel Thread Stack (KTS). Der KTS ist wie der KMS der User Threads
  8KB gross.
  
  \item Ein Interrupt eines Kernel Threads sieht genau gleich aus wie eine
  verschachtelte Unterbrechung eines User Threads.
  
  \item Auch die Rückkehr vom Interrupt unterscheidet sich nicht von der eines
  User Threads.
  
  \item Wenn der Kernel Thread fertig ist, wird er mit dem gleichen Mechanismus
  beendet wie ein User Thread.
\end{enumerate}


\subsubsection{Stack Management}

Das Neue Stack Management bedingte einige Änderungen am 
architektur-unabhängigen Teil und macht insbesondere das Stack Management 
selber architektur-abhängig.

Die unten aufgeführten Funktionen müssen für alle anderen
Architekturen noch implementiert werden. Im zweiten Abschnitt der
Funktionsbeschreibung ist jeweils die Lösung der ia32-Architektur beschrieben.

Mögliche Werte von \code{flags} sind \code{TM\_KERNEL}, wenn ein Kernel Thread 
erstellt werden soll, und \code{TM\_INIT}, wenn die Kernel Threads noch nicht 
laufen. Wenn die Kernel Threads noch nicht laufen, dürfen die Funktionen des 
Memory Managers direkt aufgerufen werden, ansonsten müssen die Syscalls des 
MM-Threads verwendet werden. 

Die Funktionen liefern \code{TM\_OK}, wenn sie erfolgreich waren, und
sonst \code{TM\_FAILED}.

\begin{itemize}
  \item \codebf{int tmHalInit()} \\
  Diese Funktion initialisiert den HAL-Layer des Thread Management. Hier können
  Datenstrukturen initialisiert werden. Diese Funktion wird von \code{tmInit()}
  aufgerufen, der Heap Allocator ist also bereits initialisiert.
  
  \emph{ia32:} Es gibt hier nichts Wesentliches zu tun.
  
  \item \codebf{int tmHalInitThread(Thread* *threadPtr, ThreadId destPDId, \\
  \phantom{int tmHalInitThread(}ThreadId tmPDId, Address* stackBaseAddress, \\
  \phantom{int tmHalInitThread(}Address* stackBaseMappedAt, \\ 
  \phantom{int tmHalInitThread(}size\_t* stackSize, int flags)} \\
  Diese Funktion alloziert die Thread Struktur und den Stack und gibt die
  entsprechenden Werte zurück.  
  
  \emph{ia32:} Diese Funktion erstellt das im Kapitel 
  \ref{implementation:threadmanagement:stacks} besprochene Layout. Dabei wird 
  der Kernel Mode Stack im TM-Thread und im Zielthread an die gleiche Stelle 
  gemappt. Auch der User Mode Stack muss in den PD des TM-Threads gemappt und 
  der Pointer \code{stackBaseMappedAt} entsprechend gesetzt werden.
  
  Dann werden die Datenstrukturen \code{Thread} und dessen architektur-abhängiger
  Teil \code{ProcContext} angelegt und initialisiert.
  
  Ein TSS muss nicht angelegt werden, da nicht pro Thread, sondern pro CPU ein
  TSS vorhanden ist.
  
  \item \codebf{int tmHalCleanupAfterThreadBuild(Thread* threadPtr, \\
  \phantom{int tmHalCleanupAfterThreadBuild(}Address stackBaseMappedAt, \\
  \phantom{int tmHalCleanupAfterThreadBuild(}int flags)} \\
  Wenn der Thread erstellt und lauffähig ist, werden eventuell bestimmte
  Ressourcen nicht mehr gebraucht, welche in \code{tmHalInitThread()} alloziert
  wurden. Diese können jetzt freigegeben werden.
  
  \emph{ia32:} Wenn der TM-Thread in einem anderen PD als der Zielthread ist,
  kann dessen Stack aus dem virtuellen Speicher des TM-Threads gelöscht werden. 
  
  
  \item \codebf{int tmHalDestroyThread(Thread* threadPtr, ThreadId destPDId, \\
  \phantom{int tmHalDestroyThread(}ThreadId tmPDId)} \\
  Wenn der Thread aus dem System entfernt wird, muss diese Funktion alle
  verbleibenden Ressourcen freigeben. Dazu gehören die Thread Struktur wie auch
  die Stacks.
  
  \emph{ia32:} Es wird zuerst der User Mode Stack gelöscht, nachher der Kernel
  Mode Stack aus dem PD des Threads und zuletzt auch aus dem PD des
  TM-Threads entfernt. Damit ist auch die Thread Struktur freigegeben.
  
\end{itemize}



\subsection{Scheduler} 

Die Unterstützung von Nested Exceptions zog Anpassungen an den Scheduler
Funktionen nach sich. Diese sind hier dokumentiert, weil sie für die anderen
Architekturen noch implementiert werden müssen.

\code{BlockCause} gibt ein Hinweis auf das gewünschte Stack Frame, welches 
verändert werden soll (siehe Kapitel 
\ref{arch:threadmanagement:reentrantinthandler}). Dabei sind folgende 
Unterbrechungsarten definiert: \code{TIMER\_INT}, \code{PAGE\_FAULT}, 
\code{MSG\_RECV}, \code{MSG\_SEND} und \code{ACTIVE}.

Die Funktionen liefern \code{TM\_OK}, wenn sie erfolgreich waren, und
sonst \code{TM\_FAILED}.

\begin{itemize}
  \item \codebf{int tmHalThreadSetReady(ThreadPtr threadPtr, BlockCause hint)} \\
  Setzt das entsprechende Stack Frame auf \code{READY}.
  
  \item \codebf{int tmHalThreadSetBlocked(ThreadPtr threadPtr, BlockCause hint)}
  \\
   Blockiert das Stack Frame.
  
  \item \codebf{void tmHalThreadSetResched(ThreadPtr threadPtr, BlockCause
  hint)}
  Markiert das Stack Frame so, dass der Interrupt Handler den Scheduler
  den nächsten Thread wählen lässt. Ansonsten läuft der aktuelle Thread weiter. 
  
  
  \item \codebf{void tmHalThreadYield(ThreadPtr threadPtr, BlockCause hint)} \\
  Gibt die CPU ab, ausser der Thread ist im Interrupt Handler. Dann wird dieser
  zuerst abgearbeitet.
  
  \item \codebf{SchedStatus tmHalThreadGetSchedStatus(ThreadPtr threadPtr, \\
  \phantom{SchedStatus tmHalThreadGetSchedStatus(}BlockCause hint)} \\
  Liefert den Scheduler Status (\code{READY}, \code{RUNNING}, \code{BLOCKED})
  des Stack Frames.
  
  \item \codebf{void tmHalIpcResetPendingFlag(Thread* threadPtr)} \\
  Diese Funktion wird aufgerufen, bevor ein Thread wieder hergestellt
  wird. Wenn der Thread auf eine Nachricht gewartet hat und jetzt durch sie geweckt
  wird, muss der Status seiner Nachrichten-Queue von
  \code{PENDING} auf \code{NOT\_WAITING} aktualisiert werden.
  
  Wenn der Thread aus einem anderen Grund geweckt wird (zB ein Page Fault),
  bleibt der Status erhalten.
  
\end{itemize}

Architekturen, welche keine Nested Exceptions kennen, können einfach im File
\code{TMHal.h} Makros definieren, welche die alten Scheduler Funktionen
aufrufen. Dieses File befindet sich im Unterverzeichnis mit den
architektur-abhängigen Files des \code{Threads} Verzeichnisses.


%\subsection{Interrupt Handling}



\subsection{Reentranter Interrupt Handler}
\label{implementation:threadmanagement:reentrant}

Den Interrupt Handler reentrant (auch thread-safe genannt) zu machen, war nicht
einfach. Zum Glück sind viele Teile von Topsy v3 schon geschützt, zum Beispiel
der Heap Allocator und weitere Teile des Memory Management. 

Die Thread Struktur ist neu quasi-gleichzeitigen Zugriffen
ausgesetzt. Sie beinhaltet nicht nur Statusinformationen des Schedulers, sondern
auch die Nachrichten-Queue. Besonders diese zwei Strukturen müssen unbedingt geschützt
werden. Sie sind aber nicht unabhängig, sondern eng
miteinander verknüpft. Deshalb können sie nicht einzeln, sondern die
Thread Struktur muss als ganzes durch ein Lock geschützt werden.

In Topsy gibt es drei Möglichkeiten, Locking zu implementieren. Die einfachste
ist das Deaktivieren von Unterbrechungen in kritischen Bereichen. Dies wäre praktikabel
und effizient für Singlecore-Systeme, funktioniert bei mehreren Prozessoren aber
nicht mehr. Die zweite Möglichkeit ist die Verwendung von \code{BigLock},
einem Lock, welches gleichzeitig mehrere lesende Zugriffe, aber immer nur einen
schreibenden zulässt. Solche Situationen kommen aber kaum vor, weshalb ein
normales \code{Lock} verwendet werden kann. \code{Lock} ist als simples
Spinlock\footnote{Ein Spinlock prüft in einer ewigen Schleife ständig, ob
das Lock freigegeben wurde und kehrt dann zurück.} implementiert. 

Das Hinzufügen der Lockvariable zur Threadstruktur und das Locking der kritischen
Bereiche genügt aber noch nicht. Das Lock muss in Bereichen des Interrupt
Handlers erworben werden, in denen Interrupts deaktiviert sind. Wenn ein
anderer Thread das Lock noch besitzt, bleibt Topsy im Spinlock hängen. Es muss
also verhindert werden, dass ein Thread in kritischen Bereichen unterbrochen
wird. 
% Dies wird mit den Funktionen \code{\_\_cli(int* flags)} und
% \code{\_\_restore\_flags(int flags)} gemacht, welche Interrupts deaktivieren
% und die originalen Einstellungen zurückgeben respektive diese
% wiederherstellen. 

Die Kombination aus Lock und maskierten Interrupts ist nicht gefahrlos. Der 
Programmierer muss garantieren, dass seine Implementation  in kritischen 
Bereichen nicht unterbrochen werden kann. Dies gilt insbesondere für Exceptions 
wie Page Faults und Non Maskable Interrupts (NMI). Diese Garantien können im 
Interrupt Handler gegeben werden, indem in den kritischen Bereichen nicht auf 
Strukturen zugegrifen wird, von denen nicht bekannt ist, ob sie gemappt sind 
und keine NMIs verwendet werden. Der wachsende Stack kann keinen Page Fault 
verursachen, da dieser zu Beginn vollständig gemappt wird.

Zur Vereinfachung wurden die Makros \code{LOCK\_THREAD(threadPtr, flags)} und
\code{UNLOCK\_THREAD(threadPtr, flags)} eingeführt, welche für alle
Architekturen implementiert werden müssen (\code{Threads/<arch>/TMHal.h}). Diese
Makros kümmern sich um die De- respektive Re-Aktivierung der Interrupts
und das Erwerben respektive Freigeben des Locks.

Die gewählte Lösung schützt die Thread Struktur vor zeitgleichen Zugriffen und
funktioniert sowohl in Single als auch in Multi Core Systemen. 


\subsection{Fazit und Limitationen des neuen Thread Management}

Das neue Thread und Stack Management ist in seinem Aufbau komplizierter als das
alte. Es bietet jedoch erweiterte Möglichkeiten wie Nested Exceptions und erhöhte
Sicherheit, da User Threads nicht auf ihren Kernel Mode Stack zugreifen können.

Da die Kernel Mode Stacks die Thread Struktur enthalten, müssen sie immer in den
PD des TM-Threads gemappt sein. Dies limitiert die maximale Anzahl gleichzeitig
lauffähiger Threads. Ein KMS ist 8KB gross und muss unterhalb und oberhalb
mindestens eine freie Page haben, um Stack Faults festzustellen. Er braucht also
16KB des VM. Bei 4GB verfügbarem VM können etwa eine Viertelmillion Threads 
angelegt werden. 

Im Betrieb ist das neue System unkomplizierter, da keine Daten kopiert werden 
müssen und nicht zwischen User und Kernel Threads oder Nested und normalen 
Exceptions unterschieden werden muss.


\subsection{Lokaler APIC}

Der lokale APIC muss einerseits initialisiert und konfiguriert und
andererseits der alte Timer durch den modernen des lokalen APICs ersetzt werden.
Der C-Code für den APIC ist in den Files \code{Threads/ia32/TMHalApic.\{c,h\}}
und die Assembler Routinen in den Files \code{Threads/ia32/TMHalApicAsm.\{S,h\}}.

Der lokale APIC wird konfiguriert durch Memory Mapped Register, welche an
bestimmten Offsets der Position \code{apic\_base} liegen. Einige der Register
sind nur lesbar andere auch schreibbar. Für genauere Informationen sei auf das
Kapitel 8 im Band 3A von \cite{bib:ia32spec} verwiesen.

\subsubsection{Kompilieren} 
Wenn im Makefile \code{Makefiles/Makefile.ia32.i386}
die Variable \code{APIC} auf \code{"YES"} gesetzt wird, wird der Kernel mit
APIC-Support kompiliert und das Makro \code{APIC} definiert. 
% Anhand dieses Makros bildet der Präprozessor den gewünschten Programmcode.

\subsubsection{Initialisierung}

\begin{figure}[!ht]
\begin{center}
  \includegraphics[width=0.66\textwidth]{topsyv3-boot-ia32.png}
  \caption{Startup von Topsy v3}
  \label{fig:topsyv3bootia32}
\end{center}
\end{figure}

Die Initialisierungsfunktionen werden im architektur-abhängigen Startup in
\code{Startup/ia32/Init.c} aufgerufen. Einen Screenshot des Outputs zeigt die
Abbildung \ref{fig:topsyv3bootia32}.

In \code{ApicInit()} wird zuerst geprüft, ob ein APIC vorhanden ist, und dieser 
dann
aktiviert. Dann probiert der Code, den CPU-Typ herauszufinden. Wenn sie nicht
von Intel stammt, wird abgebrochen. Dies hat den Grund, dass später auf 
sogenannte ``Model-Specific Registers'' zugegriffen wird, die sonst eventuell
bei diesem Prozessor ungültig sind. 
Dann werden die einzelnen Komponenten konfiguriert und die gewünschten
Interrupt Vektoren (Nummern) gesetzt. Die Priorität eines Interrupts ist gleich seiner
Nummer geteilt durch 16. Der lokale APIC sendet einen Interrupt nur an den
Prozessor, wenn dieser Interrupts aktiviert hat und nicht gerade einen mit höherer
Priorität behandelt. Momentan haben (fast) alle Interrupts die gleiche Priorität. Das
Task Priority Register definiert, welche minimale
Priorität ein Interrupt haben muss, um einen anderen unterbrechen zu können. Es
wird auf 0 initialisiert, so dass alle Interrupts andere unterbrechen dürfen.
Zuletzt werden die Interrupt Register zurückgesetzt und damit alle hängigen
Interrupts entfernt.

\code{ApicTimerInit()} kalibriert den Timer des lokalen APICs. Zuerst muss die
Geschwindigkeit des Front Side Buses herausgefunden werden. Dazu wird der Timer
mit einem grossen Initialwert gestartet und mit Hilfe der Echtzeituhr eine Sekunde
gewartet. Die Differenz der Timerwerte ist die Frequenz.

Später wird in \code{tmInit()} (\code{Threads/TMInit.c}) die Funktion
\code{tmInstallErrorHandlers()} ausgeführt, welche die Interrupt Handler des
APICs installiert. Der eine ist \code{ApicErrorISR()} mit der Interrupt Nummer
(Vektor) 
\code{APIC\_IR\_ERRIV}, welcher bei Fehlern im APIC ausgelöst wird und eine
Fehlermeldung ausgibt. Der andere ist der Spurious Interrupt Handler
\code{ApicSpivISR()} mit dem Vektor \code{APIC\_IR\_SPIV}. Dieser spezielle
Interrupt dient dazu, auf einen Prioritäten-Konflikt aufmerksam zu
machen. In Topsy wird er ignoriert und der Handler wird nur registriert, wenn
das Makro \code{APIC\_SPIV\_HANDLING\_ISR} definiert ist. Andernfalls wird immer
sofort \code{iret} ausgeführt, was den Overhead absolut minimiert (siehe
Quelltext in \code{Threads/ia32/TMHalAsm.S}). 

\subsubsection{Verwendung des Timers des lokalen APICs} 
Die Verwendung des Timers
des lokalen APICs unterscheidet sich nicht von derjenigen des alten Timers. Mittels
\code{setClockValue()} kann das gewünschte Intervall in Millisekunden gewählt
werden. Wenn der Kernel mit APIC-Support kompiliert wird, wird der APIC Timer
und sonst der alte verwendet.

\subsubsection{Interrupt Handler} 
Die Abarbeitung eines Interrupts muss dem APIC
mit \code{\_\_endOf\_APIC\_IRQ()} signalisiert werden. Dann weiss dieser, dass
er den nächsten senden darf. Die einzige Ausnahme ist der Spurious Interrupt,
welcher nicht bestätigt werden muss.


\subsection{I/O APIC}

Der I/O APIC ist ein Baustein, welcher Interrupts flexibel an verschiedene CPUs
weiterleiten kann. Bein Einschalten verhält er sich rückwärts kompatibel zum
alten Programmable Interrupt Controller. In diesem Modus sind sämtliche
APIC-Komponenten passiv und werden umgangen.

\begin{figure}[!ht] 
    \centering
    \includegraphics[width=0.75\textwidth]{ioapicsmpmode.png}
    \caption{Symmetric I/O des I/O-APIC (aus \cite{bib:mpspec})}
    \label{fig:ioapismpmode} 
\end{figure}

Der flexibelste Modus ist der Symmetric I/O Mode, welcher in
Abbildung \ref{fig:ioapismpmode} dargestellt ist. Dabei werden alle Interrupts
an den I/O-APIC gesendet. Dieser besitzt eine interne Tabelle, in der für jeden
eingehenden Interrupt eine oder mehrere CPUs und ein Interrupt-Vektor definiert
ist. Anhand dieser Tabelle leitet der I/O-APIC die eingehenden Interrupts
weiter. 

In \code{IOApicInit()}, welches gleich nach der Initialisierung des lokalen
APICs ausgeführt wird, wird zuerst der Baustein aktiviert, in den Symmetric I/O
Mode gesetzt und dann die Weiterleitungstabelle konfiguriert. Die Interrupts 0
bis 16 werden an den BSP mit den Vektoren 32 bis 48 gesandt und alle anderen
ausmaskiert. Dies wird so gemacht, dass das Verhalten äquivalent zu dem des
alten PIC ist. 





%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Interprozesskommunikation}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{implementation:ipc}
 
Die Implementation des IPC-Mechanismus muss sich zwei neuen Herausforderungen
stellen: dem virtuellen Memory und gleichzeitigen Zugriffen. 

Der Hauptteil des IPC-Managements geschieht im Interrupt Handler. Die verwendete
Nachrichten Queue ist Teil der Thread Struktur. Die Thread Safety wurde deshalb
im Kapitel \ref{implementation:threadmanagement:reentrant} schon adressiert.  

In diesem Kapitel geht es im Weiteren um das neue Memory Management.


\subsection{Memory Management}
\label{implementation:mm}

Das im Kapitel \ref{arch:ipcmm} skizzierte Protokoll wurde implementiert. Die 
Funktion 
\code{int vm\_pmap\_map\_page\_in\_other\_pmap(pmap\_t from\_pmap, address\_t from\_virt,
pmap\_t to\_pmap, address\_t to\_virt, int flags) } 
dient dazu, temporär die Page der Nachricht in den PD des TM-Threads
zu mappen. Später wird diese mittels der Funktion 
\code{void moveMessageToPD(Thread* threadPtr, Message* msgPtr, Message*
destPtr)} 
in den PD des Empfängers verschoben.

Diese Routinen benötigen jeweils eine oder zwei Pages im virtuellen Adressraum des
TM-Threads. Diese können mit 
\code{address\_t vm\_pmap\_pagebuff\_get\_page(void)}
angefordert und mit 
\code{void vm\_pmap\_pagebuff\_release\_page(address\_t v\_addr)}
wieder freigegeben werden. Diese Funktionen schützen den Page Buffer durch ein
Lock und sind thread safe.

Der Page Buffer wird bei der Initialisierung des pmap-Layers in der Funktion
\code{void vm\_pmap\_pagebuff\_init(struct vm\_segmap* segmap)} angelegt.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Boot Prozess}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{implementation:bootup}

\begin{figure}[!ht]
\begin{center}
  \includegraphics[width=0.66\textwidth]{topsyv3-boot-coreload.png}
  \caption{Core Boot und Core Loader von Topsy v3}
  \label{fig:topsyv3bootcoreload}
\end{center}
\end{figure}

Der Boot-Prozess wurde praktisch unverändert von Topsy i386 übernommen. Da an
seinem grundsätzlichen Design wenig verändert wurde, sei auf die Dokumentation
\cite{bib:topsyi386} verwiesen. Die Abbildung \ref{fig:topsyv3bootcoreload}
zeigt den Ablauf von Core Boot und Core Load. Grossen Einfluss auf den Boot Prozess
hatte die Verschiebung der Segmente und die Migration zum Topsyheader.


\subsection{Relozierung zur Link-Zeit}

\begin{figure}[!ht]
\begin{center}
  \includegraphics[width=0.66\textwidth]{topsyv3-boot-pmap.png}
  \caption{Architektur-unabhängiger Startup von Topsy v3}
  \label{fig:topsyv3bootpmap}
\end{center}
\end{figure}

Aus verschiedenen Gründen mussten die Link Skripte angepasst werden. Topsy v3
unterscheidet nicht nur zwischen Code und Daten eines Programms, sondern kennt
auch BSS, welches uninitialisierte Daten beinhaltet. Letzteres musste dem Binary
hinzugefügt und die Bereiche mussten an der Page Grenze ausgerichtet werden.
Diese Bedingungen stellt das Memory Management von Topsy v3 (siehe Abbildung
\ref{fig:topsyv3bootpmap}, welche die Initialisierung des Memory Management
zeigt). 

Sowohl das Kernel als auch das Userimage starteten ihre jeweiligen Segmente am
Offset 0 (siehe Kapitel \ref{arch:memorymanagement:segments}). Neu umspannen 
beide Segmente aber den ganzen linearen Adressraum. Somit startet der Kernel 
bei 128KB und das User Image wurde an die Position bei 2MB verschoben. Die 
Position im File ist also nicht mehr automatisch die Adresse im Memory, was im 
Link Skript berücksichtigt werden muss.


\subsection{Topsyheader}

Der Topsyheader ist ein in Topsy v3 eingeführter, obligatorischer Header für 
Binaries. Sein Format ist für alle Architekturen identisch und ersetzt den 
\code{BinFileDesc} des ia32-Ports. In Topsyheader werden vor allem Angaben zur 
Grösse und Position der Bereiche des Binaries gespeichert, sie sind in 
\cite[Kapitel 18]{bib:topsyv3} dokumentiert. Die Informationen werden am 
Schluss des Build-Prozess vom Programm PatchBinaries in das Binary geschrieben.

Der Topsyheader der Binaries wird für das Kernel Image im File
\code{Startup/ia32/start.S} und fürs User Image in \code{User/ia32/userStart.S}
erstellt. Die Felder für architekurspezifische Informationen werden im ia32-Port
für die Anzahl vom Binary belegten Tracks (Grösseneinheit auf Disketten)
verwendet. 

Der Boot Prozess ist an vielen Stellen auf den Header angewiesen und musste
angepasst werden. Schon im Bootloader liest die Funktion \code{rm\_load} (File 
\code{Boot/ia32/LowCore/CoreLoad/rm\_load.inc}) die Grösse des Images und
kopiert die angegebene Anzahl Tracks von der Diskette ins Memory (siehe
Abbildung \ref{fig:topsyv3bootcoreload}). Das dabei
gewählte Kopierverfahren ist zwar schnell, das Image ist im Memory aber nicht
mehr zusammenhängend und muss später nochmals umkopiert werden. Dies geschieht
im \code{main()} (File \code{Startup/ia32/Init.c}) anhand des Topsyheaders des
Kernel und User Images.

Das letzte Mal wird der Topsyheader im architektur-abhängigen Teil in der
Funktion \code{vm\_get\_segmap()} (File \code{VMemory/ia32/vm\_bootup\_hal.c})
gebraucht, um dem Memory Manager die Grösse und Position der belegten
Speicherbereiche anzugeben. 





%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%\section{Diverses}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%\label{implementation:misc}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


% \section{\label{implementation:essentials}Essentials}
% 
% Well this section can be further subdivided into subsection.  We present
% this in subsection \ref{implementation:essentials:subsections}.
% 
% \subsection{\label{implementation:essentials:subsections}Subsections}
% 
% \paragraph{\label{implementation:essentials:subsections:paragraph}Paragraphs}
% can be specially referenced as well.
% 
% Of further importance is the understanding of the following environments:
% 
% %*** itemized lists
% \begin{itemize}
% \item This shows an itemized bullet list
%   \begin{itemize}mechanisms
%   \item Which can be used for several levels\ldots
%   \end{itemize}
% \end{itemize}
% 
% %*** enumerated lists
% \begin{enumerate}
% \item The same applies to enumerated lists.
% \end{enumerate}
% 
% 
% %** figures
% \begin{figure}[!hbt]
%   \begin{center}
% %		 \includegraphics[width=\textwidth, angle=90]{file_name.eps}
%   \caption{This is a figure to be printed in a float}
%   \label{file_name}
%   \end{center}
% \end{figure}
% 
% By figure \ref{file_name}, we show some funny figures.
% 
% 
% Table with caption and footnotes below the table.
% 
% \begin{table}[htbp]
% \begin{center}\begin{minipage}{\textwidth}
% \begin{tabular}{| c | p{130pt} | l |}
% \hline
% Column 1 & Column 2 \newline (additional line) & Column 3 \\
% \hline
% C1,R2 & C2,R2 & C2,R3 \\
% \hline
% C1,R3	& \multicolumn{2}{| c |}{C2\&C3,R3} \\
% \hline
% C1,R4 & C2,R4\footnote{Footnote to table~\ref{tab:table1}} & C3,R4\\
% \hline
% \end{tabular}
% \end{minipage}
% \caption{Table 1}
% \label{tab:table1}
% \end{center}
% \end{table}
% 
% Examples of different text sizes:
% 
% \small Small \\
% \scriptsize Script size \\
% \normalsize Normal \\
% \large Large \\
% \huge Huge \\
% \normalsize
% 
% \CHECK
% If we reference to another document, we cite the document \cite{bib:relevantwork}.
% 
% %** landscape
% \NEW
% \begin{landscape}
% Of some interest is also the landscape environment:
% \end{landscape}
% 
% \verbatiminput{filename.txt}
% Even though we don't think full listings are useful in documents,
% you can easily insert complete files by the verbatiminput{}-command.


