Paging - Realisierung

Low-Level-Programmierung und Experimenteller Kernel; Ansprechpartner: Dirty Oerti
Benutzeravatar
Dirty Oerti
Beiträge: 2229
Registriert: Di Jul 08, 2008 5:05 pm
Wohnort: Thurndorf / Würzburg

Paging - Realisierung

Beitrag von Dirty Oerti » Do Okt 02, 2008 9:55 pm

Tag! :)

Ich überlege gerade (bzw den Tag über schon und gestern^^), wie ich Paging besser in den Kernel einbaue.
Bis jetzt ist es mehr oder weniger nur implementiert, damit es drinn ist und man sieht, dass es funktioniert.

Die Problematik besteht darin, dass ich nicht mehr auf die PageDirectories und PageTables zugreifen kann, sobald ich Paging aktiviere.
Zu diesem Problem kenne ich zwei verschiedene Lösungen:

1. Ich mappe das Pagedirectory selbst im Pagedirectory wie eine Pagetable (ich hoffe das versteht irgendwer^^).
Dadurch habe ich Zugriff auf das Directory und damit auch auf die einzelnen Pages.
Vorteil: Relativ einfach zu implementieren und ich versteh's ein bisschen:)
Nachteil: Es können dadurch 256 MB weniger benutzt werden (des virtuellen Speichers!! nicht physikalischer!!).


2. Ich speichere mir sowohl physikalische als auch virtuelle Adresse in einer Datenstruktur ab und...ja..kp.
Vorteil: Es heißt, das man dadurch nur 4 KB mehr braucht.
Nachteil: Ich weiß nicht wirklich wie's funktioniert.

Woher ich das 2. Konzept habe? Aus einem Tutorial, das ich sehr gut finde:
http://www.jamesmolloy.co.uk/tutorial_h ... aging.html
Ich habe sogar Beispielcode. Aber iwie versteh ich es nicht wirklich.


Mir fehlt auch noch ein grundsätzlicher Aufbau, wie die Zusammenhänge funktionieren sollen.
Das werde ich versuchen in der nächsten Zeit mal auf die Reihe zu bringen.

(Wenn jemand weiß, wie die 2. Methode funktioniert oder wenn jemand eine andere Idee hat, dann her damit :) )

MfG
Daniel
Bei Fragen einfach an daniel[ät]proggen[Punkt]org
Ich helfe gerne! :)
----------
Wenn du ein Licht am Ende des Tunnels siehst, freu dich nicht zu früh! Es könnte ein Zug sein, der auf dich zukommt!
----
It said: "Install Win95 or better ..." So I installed Linux.

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8858
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Paging - Realisierung

Beitrag von Xin » Do Okt 02, 2008 10:52 pm

Dirty Oerti hat geschrieben:1. Ich mappe das Pagedirectory selbst im Pagedirectory wie eine Pagetable (ich hoffe das versteht irgendwer^^).
Ich gebe zu, ich tue mich schwer... ich für meinen Teil bin in der Materie nicht mehr wirklich drin, zumal Du vermutlich inzwischen da weiter drin bist, als ich jemals.

Ich warte ja nicht umsonst gespannt darauf, die Artikel in Deinem Wiki-Namespace zu lesen. ^^
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Benutzeravatar
Dirty Oerti
Beiträge: 2229
Registriert: Di Jul 08, 2008 5:05 pm
Wohnort: Thurndorf / Würzburg

Re: Paging - Realisierung

Beitrag von Dirty Oerti » Sa Okt 04, 2008 10:30 am

Ich versuche mich jetzt an der ersten Lösung.
:)

Das ist alles ganz schön, aber irgendwie will es nicht klappen, ein neues Page Directory anzulegen (ein zweites, drittes ... für neue Tasks), ohne das ich gezwungen werde, Paging kurz auszuschalten.

Nun sind die Anweisungen dazu nicht besonders komplex etc. Von der Seite her würde nichts dagegen sprechen, Paging einfach kurz auszumachen und dann wieder anzumachen.

Allerdings wird, soweit ich weiß, dann der TLB (Translation Look Aside Buffer) ungültig, was heißt dass die nächsten Page Faults langsamer bearbeitet werden, bzw ich muss vorher den TLB sogar leeren.

Allerdings kommt mir gerade beim schreiben hier der Einfall, dass ich das eh tun muss, wenn ich ein neues Page Directory setze...
Denke ich zumindest.

