Autor Thema: Verständnisfrage zu Paging  (Gelesen 26821 mal)

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #20 am: 11. December 2014, 21:57 »
ok ich weiß noch nicht genau ob ich das verstanden habe.. ich denke aber schon.. könntest du mir dazu nur ein kleines Beispiel geben?

Wäre sehr nett..

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #21 am: 11. December 2014, 22:36 »
Was aber vor allem für mich noch ein Problem darstellt, ist, wenn ich in der Funktion zum Kontext erstellen, den Kontext dynamisch initialisiere, habe ich ja nur eine physische Adresse und kann über die nicht auf den Kontext zugreifen, um darauf zugreifen zu können, müsste ich ihne zuerts in einen anderen Kontext mappen, was irgendwie dann aber auch keinen Sinn machen würde...

OsDevNewbie

  • Beiträge: 282
    • Profil anzeigen
    • YourOS Kernel
Gespeichert
« Antwort #22 am: 11. December 2014, 23:48 »
Ein Beispiel:
Du lässt den letzten Eintrag im PD auf die PD selber zeigen (d.h. es steht dort im Prinzip das selbe wie im CR3).
Dann kannst du über folgende Addresse deine PD bearbeiten: 0xFFFFF000.
Die einzelnen PTs kannst du über folgende Addresse bearbeiten: 0xFFC00000 + (Index des PT << 12).

Somit kannst du dann auch ganz einfach deine Paging Tabellen bearbeiten und auch deine Kontext mappen (dabei suchst du dir eine freie virtuelle Addresse und bearbeitest dann den entsprechenden Eintrag).

Ich hoffe ich konnte dir helfen.
Viele Grüsse
OsDevNewbie

Ein Computer ohne Betriebsystem ist nicht mehr wert als ein Haufen Schrott.
Ein Computer ist eine Maschine, die einem Lebewesen das kostbarste klaut, was sie selber nicht hat:
DIE ZEIT DES LEBENS

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #23 am: 11. December 2014, 23:50 »
Was aber vor allem für mich noch ein Problem darstellt, ist, wenn ich in der Funktion zum Kontext erstellen, den Kontext dynamisch initialisiere, habe ich ja nur eine physische Adresse und kann über die nicht auf den Kontext zugreifen, um darauf zugreifen zu können, müsste ich ihne zuerts in einen anderen Kontext mappen, was irgendwie dann aber auch keinen Sinn machen würde...
Ja, wenn du Mappings für ein anderes als das aktive PD ändern willst, musst du in der Regel ein temporäres Mapping für die entsprechenden Page Tables machen.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #24 am: 11. December 2014, 23:57 »
Ein Beispiel:
Du lässt den letzten Eintrag im PD auf die PD selber zeigen (d.h. es steht dort im Prinzip das selbe wie im CR3).
Dann kannst du über folgende Addresse deine PD bearbeiten: 0xFFFFF000.
Die einzelnen PTs kannst du über folgende Addresse bearbeiten: 0xFFC00000 + (Index des PT << 12).

Achso ok, jetzt denke ich wird mir das ein bisschen klarer. Aber wenn ich das so richtig verstanden habe, geht das nur wenn der Kontext, also das Pagedirectory aktuell geladen ist oder?

Ja, wenn du Mappings für ein anderes als das aktive PD ändern willst, musst du in der Regel ein temporäres Mapping für die entsprechenden Page Tables machen.

Da liegt aber genau mein Problem.. wie setzte ich so ein temporäres Mapping genau auf? Theoretisch ist es mir klar, aber praktisch hab ich da irgendwie noch so meine Probleme..

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #25 am: 12. December 2014, 00:07 »
Ok, ich hab grade rausgefunden, dass der Ansatz den ich ursprünlich hatte, gar nicht so falsch war wie er für mich ausgesehen hat... Mein Ansatz

#define CURENT_PD     1023 * 1024 + 1023 * PAGE_SIZE // 0xFFFFF000

ergibt bei einer PAGE_SIZE von 4096 nämlich genau die Adresse die du in dem Beispiel genannt hast, aber ich dachte irgendwie dass ich da was anderes gemacht habe, als das was du beschrieben hast. Ich dachte dass dann der letzte PT auf mein PD zeigt, was ja eigentlich aber nichts anderes ist, als der letzte Eintrag des PD's... sollte man eigentlich durch ein bisschen nachdenken draufkommen.

