Blog
Tipps zum Paging
2022-05-31
Da wir in der Rechnerübung vergleichsweise viele verzweifelte Gesichter sehen durften, hier ein paar Tipps zum Lösen der Aufgabe:
analog zu meiner letzten Mail gilt auch hier Vorsicht bei den Linker “Source Code Reference”: Wenn ihr das externe Symbol mittels
in eurem Code einbindet, dann bekommt ihr mit
&___KERNEL_START___
die Adresse – hier wieder unbedingt den Adressoperator&
berücksichtigen!(IO/L)APIC ist memory mapped (bei
0xfec00000
sowie0xfee00000
), diese Adressen sollte entsprechend ebenfalls identitätsabgebildet sein.Es besteht auch die Möglichkeit diese auf eine andere Adresse zu legen, dass hat aber ein paar Fallstricke.
wie auch in der Tafelübung erwähnt: Testet euren Page Frame Allocator!
Wenn der falsche Seiten ausgibt, werdet ihr richtig fies beim pagen auf die Nase fallen…
am einfachsten ist es, wenn der Page Frame Allocator nur auf Seitengranularität arbeitet – also 4K ausgerichtete Start- und Endadressen.
Denkt an das korrekte auf- und abrunden (abhängig ob Start-oder Endadresse und zur Liste hinzufügen oder entfernen)
grundsätzlich ist es meiner Meinung nach sehr hilfreich wenn ihr für das Paging mindestens folgende ähnliche Methoden habt:
bool Paging::map(uintptr_t virtAddr, uintptr_t physAddr, bool usermode, bool writeable, bool executable /* 7.5 ECTS */ ); uninptr Paging::unmap(uintptr_t virtAddr); uninptr Paging::resolve(uintptr_t virtAddr, bool &usermode, bool &writeable, bool &executable /* 7.5 ECTS */ ); void activate(); /* setzt das cr3 Register */
Hierbei steht die Klasse “Paging” für einen virtuellen Adressraum (z.B. den eines Threads), die Methode
map
kümmert sich auch bei Bedarf um das allokieren von PDP / PageDirectory oder PageTable. Dabei sollte man das spülen des TLBs bei Änderungen an einem aktiven Mapping nicht vergessen.- am Anfang sollte zuerst ein Mapping aufgesetzt und mit den Kernel getestet werden. Wenn das tut, so soll jeder Thread sein eigenes Mapping bekommen. Die ganzen (dynamischen) Verwaltungsstrukturen dazu sollten natürlich im Kernel liegen.
Denkt an die (nur schwer vorhersagbare) Initialisierungsreihenfolge von Konstruktoren von globalen Objekten – wenn ihr im Thread-Konstruktor auf euren Page Frame Allocator zugreift, ist er zu diesem Zeitpunkt schon initialisiert? Da unsere Threads ihren User- und Kernel Stack nun eh bequem über den Page Frame Allocator beziehen können (statt dem statisch allokierten 4K), kann man in der
main
nun ganz einfach neue Anwendungen dynamisch erstellen, zu einem Zeitpunkt in dem der Page Frame Allocator schon initialisiert ist:- Solltet ihr einen Page Fault haben, so schaut euch neben
cr2
auch dencontext->error_code
im Interrupt Handler an, der verrät mehr über den Fehler - für 7.5 ECTS: Das NX Bit muss über das EFER MSR erst aktiviert werden, und dazu muss zuvor (via
cpuid
) geprüft werden, ob dieses Feature überhaupt existiert. wer
object/vector.h
verwendet – die Methodenfront
undback
haben einen kleinen Fehler, der Patch hierzu--- a/object/vector.h +++ b/object/vector.h @@ -78,14 +78,14 @@ template<class T> class vector { * \return first element or T() if none */ inline T& front() { - return 0 == _size ? _element[0] : _invalid; + return 0 == _size ? _invalid : _element[0] ; } /*! \brief Access the last element * \return last element or T() if none */ inline T& back() { - return 0 == _size ? _element[_size - 1] : _invalid; + return 0 == _size ? _invalid : _element[_size - 1]; } /*! \brief direct access to the underlying array @@ -305,18 +305,24 @@ template<class T> class vector { } bool operator==(const vector<T>::iterator& other) const { - return *i == *other.i; + return i == other.i; } bool operator!=(const vector<T>::iterator& other) const { - return *i != *other.i; + return i != other.i; } }; + /*! \brief Iterator to beginning + * \return Iterator pointing to the first element in the sequence + */ inline vector<T>::iterator begin() const { return vector<T>::iterator(&_element[0]); } + /*! \brief Iterator to end + * \return Iterator pointing to the past-the-end element in the sequence + */ inline vector<T>::iterator end() const { return vector<T>::iterator(&_element[_size]); }
Danke an Jonathan für den Hinweis!