Xin hat geschrieben:Ich gebe zu, ich tue mich schwer... ich für meinen Teil bin in der Materie nicht mehr wirklich drin, zumal Du vermutlich inzwischen da weiter drin bist, als ich jemals
Ich konnte mir das auch erst vorstellen, nachdem ich mir das Ganze auf Papier mehrfach hingekritzelt hatte^^
Xin hat geschrieben:Ich warte ja nicht umsonst gespannt darauf, die Artikel in Deinem Wiki-Namespace zu lesen. ^^
Sie werden kommen, die Einträge :)
Bei Fragen einfach an daniel[ät]proggen[Punkt]org
Ich helfe gerne! :)
----------
Wenn du ein Licht am Ende des Tunnels siehst, freu dich nicht zu früh! Es könnte ein Zug sein, der auf dich zukommt!
----
It said: "Install Win95 or better ..." So I installed Linux.

Benutzeravatar
Dirty Oerti
Beiträge: 2229
Registriert: Di Jul 08, 2008 5:05 pm
Wohnort: Thurndorf / Würzburg

Re: Paging - Realisierung

Beitrag von Dirty Oerti » So Okt 05, 2008 11:10 am

Die erste Lösung funktioniert soweit.
Bzw, theoretisch.

Ich habe gestern nur eine Kleinigkeit vergessen (neue PageTables wollen auch allokiert und eingetragen werden..) und hatte keine Zeit mehr, dass zu richten (Gäste im Haus). Das kommt heute dran :)

Bis jetzt sieht es also so aus:

Ich lasse absichtlich einen PageFault passieren, das heißt mein PageFault Handler wird aufgerufen.
Der speichert sich die (virtuelle) Adresse, auf die zugegriffen werden wollte, und guckt erstmal warum den ein PageFault passiert ist.
Ist der Fault passiert, weil die Page einfach nicht als "Present" markiert ist (und sich folglich nicht im Speicher befindet und in meinem Fall damit noch nicht gesetzt wurde), dann muss ein neuer Frame allokiert werden, auf den dann die Page gemappt wird.
Schön soweit.

Wenn ich aber (im 1023. Eintrag im PageDirectory liegt das PageDirectory selbst) auf das PageDirectory zugreife, und dann auf eine PageTable...und die noch nicht im Speicher ist...
Dann kommt ein neuer PageFault im PageFault Handler.
Das heißt soviel wie "tot" ^^
Bei Fragen einfach an daniel[ät]proggen[Punkt]org
Ich helfe gerne! :)
----------
Wenn du ein Licht am Ende des Tunnels siehst, freu dich nicht zu früh! Es könnte ein Zug sein, der auf dich zukommt!
----
It said: "Install Win95 or better ..." So I installed Linux.

Benutzeravatar
Dirty Oerti
Beiträge: 2229
Registriert: Di Jul 08, 2008 5:05 pm
Wohnort: Thurndorf / Würzburg

Re: Paging - Realisierung

Beitrag von Dirty Oerti » Di Okt 07, 2008 4:38 pm

Ok, ich weiß jetzt warum es nicht funktionierte:

Meine Funktionen zum Ansprechen der (virtuellen) Speicheradresse des PageDirectory/der PageTables stimmte nicht.
Drauf gekommen bin ich so:
Eine Adresse (unsigned int*) besteht aus 32 Bit.
Die vordersten 10 bezeichnen die Nummer der PageTable.
Die 10 danach bezeichnen die Nummer der Page in der jeweiligen Table.

Dann bleiben 12 übrig.
Diese 12 werden nicht, wie von mir fälschlicherweise angenommen, ebenfalls wie Nummerierungen betrachtet.
Sie haben 2 Bit mehr, heißt 4 mal so viele Möglichkeiten.
Heißt nicht 0-1023 sondern 0-4095...
Das heißt auch das die hinteren 12 Bit nicht in 4 Byteschritten gehen, sondern in 1 Byteschritten (das ist gar nicht so logisch, wenn man es noch nicht bemerkt hat).
Naja...das funktioniert jetzt auf jedenfall.
Hoffe ich.

Das Problem, was nun auftaucht, ist mir ziemlich...unbekannt:
Kernel hat geschrieben:GDT [OK]
IDT [OK]
ISRs [OK]
IRQs [OK]
Memory Check [OK]
FPU Check [OK]
Aktiviere Paging mit IdentityMapping [OK]