Jetz muss ich nur noch rausfinden wie ich das mit den ganzen (temporären) Mappings hinkriege. Danke schonmal :DD
« Letzte Änderung: 12. December 2014, 00:31 von s137 »

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #26 am: 12. December 2014, 00:30 »
Ich habe es jetzt so gelöst, dass beim aktivieren eines Speicherkontextes, das PD des Kontextes, auch gleich gemappt wird. Allerdings habe ich immernoch ein Problem auf den Speicherkontext selbst zuzugreifen (beim Erstellen) ich kann zwar auf das PD des aktuellen Tasks zugreifen allerdings habe ich nirgends die virtuelle Adresse des Speicherkontextes selbst..

// Kontext erstellen
struct vmm_context* vmm_create_context(void)
{
    struct vmm_context* context = pmm_alloc(); // Dynamisch initialisiert
    int i;

    context->pagedir_phys = pmm_alloc(); // Hier ist der Zugriff über die physische Adresse des Kontextes, der den Pagefault auslöst...

    for (i = 0; i < 1024; i++) {
        context->pagedir_phys[i] = 0; // Hier nochmals...
    }

    return context; // Physische Adresse des Kontextes wird zurückgegeben
}

 

« Letzte Änderung: 12. December 2014, 00:34 von s137 »

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #27 am: 12. December 2014, 01:04 »
Sobald du Paging aktiviert hast, musst du alles, was du mittels pmm_alloc() allokierst, mappen bevor du darauf zugreifen kannst. Also technisch gesehen freie Einträge in einer Page Table suchen und dort die eintragen. Das bereits vorgeschlagene Vorgehen einfach in den Page Tables nach einem unbelegten Eintrag herumzusuchen erfüllt diesen Zweck. Wenn du einen unbenutzen Eintrag findest, trägst du die physische Seite (= das Ergebnis von pmm_alloc) sowie die passenden Flags da ein und anhand der Stelle wo du es in der Page Table eingetragen hast, weißt du, was die dazugehörige virtuelle Adresse ist. Diese nutzt du anschließend um dadrauf zuzugreifen.

Es wäre aber vermutlich besser eine Speicher*verwaltung* zu schreiben, die den ganzen Kram abstrahiert. Zum Beispiel, willst du nicht einen x-beliebigen Eintrag nutzen. Du willst eventuell Einträge nur temporär nutzen bzw. mehrfach nutzen. Kompliziert ... (Igitt! Softwareentwicklung, geh weg, ich mach hier Lowlevel!)
Dieser Text wird unter jedem Beitrag angezeigt.

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #28 am: 12. December 2014, 07:51 »
Ich habe diese zwei Dinge jetzt einfach mal ganz dreist kombiniert. Ist zwar noch etwas unsauber aber ich denke es könnte so funktionieren...

Ich habe jetzt quasi eine Funktion um eine Page zu mappen (und ja ich lasse Doppelmappings zu wenn ich es explizit so will also auf eine gewisse Adresse, ja ich weiß etwas unsauer aber für den Anfang gehts)

Eine Funktion zum Erstellen eines Kontextes, die den zu erstellenden Kontext und das zu erstellende PD temporär in den aktuellen Kontext mappt, das PD mit nullen befüllt und dann die physische Adresse zurückgibt, sowie diese an einer bestimmten virtuellen Adresse speichert.

Eine Funktion zum Aktivieren des Aktuellen Kontexts und mappen des aktuellen PD's.

Eine vmm_alloc, die mithilfe einer anderen Funktion aufeinanderfolgende Pages im Kernel oder Usermemory findet, diese mappt und die Speicheradresse zurückgibt.

Könnte das so funtionieren eventuell?

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #29 am: 12. December 2014, 09:25 »
Ich glaube, ich würde die Funktion zum Erstellen des Kontexts sowohl die physische als auch virtuelle Adresse zurückgeben lassen anstatt die virtuelle Adresse als Parameter reinzugeben, aber das ist nur, weil ich das angenehmer zu benutzen fände.

