Paging: Verständnisschwierigkeiten zum Tutorial von James Molloy



  • Siehe Tutorial von James Molloy
    http://www.jamesmolloy.co.uk/tutorial_html/6.-Paging.html, auf welches ich mich beziehe.

    Zunächst möchte ich meine Kenntnislage zum Paging darstellen.

    Der Zugriff auf physikalische Adressen erfolgt beim Paging über dreistufig verschachtelte Verweise. Dreistufig deswegen, weil einmal ein Verweis auf eine Verzeichnistabelle existiert, von der Verzeichnisrabelle ein Verweis auf eine Seitentabelle und die Seitentabelle verweist auf eine Speicherseite.

    Ich persönlich mag den irreführenden Begriff virtuell nicht, weil es in Wirklichkeit nicht virtuell ist, sondern es ist verweisorientiert und somit immer noch reell. Es ist einfach eine indirekte Adressierung.

    Das Prinzip des Paging ist sehr einfach:
    Wir haben einen Adressraum von 32 Bit. Den zergliedern wir in 12 Bit große Seiten. Das entspricht
    4 * 1024 Bytes. Die erste Seite befindet sich an der Adresse 0, die zweite Seite liegt an der Adresse 4096, die dritte Seite an der Adresse 8192 und die letzte an der Adresse 1024 * (1024 -1). Es gibt also 1024 * 1024 Seiten. Die CPU verwaltet die Seiten mittels der MMU über zwei Tabellen. Es existiert eine Verzeichnistabelle mit 1024 Einträgen zu je 32 Bit. Damit ist die Tabelle genau so groß wie eine Speicherseite, nämlich 4096 Bytes. Sie paßt dann auch exakt in eine solche Speicherseite hinein.
    Ein Verweis der Verzeichnistabelle verweist auf eine Seitentabelle mit 1024 Einträgen zu je 32 Bit.
    Haben alle Verweise der Verzeichnistabelle einen Verweis auf eine Seitentabelle, so existieren dann 1024 * 1024 Seitentabellen und eine Verzeichnistabelle, die auf 1024 * 1205 Seiten untergebracht werden müssen. Das sprengt jedoch die Kapazität des Speicherplatzes, weil maximal nur 1024 * 1024 Seiten existieren können und diese nun voll mit Tabellen belegt sind, so daß keine Seite mehr frei sein wird. Spaßeshalber kann man sich mal ausrechnen, was die größte mögliche Anzahl von verfügbaren Seiten, sind die nicht von Tabellen belegt werden und wie viel Tabellen man wirklich hierfür braucht. Mit jeder Tabelle wird eine Seite verbraucht.
    Die virtuelle bzw. verzeichnisorientierte Adressierung benutzt die beiden Indices der beiden Tabellen. 1024 Einträge werden durch 10 Bits realisiert. Somit erhält die virtuelle Adresse in den oberen Bits 22 bis 31 den Index der Verzeichnistabelle. In den Bits 12 bis 21 ist der Index der Seitentabelle und die Bits von 0 bis 11 ist der Offset, die auf eine Stelle innerhalb einer Seite verweist.

    Die Einträge in den Tabellen sind ebenfalls 32 Bit breit. Die Bits 0 bis 11 sind für Statusflags für die Seite in der Seitentabelle, als auch für die Seitentabellen in der Verzeichnistabelle reserviert, wobei die Flags dieser beiden Tabellen größtenteils identisch sind. Diese Flags geben über das Vorhandensein einer Seite oder Seitentabelle Auskunft, regeln den Zugriff usw.. In den Bits von 12 bis 31 (20 Bit) steht eigentlich was? Nun wenn eine Speicherseite mit 12 Bits eine maximale Zahl von 4096 faßt, was die Seitengröße ist, so enthalten die restlichen 12 Bits die exakt die Seitennummer. Die Seite 0 liegt an der physikalischen Adresse 0, die Seite 1 liegt an der physikalischen Adresse 4096 usw., so wie wir es oben schon einmal erwähnt hatten. Wenn wir die Seitennummer um 12 Bits nach links schieben oder im Seiteneintrag uns die Statusbits als gelöscht denken, dann haben wir exakt die physikalische Adresse. Z.B. die zweite Seite wäre Seitennummer=1 und 1<<12=4096. Auch die Einträge in der Verzeichnistabelle enthalten physikalische Adressen, wo die Seitentabelle untergebracht ist. Sie ist ihrerseits auch in einer Seite mit der gleichen physikalischen Adresse, weswegen die Einträge in der Verzeichnistabelle ebenfalls Statusbits besitzen, um den Zugriff der entsprechenden Seite, wo die Tabelle nun untergebracht ist, zu regeln.

    Man braucht einfach den Eintrag einer Seitentabelle die Statusbits löschen, indem man mit den Wert FFFFF000 auf diesen Eintrag eine UND-Operation ausführt.
    Beispiel:
    Wir wählen beispielsweise den 5. Eintrag der Verzeichnistabelle (*Verzeichnistabelle[4]) dessen Eintrag nicht Null ist, sondern auf eine Seitentabelle verweist. Davon wählen wir ebenfalls den 5. Seiteneintrag, der nicht Null ist.

    uint32 *Verzeichnistabelle[1024];
    uint32 *Seitentabelle[1024];
    
    uint32 SeitenTabellenEintrag = *Verzeichnistabelle[4] & 0xFFFFF000] // Statusbits löschen und 
                                                                                                                              // physikalische Adresse
                                                                                                                              // der Seitentabelle erzeugen
    Seitentabelle = (uint32 *)SeitenTabellenEintrag. // Seitentabelle auf diese physikalische Adresse
                                                                                        // setzen
    uint32 SeitenEintrag = *Seitentabelle[4];               // Kopie des Eintrags anfertigen
    uint32 PhysikalischeAdresse = SeitenEintrag & 0xFFFFF000; // physikalische Adresse aus der 
                                                                                                               // Kopie erzeugen
    

    Man muß vorher für die Tabellen *Verzeichnis und *Seiten auf den physikalischen Speicher Speicherplatz reservieren, wobei die Adressen ein Mehrfaches von 4096 sein muß, damit die Tabellen genau in eine Seite gelegt werden können und sich nicht überschneiden. Man nennt es pagealign. Diese Tabellen müssen dann an diese Adressen verschoben werden, weswegen sie dynamische Variablen sind.

    Über PDBR erhält die CPU einen Verweis auf die Adresse der Verzeichnistabelle, und somit erreicht man die drei Stufen, um die physikalische Adresse einer Seite zu ermitteln. Durch die Tabellenstruktur müssen die Seiten nicht mehr der Reihenfolge physikalischer Adressen entsprechen. Ja sie können sogar ausgelagert werden auf Massenspeicher wie Festplatten etc..
    Dadurch nutzt man noch andere Speichermedien, wodurch sich der Adressraum erweitert. Da aber nur 32 Bit adressiert werden kann, müssen dann Seiten ein- bzw. ausgelagert werden. Theoretisch ist es möglich, daß in einer Seitentabelle zwei Einträge auf die gleiche physikalische Seite zeigen. Bei der Organisation der Seiteneinträge in den Seitentabellen ist zu achten, daß dieses eventuell nicht passiert, weil sonst die Statusbits in Konflikt miteinander kommen könnten. Z.B. wäre es möglich, daß zwei verschiedene virtuellen Adressen auf die gleich physikalische Seite zeigen, wo jedoch bei der einen virtuellen Adresse sie als nur lesbar erweist, während bei der anderen virtuellen Adresse sowohl lesbar als auch beschreibbar sein kann. Gegebenfalls könnte man diese Situation auch beabsichtigen. Merkwürdig wäre es jedoch, wenn die eine Adresse sagt, daß die Seite im Speicher nicht präsent ist, jedoch dagegen die andere Adresse es als präsent ausweist. Aber auch das kann gewollt sein.

    Soweit zu meinen Verständnis.

    Schwierigkeiten jedoch habe ich beim Verstehen des Codes von James Molloy, welches er in einen Tutorial angegeben hatte. Da fehlt mir einiges. Es geht um die Initialisierung bzw. die Zuweisung physikalischer Adressen in den Seiten. Außerdem sind sehr grobe Fehler enthalten. Die Seitentabellen haben bei ihren Einträgen ein falsches Format. Ein weitere Fehler ist, daß bei der Seiteninformation der Offset (Rest) einer virtuellen Adresse eingetragen wird, anstatt einer physikalischen Adresse!

    Was ich im Tutorial von James Molloy vermisse und was nicht korrekt ist:

    1. Tabellenorganisation. Jede Tabelle verbraucht eine Seite! Es muß also die geeignete Anzahl
      ermittelt werden, um möglichst viele Seiten herauszuholen, die nicht von den Seitentabellen belegt werden. James Molloy benutzt einen Bitvektor frame, der Auskunft über belegte Seiten gibt. Bei der Tabellenorganisation müssen für jede erzeugte Seitentabelle dieses im Bitvektor frame berücksichtigt werden, da eine Seitentabelle selbst eine Seite verbraucht.
    2. Die Seitentabellen fehlen, auf welche die Verzeichniseinträge verweisen. Es werden zwar Seitentabellen erzeugt, die jedoch nicht den erforderlichen Aufbau haben mit Seiteneinträgen von 32 Bit sondern 224 Bit und somit ein für die MMU ein ungültiges Format haben. Fehlerhaft ist es,
      wenn man in die Verzeichniseinträge die physikalischen Adressen der Seiten einträgt, die ebei den Seiteneinträgen ein falsches Format haben. Bei James Molloy haben sie eine Bitlänge 224 Bit, anstatt von 32 Bit.
    3. Es fehlen die Zuweisung jener Seitentabellen mit 32 Bit Einträgen in die Verzeichnistabelle.
    4. Das Eintragen der physikalischen Adressen und die Statusbits in den Seitenverweisen einer Seitentabelle fehlt.
    5. Das Schreiben in den Videobereich ab der physikalischen Adresse 0xB8000. Wenn das Paging Bit gesetzt ist, gilt nicht mehr die alte physikalische Adressierung. Folglich muß man dafür Sorge tragen, daß für den Videobereich entsprechende Seitenbereiche für den Kernel verfügbar gemacht werden müssen, um gegebenfalls bei einer nun entsprechenden virtuellen Adresse auf den Videospeicher zugreifen zu können. Bei einen Zugriff auf die Adresse 0xB8000 würde gegebenfalls eine Pagefault ausgelöst werden und eine Fehlermeldung wäre noch nicht einmal möglich, anzuzeigen.

    Folglich komme ich zum Schluß, daß James Molloy Paging nicht funktionieren kann!

    Analyse des Codes, von James Molloy:

    James Molloy wählt für eine Seite die Datenstruktur

    typedef struct page
    {
        ULONG present    :  1;   // Page present in memory
        ULONG rw         :  1;   // 0: read-only,    1: read/write
        ULONG user       :  1;   // 0: kernel level, 1: user level
        ULONG accessed   :  1;   // Has the page been accessed since last refresh?
        ULONG dirty      :  1;   // Has the page been written to since last refresh?
        ULONG unused     :  7;   // Combination of unused and reserved bits
        ULONG frame_addr : 20;   // Frame address (shifted right 12 bits)
    } page_t;
    

    Dieses entspricht nicht den geforderten Eintrag in eine 32 Bit Seitenverweis. Ein solcher fehlt.
    Man kann zwar diese Struktur intern benutzen, um Bitoperationen zu vermeiden, jedoch muß diese Struktur auf ein 32 Bit Seitenverweis abgebildet werden. Das fehlt jedoch im Code von James Molloy.

    für die Seitentabelle gibt es die Struktur

    typedef struct page_table
    {
        page_t pages[1024];
    } page_table_t;
    
    

    Wir bräuchten hier noch eine Seitentabelle von 32 Bit Seiteneinträgen, die jedoch fehlt.
    Für das Tabellenverzeichnis haben wir die Struktur

    typedef struct page_directory
    {
        page_table_t* tables[1024];
        ULONG tablesPhysical[1024];
        ULONG physicalAddr;
    } page_directory_t;
    
    

    Hier ist auch etwas auszusetzen! Man könnte jedoch die letzten beiden unteren Variablen auslagern.
    tablesPhysical müßte jedoch ein Zeiger sein, damit es mit k_malloc pagealign allokiert werden kann.

    Für die CPU ist nur

    ULONG tablesPhysical[1024];
    
    

    relevant.

    Eigentlich bräuchte man nur

    ULONG *tablesPhysical[1024];
    ULONG *pagesPhysical[1024];
    

    geben, da nur sie von der MMU verwaltet werden können. Das würde meinen obigen Erklärungen

    uint32 *Verzeichnistabelle[1024];
    uint32 *Seitentabelle[1024];
    

    entsprechen. Man muß dafür sorgen, daß diese beiden Tabellen page-aligned im Speicher angeordnet werden, wie ich es oben schon beschrieben hatte.

    Im letzten Verweis, d.h. in der Page kann jede beliebige physikalische Adresse stehen, die jedoch ebenfalls "page align" sein muß, was ich oben ebenfalls schon beschrieben hatte. Ich vermisse bei der Initialisierung den Eintrag jener Adresse mit den entsprechenden Zugriffsattributen, bzw. eine Funktion, die dieses nach dem Setzen des Pagingbits explizit später tut. Bei der Initialisierung könnten sie zunächst erst einmal Null sein. Das wird wohl James Molloy erst einmal tun, wie wir es später noch sehen werden, wo keine Seite zunächst verfügbar ist. Ich muß also die Möglichkeit haben, dort eine physikalische Adresse einzutragen, um später auf eine bestimmte physikalische Speicherseite zugreifen zu können. Es fehlt also die Funktion setpage(...).

    Weiteres Kopfzerbrechen bereitet mir die Verwendung des Ausdrucks von virtuell und physikalisch in seinen Tutorial. Bevor ich das Paging Bit setze, werden die Tabellen initialisiert und somit sind die Adressen bzw. die Verweise physikalische Adressen (eigentlich auch virtuell, da sie über die Deskriptortabelle ebenfalls verweisorientiert sind), sofern man sich die Statusbits wegdenkt. Nach dem Setzen des Paging Bits wird jedoch die Adressierung anders sein. Doch ich denke, daß die interne Speicherverwaltung der CPU (MMU) die Verweise in den Tabellen als physikalisch interpretiert und nicht virtuell, wie James Molloy es beschreibt.

    Die Funktion k_malloc

    ULONG k_malloc(ULONG size, UCHAR align, ULONG* phys)
    {
        if( kheap!=0 )
        {
            void* addr = alloc(size, align, kheap);
            if (phys != 0)
            {
                page_t* page = get_page((ULONG)addr, 0, kernel_directory);
                *phys = page->frame_addr * PAGESIZE + ((ULONG)addr&0xFFF);
            }
            return (ULONG)addr;
        }
        else
        {
            if( !(placement_address == (placement_address & 0xFFFFF000) ) )
            {
                placement_address &= 0xFFFFF000;
                placement_address += PAGESIZE;
            }
    
            if( phys )
            {
                *phys = placement_address;
            }
            ULONG temp = placement_address;
            placement_address += size;     // new placement_address is increased
            return temp;                   // old placement_address is returned
        }
    }
    
    

    liefert offenbar physikalische Adressen, da auch die Funktion alloc(size, align, kheap) sich auf das placement bezieht oder bezüglich der Variable heap auf physikalische Anfangs- und Endadressen des lokalen Heaps, da mehrere Heaps eingerichtet werden können.

    James Molly hat nur eine Funktion, um eine Seite laden zu können, und das ist getpage()

    page_t* get_page(ULONG address, UCHAR make, page_directory_t* dir)
    {
        address /= PAGESIZE;                // address ==> index.
        ULONG table_index = address / 1024; // ==> page table containing this address
    
        if(dir->tables[table_index])       // table already assigned
        {
            return &dir->tables[table_index]->pages[address%1024];
        }
        else if(make)
        {
            ULONG phys;
            dir->tables[table_index] = (page_table_t*) k_malloc( sizeof(page_table_t), 1, &phys );
            k_memset(dir->tables[table_index], 0, PAGESIZE);
            dir->tablesPhysical[table_index] = phys | 0x7; // 111b meaning: PRESENT=1, RW=1, USER=1
            return &dir->tables[table_index]->pages[address%1024];
        }
        else
            return 0;
    }
    

    Nun gibt es bei mir etwas Kopfzerbrechen. Wenn das Pagebit gesetzt ist, ist die Adressierung virtuell, bzw. verweisorientiert oder physikalisch? Man hat also 1024 Seiten und 1024 Seitentabellen maximal. Somit ist der Wert von address maximal 1024 * 1024, weswegen durch 1024 geteilt wird, um den tabellen_index zu erhalten.
    Multipliziert man 1024 * 1024 mit der Seitengröße von 4*1024, so hat man den gesamten Adressraum, der durch 32 Bit darstellbar ist.
    Die virtuelle Adresse wird gebildet durch die oberen 10 Bits (22 - 31) des Tabellenindex, von Bit 12 bis 21 durch den Index der Seitentabelle und von den Bit 0 bis 11, wo der Offset innerhalb einer Seite adressiert. Also so muß address virtuell bzw. verweisorientiert sein, weil wir sie auf die Indices der Tabelleneinträge zerlegen und über die Tabelleneinträge die entsprechende Seite zugreifen können. Dieses ist mir jedoch in den Ausführungen von James Molloy nicht sehr klar ersichtlich.

    Doch nun kommt die Abfrage

    if (dir->tables[table_index])       // table already assigned
    

    Wenn der Eintrag 0 ist, dann gibt es keine Seitentabelle, sonst kann man sich die Seite holen.
    Doch sie wird laut Initialisierung nicht vorhanden sein, da James Molloy in der Funktion

    void paging_install()
    {
        // setup bitset
        frames = (ULONG*) k_malloc( NFRAMES/32, 0, 0 );
        k_memset( frames, 0, NFRAMES/32 );
    
        // make a page directory
        kernel_directory = (page_directory_t*) k_malloc( sizeof(page_directory_t), 1, 0 );
        k_memset(kernel_directory, 0, sizeof(page_directory_t));
        kernel_directory->physicalAddr = (ULONG)kernel_directory->tablesPhysical;
    
        // Map some pages in the kernel heap area.
        ULONG i=0;
        for( i=KHEAP_START; i<KHEAP_START+KHEAP_INITIAL_SIZE; i+=0x1000 )
            get_page(i, 1, kernel_directory);
    
        // Allocate ... extra so the kernel heap, tasks and kernel stacks can be initialized properly.
        // map (phys addr <---> virt addr) from 0x0 to the end of used memory
        ULONG counter=0;
        i=0;
        while( i < placement_address + 0x6000 ) //important to add more! at least 0x2000
        {
            alloc_frame( get_page(i, 1, kernel_directory), 0, 0);
            i += PAGESIZE;
            ++counter;
        }
    
        // Now allocate those pages we mapped earlier.
        for( i=KHEAP_START; i<KHEAP_START+KHEAP_INITIAL_SIZE; i+=0x1000 )
            alloc_frame( get_page(i, 1, kernel_directory), 0, 0);
    
        current_directory = clone_directory(kernel_directory);
    
        // cr3: PDBR (Page Directory Base Register)
        asm volatile("mov %0, %%cr3":: "r"(kernel_directory->physicalAddr)); //set page directory base pointer
    
        // read cr0, set paging bit, write cr0 back
        ULONG cr0;
        asm volatile("mov %%cr0, %0": "=r"(cr0)); // read cr0
        cr0 |= 0x80000000; // set the paging bit in CR0 to enable paging
        asm volatile("mov %0, %%cr0":: "r"(cr0)); // write cr0
    }
    
    

    mit

     k_memset(kernel_directory, 0, sizeof(page_directory_t));
    

    das gesamte Verzeichnis und alle Tabelleneinträge auf 0 gesetzt hat. Aber es wird noch grausamer! Schauen wir noch einmal in die Funktion getpage hinein, wo es diesen Abschnitt gibt

    else if(make)
        {
            ULONG phys;
            dir->tables[table_index] = (page_table_t*) k_malloc( sizeof(page_table_t), 1, &phys );
            k_memset(dir->tables[table_index], 0, PAGESIZE);
            dir->tablesPhysical[table_index] = phys | 0x7; // 111b meaning: PRESENT=1, RW=1, USER=1
            return &dir->tables[table_index]->pages[address%1024];
        }
        else
            return 0;
    

    Es wird eine Seitentabelle falschen Formats mit k_malloc erzeugt und die physikalische Adresse
    tabelsPhysikal eingetragen! Die Seitentabelle dürfte jedoch nur 32 Bit- Eintrage haben, die jedoch fehlt allerdings!

    Nun hat jedoch James Molloy zwei Verzeichnistabellen definiert:

    Eine Verzeichnistabelle tables und eine tablesPhysical.
    tables verweist auf eine Struktur der Page

    typedef struct page
    {
        ULONG present    :  1;   // Page present in memory
        ULONG rw         :  1;   // 0: read-only,    1: read/write
        ULONG user       :  1;   // 0: kernel level, 1: user level
        ULONG accessed   :  1;   // Has the page been accessed since last refresh?
        ULONG dirty      :  1;   // Has the page been written to since last refresh?
        ULONG unused     :  7;   // Combination of unused and reserved bits
        ULONG frame_addr : 20;   // Frame address (shifted right 12 bits)
    } page_t;
     
    
    

    und tablesPhysical hat in seinen Einträgen nur 32 Bit Einträge für die Seiten, wo Statusbits vorhanden sind und frame_addr um 12 Bit nach links verschoben sind. Nur die Statusbits werden hier nicht gesetzt. Bei der Struktur page_t, gibt es keine Statusbits, sondern Statusvariablen! Somit hat tables ein falsches Format und ist nicht 32 Bit sondern 224 Bit lang!

    Bei tablesPhysical sind jedoch mit k_memset auf Null überschrieben worden, wo also keine Seiten existieren aus der Sicht der CPU. Doch warum wurde dann bei tables frame_addr auf 20 gesetzt? Eigentlich müßte, diese page_t Struktur mit 0 initialisieren. Beim Setzen der Seite müßte man page_t erst die Parameter entsprechend zuweisen. Allderdings hat James Molloy mit k_memset(kernel_directory, 0, sizeof(page_directory_t)) diese Initialisierung wieder zunichte gemacht und auf 0 gesetzt, wodurch die Initialiserung hinfällig wird.

    Wenn nun keine Seitentabelle existiert, wird k_malloc eine erzeugen. Was passiert da nun, wenn das Pagingbit gesetzt ist? Sofern kein Heap vorhanden ist, dann ist das klar. k_malloc erzeugt eine physiaklische Adresse auf Basis des placement. Doch was ist, wenn eine lokaler heap existiert? Nun für den Kernel sollte dieser nicht existieren. Ein lokaler Heap ist eher für Benutzerprogramme geignet. Doch was ist, wenn ein Benutzerprogramm nun eine Speicherseite anfordert? Dann haben wir einen lokalen Heap.

    Bei k_malloc(size,align,&phys) wird nun der obere Teil entscheidend:

    if (phys != 0)
       {
         page_t* page = get_page((ULONG)addr, 0, kernel_directory);
         *phys = page->frame_addr * PAGESIZE + ((ULONG)addr&0xFFF);
       }
    
    return (ULONG)addr;
    

    Soweit ich verstehe, arbeitet alloc über das placement oder mit den Heapbegrenzungen der Variable heap mit physikalischen Adressen. Bin mir aber nach dem Einschalten des Pagebits nicht mehr ganz so sicher!

    Wie ich sehe, hat James Molloy 4 grobe Fehler eingebaut.

    1. tables hat ein falsches Format und jeder Eintrag müßte 32 Bit lang sein, wo man mit
      Hilfe von Bitoperationen die Statusbits setzt und ebenso die physikalische Adresse
      2 tabelsPhysical muß ein Pointer sein und dynamisch pagealigned allokiert werden, damit es in
      eine Speicherseite paßt. Jene Speicherseite gilt ebenfalls als belegt für den Kernel. Das
      Gleiche gilt auch für die Seitentabellen.
    2. bei getpage dürfte man man nicht die den Offset einer virtuellen Adresse in die
      Seiteninformation eintragen.
    3. Seiteneinträge müssen während der Initialisierung oder explizit mit physikalischen und Statusbits versehen werden. Bei Getpage dürfen nur die Statusbist verändert werden, um beispielsweise die Seite für sich zu reservieren.

    Da im Kernel auch auf den Videospeicher zugegriffen, müßte man vor dem Setzen des Pagingbits diesen manuell auf entsprechende Seiten, Seitentabellen und Seitenverzeichnisse setzen, damit man später nach dem Setzen des Page-Bits unter einer virtuellen Adresse darauf zugreifen kann. Das würde eventell bedeuten, daß ich nun diesen anders adressieren muß, sofern man die Videoadresse in irgendeine Seite legt. Um die alte physikalische Adresse zB. 0xB8000 beizubehalten, müßte ich im Falle eines Paging ausrechnen, welchen Index das Verzeichnis haben muß und welchen Index der Seitentabelle verweisen muß, damit man die entsprechende Seite im Video-Bereich legen kann. Das muß also vorher für den Kernel schon bei paging_install passieren, was ich bei James Molloy ebenfalls vermisse.

    Nach James Molloy müßte dann, weil alle Seiten in tablesPhysical mit 0 initialisiert worden sind, ein Zugriff auf den Videospeicher ein Pagefault auslösen, und man würde noch nicht einmal eine Meldung auf den Bildschirm bekommen.

    So wie ich es sehe, kann das Paging gemäß James Molloy wegen der oben genannten Fehler gar nicht funktionieren oder verstehe ich da etwas falsch? Ich könnte mich eventuell in den physikalischen Adressen in den Seitenverweisen als auch in den Verweisen der Verzeichnistabelle irren. Ich denke jedoch, daß die MMU diese physikalischen Adressen benötigt.



  • Ich hab den Post nur überflogen, aber ein paar Sachen sind mir aufgefallen:

    1. Die structs sind bitfields. Hinter dem Doppelpunkt steht die Anzahl der Bits, nicht der Initialwert. Damit passt die Größe und Layout zu dem was die CPU erwartet.
    2. Es werden die ersten 16 MB des Kernel-Adressraums 1:1 auf den physischen Adressraum gemappt. Da ist der Videospeicher mit drin.


  • Ich muß offenbar einen Anfall von Legasthenie gehabt haben. Ich hatte den Doppelpunkt als Gleichheitszeichen gelesen. Dann ist mir nur noch eine Sache unklar. Was müßte eigentlich in frame_addr stehen? Ich denke eher eine physikalische Adresse also z.B. 1 << 12 = 4096 und nicht der Rest bzw. Offset einer virtuellen Adressangabe.



  • @w_ciossek sagte in Paging: Verständnisschwierigkeiten zum Tutorial von James Molloy:

    Zunächst möchte ich meine Kenntnislage zum Paging darstellen.

    TL;DR
    Ernsthaft, glaubst du dass sich das irgendjemand durchliest?


  • |  Mod

    Das durchzulesen ist wirklich unzumutbar. 🤓

    Vielleicht noch hier rein schauen:
    http://lowlevel.eu/wiki/Paging_Tutorial
    ... auch an das Intel Manual denken.