[PAGE FAULT] at 0xf000000
1
0
4
0
16

[PAGE FAULT]LL
[AUSNAHME] System gestoppt!
Invalid Opcode Exception
"Invalid Opcode Exception" ?

Ich weiß zumindest, wo der Fehler passiert:

Code: Alles auswählen

// (...)
if (present) {
   K_PSUCCESS("\n[PAGE FAULT]");
   if (GetPTEntry(1023,RESOLVE_PAGETAB(faultaddress)) == 0)  {
       K_PINFO("LL"); 

// Bis hier hin geht es noch, dann kommt die Exception/////////////////////////////////////

       SetPTEntry(1023,RESOLVE_PAGETAB(faultaddress), K_alloc(), (0x3 | (userm)) );
   }
   SetPTEntry( RESOLVE_PAGETAB(faultaddress),  RESOLVE_PAGENUM(faultaddress),
                   K_alloc(),  (0x3 | (userm)) );
   return;
}
// (...)
    }

Code: Alles auswählen

void SetPTEntry(unsigned int PT, unsigned int num, unsigned int FrameAd, unsigned short Flags)
{
    ////////////////////////////////////////
    // PT = Nummer der PageTable, in der eine Page gesetzt werden soll
    // num = Nummer der Page in der PageTable
    // FrameAd = phys Adresse
    // Flags = Einstellungen
    ////////////////////////////////////////
    unsigned int *tmp =(unsigned int*) ( ((1023)<<22) | ((PT)<<12) );
    tmp+=num;
    *tmp = (FrameAd & 0xFFFFF000) | (Flags & 0xE67);
}
Wo genau in der Funktion "SetPTEntry" der Fehler ist kann ich nicht feststellen.
Wenn ich Debugausgaben einbaue schmiert es komplett ab (Speicher wird einfach so undefiniert überschrieben, sieht man daran, dass sich der Bildschirm mit einer regelmäßigen Folge an kryptischen Zeichen füllt).

Ich habe zur Exception bis jetzt folgendes gefunden:
Die "Invalid Opcode Exception" wird generiert, falls der Execution Unit ein unbekannter Operationscode zugeführt wird
*Fragend blick* ?
Bei Fragen einfach an daniel[ät]proggen[Punkt]org
Ich helfe gerne! :)
----------
Wenn du ein Licht am Ende des Tunnels siehst, freu dich nicht zu früh! Es könnte ein Zug sein, der auf dich zukommt!
----
It said: "Install Win95 or better ..." So I installed Linux.

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8858
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Paging - Realisierung

Beitrag von Xin » Di Okt 07, 2008 5:08 pm

Dirty Oerti hat geschrieben:Ich habe zur Exception bis jetzt folgendes gefunden:
Die "Invalid Opcode Exception" wird generiert, falls der Execution Unit ein unbekannter Operationscode zugeführt wird
*Fragend blick* ?
Klingt für mich, dass Du einen invaliden Befehl in Deinem Programm hast. Ein Bitmuster, dass die CPU nicht als Befehl erkennt und sich entsprechend beschwert!?
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Benutzeravatar
Dirty Oerti
Beiträge: 2229
Registriert: Di Jul 08, 2008 5:05 pm
Wohnort: Thurndorf / Würzburg

Re: Paging - Realisierung

Beitrag von Dirty Oerti » Di Okt 07, 2008 5:15 pm

Xin hat geschrieben:
Dirty Oerti hat geschrieben:Ich habe zur Exception bis jetzt folgendes gefunden:
Die "Invalid Opcode Exception" wird generiert, falls der Execution Unit ein unbekannter Operationscode zugeführt wird
*Fragend blick* ?
Klingt für mich, dass Du einen invaliden Befehl in Deinem Programm hast. Ein Bitmuster, dass die CPU nicht als Befehl erkennt und sich entsprechend beschwert!?
Hört sich auch für mich so in etwa an.
Aber welcher Befehl soll das denn sein?!?

Ich hatte zwischen durch noch ein paar Ideen, woran es liegen könnte:

1. Ich erinnere mich gelesen zu haben das es notwendig sein kann, den Instruction Pointer um eins nach hinten zu setzen, bevor man aus der Interrupt Routine zurückkehrt.
Könnte es damit etwas zu tun haben?
Wobei der Fehler ja IN der Routine passiert, und nicht danach.