Ansonsten könnte das so funktionieren. Nimmt dein vmm_alloc() dann einen Parameter für den Kontext, in dem gemappt werden soll oder ist das nur für den aktiven?
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #30 am: 12. December 2014, 11:11 »
Naja stimmt eigentlich, aber ich werde das jetzt erst einmal so ausprobieren, um zu sehen obs so überhaupt funktionieren würde.

Meine vmm_alloc nimmt als Parameter, einen Speicherkontext, die Anzahl der Pages, die zu allokieren sind und die Flags. Aus den Flags lese ich dann ob ich Speicher im Usermemory (U/S Bit gesetzt) oder Speicher im Kernelmemory (U/S Bit nicht gesetzt) reservieren muss. Am Ende gebe ich dann die virtuelle Adresse des allokierten Speicher zurück.

Außerdem verwende ich eine noch eine extra Funktion, die am Anfang den kernel_context erstellt und mit physischen Adressen arbeitet. 

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #31 am: 12. December 2014, 18:25 »
Ich habe das jetzt mal folgendermaßen umgesetzt, ja ich weiß vermutlich extrem unübersichtlich und uneffizient... Aber im Momemnt geht es mir nur um die Funktionalität, die aber leider immernoch nicht gegeben ist.

Woran könnte das liegen... Ich habe schon so ziemlich alles als Fehlerquelle ausgeschlossen.

Mein Log des Pagefaults bei dem er abbricht sieht so aus und im Code ist die Stelle des Abbruchs gekennzeichnet:

Exception: 14 ( Page Fault)
Error Code: 2

ebp: 127164
eip: 10102c (im Code markiert)
cs: 8
eflags: 210006
esp: 4fdc00
ss: 4fcc00

// Kontext erstellen
struct vmm_context* vmm_create_context(void)
{

    struct vmm_context* context = pmm_alloc();
    int i;

    vmm_map_page((void*)((uintptr_t)CURRENT_CONTEXT), NEW_CONTEXT, (uintptr_t) context, PTE_PRESENT | PTE_WRITE);

    struct vmm_context* context_temp = (void*)((uintptr_t)NEW_CONTEXT);

    //Pagedir in gemapptem Kontext initialisieren
    context_temp->pagedir_phys = pmm_alloc();

// Irgendwo hier dazwischen bei einer Assemblerinstruktion gibt es den Page Fault

    // Pagedir in aktuellen Kontext temporaer mappen
    vmm_map_page((void*)((uintptr_t)CURRENT_CONTEXT), TEMP_PAGEDIR, (uintptr_t) context_temp->pagedir_phys, PTE_PRESENT | PTE_WRITE);

    context_temp->pagedir = (void*)((uintptr_t)TEMP_PAGEDIR);

    for (i = 0; i < 1024; i++) {
        context_temp->pagedir[i] = 0;
    }