2. Ist es vllcht nicht möglich, Funktionen aus der Interrupt Routine herraus aufzurufen?
Kann ich aber nich glauben, die Funktion "GetPTEntry" funktioniert ja auch...
Und die Ausgabefunktionen...

3. Könnte es an der Speicherzuweisung liegen?
Irgendwas mit Pointern?

4. Oder auch: Ist die Anzahl der Argumente vllcht zu groß?
Also die Anzahl der Argumente für den Funktionsaufruf?
Ich könnte den Stack vergrößern...

5. So absurd das klingt, aber kann es sein, dass "+=" nicht funktioniert?
Ich habe Sachen über Befehle mit LOCK-Prefix gelesen, die bei falscher Anwendung so eine Exception verursachen können.

EDIT
Habe so eine leise Ahnung woran es liegen könnte....vllcht fehlt einfach nur ein Return?
Denn:
Ändere ich die Funktion so ab:

Code: Alles auswählen

void SetPTEntry(unsigned int PT, unsigned int num, unsigned int FrameAd, unsigned short Flags)
{
    ////////////////////////////////////////
    // PT = Nummer der PageTable, in der eine Page gesetzt werden soll
    // num = Nummer der Page in der PageTable
    // FrameAd = phys Adresse
    // Flags = Einstellungen
    ////////////////////////////////////////
    K_PSUCCESS("b");
    K_PINFO("x");
    unsigned int *tmp =(unsigned int*) ( ((1023)<<22) | ((PT)<<12) );
    K_PSUCCESS("r");
    tmp+=num;
    K_PINFO("d");
    *tmp = (FrameAd & 0xFFFFF000) | (Flags & 0xE67);
}
Dann erhalte ich folgende Ausgabe (nur die Ausgabe aus dieser Funktion heraus)
bxrdbxrd
(Die einzelnen Buchstaben sind eigntl noch farblich unterschiedlich, aber das tut nichts zur Sache.)

Ich versuch jetzt einfach mal das mit einem return hinzubekommen :)
Bei Fragen einfach an daniel[ät]proggen[Punkt]org
Ich helfe gerne! :)
----------
Wenn du ein Licht am Ende des Tunnels siehst, freu dich nicht zu früh! Es könnte ein Zug sein, der auf dich zukommt!
----
It said: "Install Win95 or better ..." So I installed Linux.

Benutzeravatar
Dirty Oerti
Beiträge: 2229
Registriert: Di Jul 08, 2008 5:05 pm
Wohnort: Thurndorf / Würzburg

Re: Paging - Realisierung

Beitrag von Dirty Oerti » Di Okt 07, 2008 5:55 pm

Ok, ich denke ich weiß woran es liegt.
Ich weiß aber noch nicht, wie ich es beseitigen kann.

Diese Exception scheint sich nicht auf den aktuell ausgeführten Code zu beziehen, sondern auf einen, der noch folgt. (Der Code wird im Vorraus geholt und als falsch befunden)

Die Exception bezog sich auf das

Code: Alles auswählen

return;
Diese Anweisung funktioniert anscheinend nicht.
Wenn ich das return herraus lasse ist alles ok, die Funktion stoppt bei der Endlosschleife.

Jetzt überlege ich natürlich, wie ich aus der Funktion (der Interrupt Routine) zurück in den ausgeführten Code komme.
Einfach die Endlosschleife weglassen führt zu einem totalen Chaos. (Wildes schreiben im Speicher, sichtbar am Monitor).

Ich versuche es mal mit einer Art "Jump" zum Ende der (die Interruptroutine aufrufenden) Assemblerfunktion.
Am Ende derer wird ein iret durchgeführt, was wohl das ist, was ich brauche.

Oder muss ich den Instruction Pointer nun doch erhöhen?
Wobei das laut Internet bei dieser Art von Exception (Page Fault) nicht notwendig ist.

EDIT

Ok, ich denke ich hab's.
Die Interrupt Routine wird folgendermaßen aufgerufen:

Code: Alles auswählen

isr_standard_handler:
    pusha
    push ds
    push es
    push fs
    push gs
    mov ax, 0x10   ; Lädt den Kernel Daten Segment Deskriptor
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov eax, esp   ; Push den Stack
    push eax
    mov eax, _fehler_handler ; Ruft C-Code Fehler-Handler auf
    call eax       ; Spezieller Aufruf, lässt 'eip' unberührt
    pop eax
    pop gs
    pop fs
    pop es
    pop ds
    popa
    add esp, 8     ; Aufräumen (Errorcode und ISR Nummer)
    iret           ; Pop 5 aufeinmal: CS, EIP, EFLAGS, SS, ESP
Interessant ist, wie der "C-Code Fehler-Handler" aufgerufen wird.
Nicht durch einen direkten Call, sondern durch sowas "umständliches".
Interessant auch, was ich daneben geschrieben habe ;)

Heißt es liegt doch an den Funktionsaufrufen innerhalb der Interrupt Routine.
Vielleicht kann ich das berichtigen, indem ich die Funktionen als "inline" deklariere..
Bei Fragen einfach an daniel[ät]proggen[Punkt]org
Ich helfe gerne! :)
----------
Wenn du ein Licht am Ende des Tunnels siehst, freu dich nicht zu früh! Es könnte ein Zug sein, der auf dich zukommt!
----
It said: "Install Win95 or better ..." So I installed Linux.

Benutzeravatar
Dirty Oerti
Beiträge: 2229
Registriert: Di Jul 08, 2008 5:05 pm
Wohnort: Thurndorf / Würzburg

Re: Paging - Realisierung

Beitrag von Dirty Oerti » Di Okt 07, 2008 9:45 pm

------------------------------------------------------
So :mrgreen:

Geschafft. Paging funktioniert nun.
Zumindest soweit, dass bei einem PageFault automatisch eine Page nachgeladen wird.

Der Fehler lag an einer ziemlich blöden Stelle. Ziemlich einfach, aber schwer zu finden.
Inline-Funktionen hatten nichts gebracht.
Das Problem lag daran, dass der Page Fault Handler gar nicht, wie eigntl von mir gedacht, durch die oben gezeigte ASM-Funktion aufgerufen wurde, sondern direkt.
Heißt, nach der Beendigung der Funktion wurde auch nicht in die ASM-Funktion zurückgekehrt.
Heißt wiederrum, die nötigen Befehle um den Zustand vor dem Interrupt wiederherzustellen wurden nicht ausgeführt.
Daraus folgerte das undefinierte Verhalten.

Nachdem ich das nun erkannt habe, habe ich den PageFault Handler an anderer Stelle eingebunden (per Funktionszeiger).

Nun wird der Handler durch die ASM-Funktion aufgerufen und kehrt nach Beendigung auch wieder zu dieser zurück.
Die ASM-Funktion kehrt dann an die unterbrochene Stelle zurück.

Was mein PageFault Handler nicht kann ist etwas anderes zu bearbeiten als den PageFault, der generiert wird, wenn eine Page einfach noch nicht im wirklichen (physikalischen) Speicher vorhanden ist.
Das werde ich aber mit der Zeit noch ergänzen.


Den Code (den ich im Übrigen auch ein bisschen aufgeräumt habe) findet man wie üblich im Repository.
(Revision 34)

MfG
Daniel
Bei Fragen einfach an daniel[ät]proggen[Punkt]org
Ich helfe gerne! :)
----------
Wenn du ein Licht am Ende des Tunnels siehst, freu dich nicht zu früh! Es könnte ein Zug sein, der auf dich zukommt!
----
It said: "Install Win95 or better ..." So I installed Linux.

Benutzeravatar
Dirty Oerti
Beiträge: 2229
Registriert: Di Jul 08, 2008 5:05 pm
Wohnort: Thurndorf / Würzburg

Re: Paging - Realisierung

Beitrag von Dirty Oerti » Mi Okt 15, 2008 6:10 pm

Noch eine Anmerkung:

Ich habe Code eingebaut, der den TLB invalidieren müsste, wenn bei einem PageFault eine neue Page gesetzt wird.
"Müsste", weil ich keine Ahnung habe, wie ich das überprüfen könnte.

(Revision 49)
Bei Fragen einfach an daniel[ät]proggen[Punkt]org
Ich helfe gerne! :)
----------
Wenn du ein Licht am Ende des Tunnels siehst, freu dich nicht zu früh! Es könnte ein Zug sein, der auf dich zukommt!
----
It said: "Install Win95 or better ..." So I installed Linux.

Antworten