    // Dauerhaftes Mapping
    // Physische Adresse des Kontextes speichern an bestimmter speicheradresse in sich selbst
    vmm_map_page((void*)((uintptr_t)NEW_CONTEXT), CURRENT_CONTEXT, (uintptr_t) context, PTE_PRESENT |$

    // Physische Adresse des PD's speichern an bestimmter Speicheradresse in sich selbst
    vmm_map_page((void*)((uintptr_t)NEW_CONTEXT), CURRENT_PD, (uintptr_t) context->pagedir_phys, PTE_PRESENT | PTE_WRITE);

    // Temporaere Mappings aufheben
    vmm_unmap_page((void*)((uintptr_t)CURRENT_CONTEXT), TEMP_PAGEDIR);

    return context; // Physische Adresse des Kontextes zurueckgeben

}

Noch eine Erklärung zu den Konstanten:
CURRENT_PD bezeichnet die Speicheradresse des aktuellen PD's wenn es in sich selbst gemappt ist
CURRENT_PT_BASE ist die Basis zur Berechnung der Adressen der PT's (noch nicht benutzt)
CURRENT_CONTEXT ist der aktuelle Kontext in sich sebst gemappt
NEW_CONTEXT wird in "create_context" erstellt und wir dafür benutzt den neu erstellten Kontext im aktuellen zu mappen
TEMP_PAGEDIR ist die Adresse eines temporären Mappings des PD's

#define CURRENT_PD         1023 * 1024 + 1023 * PAGE_SIZE // 0xFFFFF000
#define CURRENT_PT_BASE    0xFFC00000
#define CURRENT_CONTEXT    1023 * 1024 + 1022 * PAGE_SIZE // 0xFFFFE000
#define NEW_CONTEXT        1023 * 1024 + 1021 * PAGE_SIZE // 0xFFFFD000
#define TEMP_PAGEDIR       1023 * 1024 + 1020 * PAGE_SIZE // 0xFFFFC000

« Letzte Änderung: 12. December 2014, 18:27 von s137 »

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #32 am: 12. December 2014, 18:48 »
Wie kommst du auf 1023 * 1024 + 1023 * PAGE_SIZE und die anderen Formeln? Das Ergebnis ist eher in der Region von 5000000 aber nicht 0xFFFFF000.
Dieser Text wird unter jedem Beitrag angezeigt.

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #33 am: 12. December 2014, 19:07 »
Gute Frage, die Formeln sind natürlich falsch, ich hab nur ein Zahlenbeispiel verwendet um sie zu testen, vermutlich hatte ich da Glück ^^ oder ich hab mich da schon verrechnet...

Naja so müsste es gehen, ich teste das mal:

define CURRENT_PD         (1024 * 1024 * PAGE_SIZE) - (1 * PAGE_SIZE) // 0xFFFFF000
#define CURRENT_PT_BASE    0xFFC00000
#define CURRENT_CONTEXT    (1024 * 1024 * PAGE_SIZE) - (2 * PAGE_SIZE) // 0xFFFFE000
#define NEW_CONTEXT        (1024 * 1024 * PAGE_SIZE) - (3 * PAGE_SIZE) // 0xFFFFD000
#define TEMP_PAGEDIR       (1024 * 1024 * PAGE_SIZE  - (4 * PAGE_SIZE) // 0xFFFFC000


Zwar nicht die beste implementierung und nicht sehr dynamisch aber richtig sollte es zumindest sein :DD

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #34 am: 12. December 2014, 19:11 »
Edit: jetzt bekomme ich einen: "Warnung: Ganzzahlüberlauf in Ausdruck [-Woverflow]" was auch immer das ist... vermutllich ist die Konstante zu groß? Also eigentlich gedacht für unsigned int aber zu groß für int... Müssen Konstanten zwingend int sein? Gibt es vielleicht noch eine andere Möglichkeit für mich das zu lösen?

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #35 am: 12. December 2014, 19:28 »
So ist es. 1024 * 1024 * 4096 = 2^32 -> passt nicht mal mehr in ein unsigned int.

Alternative Methoden die Adresse der letzten Page zu berechen:

(1024 * 1024 - 1) * PAGE_SIZE
oder
((1023 * 1024) + 1023) * PAGE_SIZE
oder verallgemeinert:
((PD_INDEX * 1024) + PT_INDEX) * PAGE_SIZE
Dieser Text wird unter jedem Beitrag angezeigt.

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #36 am: 12. December 2014, 19:32 »
Hmm ok...aber das ist doch eine Speicheradresse unter 4GB sprich die sollte nicht großer als 32bit sein oder verstehe ich da was falsch..?

Danke :DD

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #37 am: 12. December 2014, 19:54 »
Ja, 32-Bit Speicheradressen passen in ein 32-Bit Integer. Die Zahl 2^32 (= 4 GB) passt aber nicht in ein 32-Bit vorzeichenloses Integer, weil dort eben das Maximum 2^32-1 ist.
Dieser Text wird unter jedem Beitrag angezeigt.

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #38 am: 12. December 2014, 20:00 »
Naja aber es geht ja auch nicht um die Zahl 4GB, alle meine Zahlen liegen ja unter dem Limit 2^32-1... das heißt es müsste doch funktionieren wenn meine Konstanten statt int, unsigned int sein könnten... oder?

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #39 am: 12. December 2014, 20:01 »
Edit: kann es sein das bei der Berechnung selbst schon der Overflow auftritt und ich, wenn ich einfach die Methode der berechnung ändere das umgehen kann?

 

Einloggen