Lowlevel

Lowlevel => Lowlevel-Coding => Thema gestartet von: rizor am 16. December 2008, 17:53

Titel: Paging
Beitrag von: rizor am 16. December 2008, 17:53
Nabend zusammen,

ich bin eben dabei jetzt paging einzubauen.
Dabei sind mir ein paar Fragen gekommen.
Wie arbeiten denn die physikalische und die virtuelle Speicherverwaltungen zusammen?
Wenn ich das richtig verstanden habe, ist Paging komplett unabhängig von der physischen Verwaltung.
Wenn ja, wozu brauche ich dann eine physikalsche Verwaltung?
Gut ok, damit kann ich die Module etc nachladen, aber das könnte ich ja auch anders realisieren.
Allerdings ist eines ein ganz großes Fragezeichen:
Wenn ich mir eine virtuelle Verwaltung aufbaue, liegt die doch im RAM, oder liegt die im Prozessorcache?
Müsste ich nicht bei der Erstellung der Virtuellen Verwaltung die Pages in der physischen Verwaltung anmelden?
Ich habe auch gelesen, dass ich bestimmte physische Speicherbereiche in den virtuellen Bereich mappen kann.
Das wäre doch dann zum Beispiel für den VGA-Block nützlich, oder?
Wie würde das denn dann aussehen?
Ich kann ja nur noch über virtuelle Adressen daran kommen.
Oder mappe ich den vor dem aktivieren des Paging-Mechanismusses?

Das waren jetzt so die Fragen, die mir auf anhieb gekommen sind.
Da folgen bestimmt noch einige.

Danke.

Gruß
rizor
Titel: Re: Paging
Beitrag von: kevin am 16. December 2008, 18:31
Hast du http://lowlevel.brainsware.org/wiki/index.php/Paging gelesen?
Titel: Re: Paging
Beitrag von: rizor am 16. December 2008, 21:16
Ok, danke.
Habe ich übersehen....
Nun habe ich trotzdem noch eine Frage.
Wenn ich eine Seite mappen möchte, erstelle ich als erstes eine Directory die dann mit einer Table_Page zusammenarbeitet, oder wie?
Dann habe ich mir mal den Code von LOST angeschaut und bei map_page oder so nur Bahnhof verstanden.
Wieso mappt ihr eine neue Adresse erst in den Kernel-Bereich?
reicht es nicht aus, wenn man eine Directory und eine Table hat?
Man kann doch den Unterschied zwischen Kernel und User mit dem Flag realisieren.
Dann könnte man noch unter Umständen abfragen, ob ein Bereich schon beschrieben ist, wenn ja dann einen Panic auslösen oder beim Multitasking denjenigen der Requested abschießen.
Und wenn der noch nicht besteht einfach einen neuen erzeugen.
Wenn es sich dann dabei um einen Kernelaufruf einfach den Usermode nicht mit einschalten.

Ich finde eure Variante ein wenig zu kompliziert, es sei denn ich habe das mit dem Paging noch nicht richtig verstanden.
Titel: Re: Paging
Beitrag von: rizor am 17. December 2008, 00:06
Habe mal versucht mein Paging zu implementieren.
Leider funktioniert das Mappen des GraKa-Speichers nicht.
Der Code soeht wie folgt aus:
size_t video_size = 80 * 25 * 2 / BLOCK_SIZE + 1;
map_paging_range((physaddr_t)0xB8000 , (virtaddr_t)0xB8000 , PAGING_PRESENT | PAGING_WRITEABLE , video_size);

Dazu dann noch die Methode, die mappen soll:
    paging_table_t paging_table;
    dword virt_page = (dword)vaddr;

    if(vaddr == NULL)
        panic("Illegal call to the NULL-Table-Entry");

    if(flags & ~0x01F)
        return;

    if(((dword)vaddr | (dword)paddr) && 0xFFF)
        panic("The requested address is not 4k-aligned");

    //page does not exist
    if((paging_directory[virt_page / PAGING_TABLE_SIZE] & PAGING_NOTTLB) == 0 ){
        paging_table = (paging_table_t)phys_alloc(sizeof(paging_table_t));

        paging_directory[virt_page / PAGING_TABLE_SIZE] = ((dword)paging_table) | flags;

        memset(paging_table , 0 , BLOCK_SIZE);
    }

Es wird folgender Panic ausgelöst:
The requested address is not 4k-aligned

Woran kann das liegen?
Titel: Re: Paging
Beitrag von: Jidder am 17. December 2008, 09:28
Du willst in der if-Abfrage das bitweise Und (&) verwenden, nicht das logische Und (&&).
Titel: Re: Paging
Beitrag von: rizor am 17. December 2008, 17:18
Danke.
Nun habe ich leider ein anderes Problem.
Wenn ich alles gemappt habe und dann das Paging aktivieren möchte, bekomme ich beim qemu ein triple fault.
Das liegt daran, dass ih cr0 das 31-Bit setze.
Leider kann ich mir nicht erklären.
Was mir aufgefallen ist, ist dass wenn ich zwei debug-ausgaben mache, dass meine page-directory auf 0x0001090 oder so zeigt und der Eintrag in dem cr3 Register auf 0x0001027 oder so.
Woran kann das liegen?
Ist das der Grund für meinen triple fault?

Leider funktioniert bei mir bochs nicht (findet die VGA-Bibliothek nicht), deshalb kann ich damit leider nicht debuggen und das Debugging beim qemu will bei mir nicht so richtig laufen...

Danke für eure Hilfe.

Gruß
rizor
Titel: Re: Paging
Beitrag von: kevin am 17. December 2008, 18:32
Was mir aufgefallen ist, ist dass wenn ich zwei debug-ausgaben mache, dass meine page-directory auf 0x0001090 oder so zeigt und der Eintrag in dem cr3 Register auf 0x0001027 oder so.
Woran kann das liegen?
Ist das der Grund für meinen triple fault?
Vermutlich ja. cr3 sollte auf 0x1000 aligned sein. Aber dein geposteter Code zeigt leider nicht, was du beim Initialisieren genau machst.
Titel: Re: Paging
Beitrag von: rizor am 17. December 2008, 18:48
Das ist der initialisierende Code:

paging_directory = (paging_directory_t)phys_alloc(PAGING_DIRECTORY_SIZE);
    memset(paging_directory , 0 , BLOCK_SIZE);
    paging_directory[PAGING_VIRTADDR >> PAGING_DIR_SHIFT] = (dword)paging_directory | PAGING_PRESENT | PAGING_WRITEABLE;
    size_t kernel_size = ((dword)kernel_end - (dword)kernel_start) / BLOCK_SIZE;
    map_paging_range(kernel_start , kernel_mem_start , PAGING_PRESENT | PAGING_WRITEABLE | PAGING_NOTTLB , kernel_size);
    size_t video_size = 80 * 25 * 2 / BLOCK_SIZE + 1;
    map_paging_range((physaddr_t)0xB8000 , (virtaddr_t)0xB8000 , PAGING_PRESENT | PAGING_WRITEABLE , video_size);
    map_paging(paging_directory , paging_directory , PAGING_PRESENT | PAGING_WRITEABLE);
    map_paging_range(bitmap_start , bitmap_start , PAGING_PRESENT | PAGING_WRITEABLE , bitmap_length / BLOCK_SIZE);
    //enable paging
    _write_cr3((dword)&paging_directory);
    _write_cr0(_read_cr0() | 0x80000000);

Wieso soll cr3 aof 0x1000 zeigen?
Meintest du nicht er 0x1090?
Titel: Re: Paging
Beitrag von: kevin am 17. December 2008, 19:08
    _write_cr3((dword)&paging_directory);
Da ist schonmal das & zuviel. paging_directory ist doch schon ein Pointer.

Zitat
Wieso soll cr3 aof 0x1000 zeigen?
Meintest du nicht er 0x1090?
Öhm, nein. Wo sollte die 9 herkommen?
Titel: Re: Paging
Beitrag von: rizor am 17. December 2008, 19:11
Ok stimmt.
War vorher auch nicht da...
Wieso soll es auf 0x1000 zeigen?
Das muss doch dahin zeigen, wo meine Directory liegt, oder?
Aber ich alloziere mir ja Speicher dieser Größe und wer sagt mir, dass das Teil bei 0x1000 liegt?
Titel: Re: Paging
Beitrag von: FreakyPenguin am 17. December 2008, 19:24
taljeth hat ja nicht gesagt, dass das auf 0x1000 zeigen müsse. Die Adresse die du da reinschreibst muss halt auf 0x1000 Bytes ausgerichtet sein, d.h. ein Vielfaches davon sein.
Titel: Re: Paging
Beitrag von: rizor am 17. December 2008, 19:27
Das bedeutet, dass meine Page-Directory an einer anderen stelle liegen muss, oder wie?
Also bei 0x2000, etc.
Aber wie mache ich das am besten mit meiner physikalischen Speicherverwaltung?
Die gibt mir ja vor, wo das alles zu liegen hat.
Titel: Re: Paging
Beitrag von: kevin am 17. December 2008, 19:35
Ganz einfach: Die gibt dir 4k-Pages, also ist automatisch alles auf 0x1000 ausgerichtet.
Titel: Re: Paging
Beitrag von: rizor am 17. December 2008, 19:37
Aber wieso liegt meine page-directory dann bei 0x1090, dann müsste die ja verbugged sein, oder?
Titel: Re: Paging
Beitrag von: kevin am 17. December 2008, 20:01
Sieht grad so aus.
Titel: Re: Paging
Beitrag von: rizor am 17. December 2008, 22:55
Ok.
Das Problem mit dem physischen Speichermanagment habe ich behoben (scheint zumindest so).
Leider bekomme ich bei der Benutzung des Pagings immer noch den triple fault.
Die Adresse, die jetzt im cr3-reg steht sieht nun besser aus:
0x10C000.
Aber woran kann es nun liegen, dass es den Triple fault gibt?
Titel: Re: Paging
Beitrag von: kevin am 18. December 2008, 01:12
Wenn du wissen willst, auf welche Adresse er zugegriffen hat, kannst du qemu mal mit -d int starten. In der /tmp/qemu.log findest du dann alle Interrupts, die ausgelöst worden sind. Kurz vor dem Ende müßte ein 0e kommen (Page Fault) und beim zugehörigen CPU-Dump steht die schuldige Adresse in cr2. Und dann kannst du versuchen, rauszufinden, warum diese Adresse nicht gemappt ist.
Titel: Re: Paging
Beitrag von: rizor am 18. December 2008, 19:36
Die Ausgabe des Logs ergab folgendes:
check_exception old: 8 new e
qemu: fatal: triple fault
EAX=e0000011 EBX=00001000 ECX=00000000 EDX=00031000
ESI=00000001 EDI=00000001 EBP=00107f68 ESP=00107f68
EIP=0010271d EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300
CS =0008 00000000 ffffffff 00cf9a00
SS =0010 00000000 ffffffff 00cf9300
DS =0010 00000000 ffffffff 00cf9300
FS =0010 00000000 ffffffff 00cf9300
GS =0010 00000000 ffffffff 00cf9300
LDT=0000 00000000 0000ffff 00008000
TR =0000 00000000 0000ffff 00008000
GDT=     00009108 00000027
IDT=     00000000 000003ff
CR0=e0000011 CR2=00000040 CR3=0010c000 CR4=00000000
CCS=0000000c CCD=e0000011 CCO=LOGICL 
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000

Da steht leider nichts von 0e oder ich gucke falsch.
Aber was mich wundert ist cr2. Da dürfte er gar nicht hin.
Da wird nichts gemappt.
Soll es auch nicht.
Wie kann ich denn am besten mit dem qemu debuggen?
Also wie füge ich Breakpoints und so ein?
Habe mal gegoogelt aber leider kein ordentliches Tut gefunden.
Was ist besser zum debuggen?
Boch oder QEMU?
Titel: Re: Paging
Beitrag von: kevin am 18. December 2008, 21:27
Für die lowleveligeren Sachen am Anfang ist bochs vermutlich besser. Ansonsten bin ich überzeugter qemu-Anhänger. ;)

In der Log mußt du noch ein Stück zurück. Vor dem Triple Fault kommt ein Double Fault (das ist die 8 ) und davor müßte der Page Fault kommen.
Titel: Re: Paging
Beitrag von: rizor am 18. December 2008, 21:35
Kannst du mir dann vllt erklären, warum mein Boch die VGA-Bibliothek nicht findet?
Was mussen ich denn da alles noch mit installieren.
Benutze Ubuntu 8.04.

Da steht dann nur noch
check_exception old: ffffffff new e
check_exception old: e new e

Ist der erste die page fault exception?
Die Exceptions werden doch nicht deaktiviert, oder?
Also wenn ich die Interrupts deaktiviert habe.
Titel: Re: Paging
Beitrag von: rizor am 18. December 2008, 22:50
Ich habe mitlerweile herausgefunden, warum er auf die Adresse zugreifen will.
Habe meine Directory mit den Flags falsch in die Directory eingetragen.
Vorher:
paging_directory[PAGING_VIRTADDR >> PAGING_DIR_SHIFT] = (dword)paging_directory | PAGING_PRESENT | PAGING_WRITEABLE;
Nachher:
paging_directory[PAGING_VIRTADDR << PAGING_DIR_SHIFT] = (dword)paging_directory | PAGING_PRESENT | PAGING_WRITEABLE;

So herum müsste es jetzt richtig sein, oder?
Titel: Re: Paging
Beitrag von: kevin am 18. December 2008, 23:00
Eher nicht, die alte Variante sieht mir vernünftiger aus.
Titel: Re: Paging
Beitrag von: rizor am 18. December 2008, 23:16
Ach ja, ich kenne ja die virtuelle Adresse.
Die Frage ist, woran liegt es dann?
Die Adresse die ich  aus dem Rechtsshift erhalte ist dann genau die Adresse die im cr2 register liegt.
Die Frage ist jetzt nur, wieso versucht er daruf zuzugreifen?
Titel: Re: Paging
Beitrag von: rizor am 21. December 2008, 01:08
Nabend,

ich habe mir mal Gedanken gemacht, ob mein Algorithmus überhaupt richtig ist.
So wie ich euer Wiki dazu verstanden habe, muss ich mir zu jeder virtuellen Adresse die Directory, etc suchen.
Dann habe ich aber woanders gelesen, dass ich mir die Stelle in der Directory suche (für die virtuelle Startadresse) und ab da für eine bestimmte Länge jedes Nachfolgeelement mit der physikalischen Adresse belege.

Das klingt für mich auch logischer, da das ja die externe Fragmentierung verhindert.
Also habe ich das mal so programmiert.
Leider funktioniert das immer noch nicht.
Schaut euch mal bitte den Code an.
Vllt findet ihr den Fehler.

void map_pages(physaddr_t paddr , virtaddr_t vaddr , paging_flags flags , size_t size){
    size_t i , offset = (dword)vaddr >> PAGING_TAB_SHIFT;;
    dword phys_addr;
    paging_directory_t requested_directory = (paging_directory_t)paging_directory[(dword)vaddr >> PAGING_DIR_SHIFT];
    paging_table_t requested_table;

    if((dword)requested_directory & PAGING_PAGE_FREE){
        //request memory for the table and prepare it to run
        requested_table = phys_alloc(PAGING_TABLE_SIZE * sizeof(paging_table_t) / BLOCK_SIZE);
        for(i = 0; i < PAGING_TABLE_SIZE; i++)
            requested_table[i] = 0 | PAGING_PAGE_FREE;
        //include the new table to the directory
        requested_directory = requested_table;
        //map the physical addresses
        for(i = 0; i < size; i++){
            phys_addr = (dword)paddr + i * BLOCK_SIZE;
            requested_table[offset + i] = phys_addr | flags | PAGING_PAGE_INUSE;
        }
    }
    else if((dword)(requested_table = (paging_table_t)requested_directory[offset]) & PAGING_PAGE_FREE){
        //go through the tavle at the requested addresses
        for(i = 0; i < size; i++){
            phys_addr = (dword)paddr + i * BLOCK_SIZE;
            //check if the entry is empty
            if((dword)requested_table[i] & PAGING_PAGE_FREE)
                requested_table[i] = phys_addr | flags | PAGING_PAGE_INUSE;
            else
                panic("Tried to write into a set table-entry");
        }
    }
    else
        panic("Tried to write into a set table-entry");
}

Danke für eure Hilfe.

Titel: Re: Paging
Beitrag von: kevin am 21. December 2008, 10:56
void map_pages(physaddr_t paddr , virtaddr_t vaddr , paging_flags flags , size_t size){
    size_t i , offset = (dword)vaddr >> PAGING_TAB_SHIFT;;
    dword phys_addr;
    paging_directory_t requested_directory = (paging_directory_t)paging_directory[(dword)vaddr >> PAGING_DIR_SHIFT];
    paging_table_t requested_table;

    if((dword)requested_directory & PAGING_PAGE_FREE){
        //request memory for the table and prepare it to run
        requested_table = phys_alloc(PAGING_TABLE_SIZE * sizeof(paging_table_t) / BLOCK_SIZE);
        for(i = 0; i < PAGING_TABLE_SIZE; i++)
            requested_table[i] = 0 | PAGING_PAGE_FREE;
Ist an dieser Stelle Paging noch aus? Sonst ist das falsch, du greifst hier auf physische Adressen zu.

        //include the new table to the directory
        requested_directory = requested_table;
Ähm, sicher?

        //map the physical addresses
        for(i = 0; i < size; i++){
            phys_addr = (dword)paddr + i * BLOCK_SIZE;
            requested_table[offset + i] = phys_addr | flags | PAGING_PAGE_INUSE;
Wofür hast du ein FREE und ein INUSE?

        }
    }
    else if((dword)(requested_table = (paging_table_t)requested_directory[offset]) & PAGING_PAGE_FREE){
Ob eine Page Table frei ist, wird nirgends gesetzt, wenn ich das richtig sehe. Und wenn du das requested_table als Pointer benutzen willst, dann solltest du vielleicht vorher die Flags rausmachen...

        //go through the tavle at the requested addresses
        for(i = 0; i < size; i++){
            phys_addr = (dword)paddr + i * BLOCK_SIZE;
            //check if the entry is empty
            if((dword)requested_table[i] & PAGING_PAGE_FREE)
                requested_table[i] = phys_addr | flags | PAGING_PAGE_INUSE;
            else
                panic("Tried to write into a set table-entry");
        }
    }
    else
        panic("Tried to write into a set table-entry");
}
Was passiert, wenn sich ein Aufruf über mehrere Page Tables erstreckt? Dein Code würde dann halt irgendwo in die Landschaft schreiben - gelegentlich auch Buffer Overflow genannt.

Die Gültigkeit der Parameter zu überprüfen wäre auch keine schlechte Idee, aber daran liegt es vermutlich erstmal nicht.
Titel: Re: Paging
Beitrag von: rizor am 21. December 2008, 12:57
Ist an dieser Stelle Paging noch aus? Sonst ist das falsch, du greifst hier auf physische Adressen zu.

Ja, an dieser Stelle ist Paging noch aus.

Ähm, sicher?

Wie sollte ich die neue Table denn dann in die Directory eintragen?
Im Prinzip muss ich die Tabelle doch genau an der Stelle eintragen.

Wofür hast du ein FREE und ein INUSE?

Die benutze ich in den Bits, die für das OS da sind.
Da wird dann später geschaut, ob die Table geswapped wurde.

Ob eine Page Table frei ist, wird nirgends gesetzt, wenn ich das richtig sehe. Und wenn du das requested_table als Pointer benutzen willst, dann solltest du vielleicht vorher die Flags rausmachen...

Das setze ich ja, wenn ich sehe, dass die Table noch nicht existiert.
Titel: Re: Paging
Beitrag von: rizor am 22. December 2008, 00:16
Ich bin den Code jetzt immer wieder durchgegangen.
Finde den Fehler aber nicht.
Die Methode zur Initialisierung des Pagings hat sich nicht geändert.
Könnt ihr einen Fehler erkennen, außer dass ich nicht alle Parameter auf Korrektheit überprüfe?

Danke für eure Hilfe.

Gruß
rizor
Titel: Re: Paging
Beitrag von: rizor am 29. December 2008, 01:18
Nabend zusammen,

habe mir noch einmal den Code angeschaut und ihn elementarer gemacht.
Leider geht es immer noch nicht.
Mein File zum Paging sieht jetzt so aus:

#include <kernel32.h>
 #include <memory/mmu.h>
 #include <memory/pmmu.h>

//internal methods
void map_pages(physaddr_t , virtaddr_t , cond_flags , size_t);
void directory_init();
void printReserved(int , int);

//methods from the asm-file
extern void _write_cr3(dword);
extern void _write_cr0(dword);
extern dword _read_cr0();
extern dword _read_cr3();

page_table_t directory;
extern dword bitmap_length;
extern dword *bitmap_virt;

void paging_init(){
    size_t param;
    //initialize the directory
    directory_init();

    //map the kernel
    param = ((dword)kernel_end - (dword)kernel_start) / BLOCK_SIZE;
    map_pages(kernel_start , kernel_mem_start , PAGE_READWRITE | PAGE_PRESENT , param);

    //map the video
    param = 80 * 25 * 2 / BLOCK_SIZE + 1;
    map_pages((physaddr_t)0xB8000 , (virtaddr_t)0xB8000 , PAGE_READWRITE | PAGE_PRESENT , param);

    //map the directory
    map_pages(directory , directory , PAGE_READWRITE | PAGE_PRESENT , 1);

    //map the bitmap
    param = bitmap_length / BLOCK_SIZE;
    map_pages(bitmap_virt , bitmap_virt , PAGE_READWRITE | PAGE_PRESENT , param);

    _write_cr3((dword)directory);
    _write_cr0((_read_cr0() | 0x80000000));
}

void directory_init(){
    size_t i;
    directory = phys_alloc(TABLE_SIZE * sizeof(page_table_t) / BLOCK_SIZE);

    memset(directory , 0 , TABLE_SIZE);
}

void map_pages(physaddr_t paddr , virtaddr_t vaddr , cond_flags flags , size_t size){
    size_t i , offset = ((dword)vaddr >> SHIFT_PAGE) % TABLE_SIZE;
    page_table_t table;
    dword phys_addr;

    if(size >= TABLE_SIZE - offset){
        //TODO: change parameters
    }

    if(directory[(dword)vaddr >> SHIFT_DIRECTORY] == NULL){
        puts("Generating new table\n");
        //prepare the table
        table = phys_alloc(TABLE_SIZE * sizeof(page_table_t) / BLOCK_SIZE);
        memset(table , 0 , TABLE_SIZE);

        //register in the directory
        directory[(dword)vaddr >> SHIFT_DIRECTORY] = (dword)table | PAGE_PRESENT | PAGE_READWRITE;
    }

    table = (page_table_t)directory[(dword)vaddr >> SHIFT_DIRECTORY];
    for(i = 0; i <= size; i++){
        phys_addr = (dword)paddr + i * BLOCK_SIZE;

        table[offset + i] = phys_addr | flags;
    }
}

Habe immer noch keine Ahnung woran das liegt.
Die Berechnung müsste ja an sich stimmen.
Seht ihr nun vllt den Fehler?

Gruß
rizor

[EDIT]
Stimmt meine Theorie überhaupt, dass ich einfach nur die Offset-Adresse berechne und Dann in meinem Array einfach solange hoch zählen muss, bis alles gemappt ist, was im physischen Speicher liegt?
Titel: Re: Paging
Beitrag von: tarrox am 29. December 2008, 10:38
Hab mal durgeschaut und ein paar Fehler gefunden.

#include <kernel32.h>
 #include <memory/mmu.h>
 #include <memory/pmmu.h>

//internal methods
void map_pages(physaddr_t , virtaddr_t , cond_flags , size_t);
void directory_init();
void printReserved(int , int);

//methods from the asm-file
extern void _write_cr3(dword);
extern void _write_cr0(dword);
extern dword _read_cr0();
extern dword _read_cr3();

page_table_t directory;
extern dword bitmap_length;
extern dword *bitmap_virt;

void paging_init(){
    size_t param;
    //initialize the directory
    directory_init();

    //map the kernel
    param = ((dword)kernel_end - (dword)kernel_start) / BLOCK_SIZE;
    map_pages(kernel_start , kernel_mem_start , PAGE_READWRITE | PAGE_PRESENT , param);

    //map the video
    param = 80 * 25 * 2 / BLOCK_SIZE + 1;
    map_pages((physaddr_t)0xB8000 , (virtaddr_t)0xB8000 , PAGE_READWRITE | PAGE_PRESENT , param);

    //map the directory
    map_pages(directory , directory , PAGE_READWRITE | PAGE_PRESENT , 1);

    //map the bitmap
    param = bitmap_length / BLOCK_SIZE;
    map_pages(bitmap_virt , bitmap_virt , PAGE_READWRITE | PAGE_PRESENT , param);

    _write_cr3((dword)directory);
    _write_cr0((_read_cr0() | 0x80000000));
}

void directory_init(){
    size_t i;
    directory = phys_alloc(TABLE_SIZE * sizeof(page_table_t) / BLOCK_SIZE);

    memset(directory , 0 , TABLE_SIZE);
}

void map_pages(physaddr_t paddr , virtaddr_t vaddr , cond_flags flags , size_t size){
    size_t i , offset = ((dword)vaddr >> SHIFT_PAGE) % TABLE_SIZE;
    page_table_t table;
    dword phys_addr;
Ich frag mich was du hier machst? Dir ist schon klar, dass du mindestens 3073 Pages anfragen musst, damit diese Bedingung erfüllt ist. Ich denke nicht, dass du das gemeint hast.
    if(size >= TABLE_SIZE - offset){
        //TODO: change parameters
    }

    if(directory[(dword)vaddr >> SHIFT_DIRECTORY] == NULL){
        puts("Generating new table\n");
        //prepare the table
        table = phys_alloc(TABLE_SIZE * sizeof(page_table_t) / BLOCK_SIZE);
Sollte jetzt noch nicht stören, wird es aber wenn das Paging aktiviert ist, den dann greifst du auf ungemappten Speicher zu sehr sehr böse. Daher erst zuweisen dann Nullen.
        memset(table , 0 , TABLE_SIZE);

        //register in the directory
        directory[(dword)vaddr >> SHIFT_DIRECTORY] = (dword)table | PAGE_PRESENT | PAGE_READWRITE;
    }

Hier hast du wohl vergessen, das im directory Eintrag noch die Flags sind, die musst du rausnehmen bevor du die Richtige Table Adresse erhältst.
    table = (page_table_t)directory[(dword)vaddr >> SHIFT_DIRECTORY];
    for(i = 0; i <= size; i++){
        phys_addr = (dword)paddr + i * BLOCK_SIZE;

        table[offset + i] = phys_addr | flags;
    }
}

Zitat
Stimmt meine Theorie überhaupt, dass ich einfach nur die Offset-Adresse berechne und Dann in meinem Array einfach solange hoch zählen muss, bis alles gemappt ist, was im physischen Speicher liegt?
Stimmt soweit nur solltest du mitbedenken, das das Maximum für das offset 1023 ist und du dannach denn nächsten directory Eintrag nehmen solltest.

Ansonsten würde mich interessieren wie page_table_t aussieht. Und ob du auch wirklich Adressen vom Physischem Memory Manager kreigst die Page Alligned sind. Ansonsten musst du alle Werte dir ausgeben lassen und schaun ob nicht einer falsch ist.
Titel: Re: Paging
Beitrag von: rizor am 30. December 2008, 15:38
Ich frag mich was du hier machst? Dir ist schon klar, dass du mindestens 3073 Pages anfragen musst, damit diese Bedingung erfüllt ist. Ich denke nicht, dass du das gemeint hast.

Welche Bedingung meinst du?

    if(size >= TABLE_SIZE - offset){
        //TODO: change parameters
    }

    if(directory[(dword)vaddr >> SHIFT_DIRECTORY] == NULL){
        puts("Generating new table\n");
        //prepare the table
        table = phys_alloc(TABLE_SIZE * sizeof(page_table_t) / BLOCK_SIZE);
Sollte jetzt noch nicht stören, wird es aber wenn das Paging aktiviert ist, den dann greifst du auf ungemappten Speicher zu sehr sehr böse. Daher erst zuweisen dann Nullen.
        memset(table , 0 , TABLE_SIZE);

        //register in the directory
        directory[(dword)vaddr >> SHIFT_DIRECTORY] = (dword)table | PAGE_PRESENT | PAGE_READWRITE;
    }

Gut, das stimmt.

Hier hast du wohl vergessen, das im directory Eintrag noch die Flags sind, die musst du rausnehmen bevor du die Richtige Table Adresse erhältst.
    table = (page_table_t)directory[(dword)vaddr >> SHIFT_DIRECTORY];
    for(i = 0; i <= size; i++){
        phys_addr = (dword)paddr + i * BLOCK_SIZE;

        table[offset + i] = phys_addr | flags;
    }
}

Ja, habe ich korrigiert, ändert aber nichts an der Fehlermeldung.

Ansonsten würde mich interessieren wie page_table_t aussieht. Und ob du auch wirklich Adressen vom Physischem Memory Manager kreigst die Page Alligned sind. Ansonsten musst du alle Werte dir ausgeben lassen und schaun ob nicht einer falsch ist.

Mein page_table_t ist ein unsigned long*.
Ja, der Physische Manager liefert 4k-aligned Adressen und auch wirklich die Anfangsadresse, denn wenn ich es ganz primitiv mache und einfach die ersten 4 MB mappe, funktioniert der Code.
Titel: Re: Paging
Beitrag von: rizor am 30. December 2008, 18:24
Verdammt.... habe den Fehler entdeckt.
Habe mir die Adresse, die in der Tabelle steht falsch formatiert.

Nun habe ich allerdings eine Frage zur Funktionsweise:
Wie sollte das denn nun aussehen, wenn ein neuer Prozess aufgerufen wird?
Ich könnte die neuen Prozesse ja einfach in die Directory eintragen.
Dann habe ich doch nur das Problem, dass ich Zugriffsfehler nicht feststellen kann, außer der Prozess greift in den Kernel oder die Page ist noch nicht gemappt.
Dann ist mir eingefallen, dass ich jedem Prozess ja eine eigene Directory geben könnte.
Da habe ich nur das Problem, dass ich bei jdem Prozesswechsel den Speicher swappen müsste, oder?
Ansonsten könnte es doch zu doppelten Zugriffen kommen.
Das wäre mir dann ein wenig zu viel Arbeit des Kernels.
Wie kann man das denn am besten realisieren?
Titel: Re: Paging
Beitrag von: kevin am 30. December 2008, 20:20
Jeder Prozeß bekommt sein eigenes Page Directory. Beim Taskwechsel wird dann eben cr3 neu geladen.
Titel: Re: Paging
Beitrag von: rizor am 03. January 2009, 22:36
Nabend,

habe jetzt nochmal eine Frage:

Wie kann ich am besten Speicher allozieren, wenn Paging aktiviert wurde?
Wollte mir der Einfachheit halber eine Liste erstellen, die alle Directories speichert.
Die Frage ist, wie mache ich das am besten?
Mein phys_alloc liefert mir ja eine physische Seite, wie mache ich daraus eine virtuelle?
Oder ist es am besten, wenn ich mir erst die virtuellen Seiten suche und danach einfach physischen Speicher alloziere und diesen dann in die neue Page eintrage?
Titel: Re: Paging
Beitrag von: kevin am 03. January 2009, 23:30
Die Liste aller PDs entspricht ja ziemlich genau der Liste aller Prozesse, und die brauchst du so oder so. ;)

Aber von einer physischen Adresse auf die virtuelle schließen mußt du eigentlich nie. Beim Allozieren suchst du eben einen freien Platz im virtuellen Adreßraum, mappst die physische Seite, die du von phys_alloc bekommst, und gibst dann die virtuelle Adresse zurück. Alles weitere arbeitet dann nur noch mit virtuellen Adressen. Was du gelegentlich brauchen kannst, ist der umgekehrte Weg, also von virtuellen Adressen  auf die zugehörigen physischen zu schließen. Das kannst du einfach in der passenden Page Table nachschlagen.
Titel: Re: Paging
Beitrag von: rizor am 08. January 2009, 00:08
Nabend,

nun habe ich noch eine Frage zu malloc.
Wie sollte man das am besten implemeniteren.
Wenn ich bei jedem malloc eine bestimmte Anzahl an Pages abgebe kann ich doch abartig großen verschnitt haben.
Wenn ich mir überlege, dass wenn ein Prozess eine Struktur anfordert, die 12 Byte groß ist, wäre es das dümmste, wenn ich einen 4k-Block markiere.
Sollte ich den noch unterteilen?
Das würde aber wiederrum einen extremen Overhead bedeuten.

Wie macht man das am besten?
Titel: Re: Paging
Beitrag von: Jidder am 08. January 2009, 00:27
Wenn du mit Unterteilen meinst, dass die restlichen 4084 Bytes der Seite dem Prozess für weitere malloc()-Aufrufe zur Verfügung stehen, dann ist das sinnvoll. Den Rest für andere Prozesse/Zwecke zu verfügbar machen, ist hingegen nicht praktikabel.
Titel: Re: Paging
Beitrag von: kevin am 08. January 2009, 10:51
Und das passende Stichwort für malloc heißt Freispeicherliste.
Titel: Re: Paging
Beitrag von: tarrox am 08. January 2009, 12:32
Du solltest am besten für jeden Prozess einen Heap erstellen, der die dynamische Speicherverwaltung übernimmt. Der kümmert sich darum aus den für sie vorgegebenen Pages, Speicher an den Prozess zu geben, wenn er angefordert wird (und auch wieder freizugeben).
Titel: Re: Paging
Beitrag von: rizor am 08. January 2009, 17:49
Gut ok.
Ist das nicht ein enormer Speicheraufwand?
Da fällt mir auch noch eine Frage ein:

Wenn ich nun malloc/kmalloc etc implementiere, wie kommuniziert mein Programm dann mit diesen Methoden?
Über Syscalls?
Bei Linux sehe ich ja, dass das irgendwie über libc geregelt wird.
Wie mache ich das bei meinem eigenen OS und wie kann ich überhaupt shared-libraries implementieren?
Titel: Re: Paging
Beitrag von: kevin am 08. January 2009, 18:45
Für malloc solltest du eher keinen Syscall nehmen, sondern eine Lib. Den Syscall sollte malloc erst aufrufen, wenn es neue Pages braucht. Du brauchst dazu nicht unbedingt Shared Libs, du kannst die libc einfach statisch dazulinken.
Titel: Re: Paging
Beitrag von: rizor am 08. January 2009, 19:49
Ich soll einfach die libc des gcc benutzen?
Dann muss ich doch gar kein malloc schreiben, oder?

Kann es sein, dass ich da was falsch verstehe?
Klärt mich mal bitte auf, wie das mit der libc und dem Kernel ist.
Titel: Re: Paging
Beitrag von: kevin am 08. January 2009, 22:28
Der gcc hat mit der libc nicht viel zu tun, außer dass man sie C-Programmen, die der gcc kompiliert, benutzen kann. Und nein, du sollst nicht die glibc nehmen. Die ist auf Linux ausgelegt und gilt nicht als besonders portabel.

Eine Binary - zum Beispiel deinen Kernel, aber auch deine Programme - erstellst du ja, indem du mehrere Objektdateien zusammenlinkst. Wenn du jetzt ein paar von diesen Objektdateien so geschrieben hast, daß du sie in jedes Programm reinlinken kannst, hast du eine Bibliothek geschrieben. Üblicherweise packt man dann die Objektdateien (*.o) in ein ar-Archive (*.a) zusammen und gibt dem Linker das zu den eigentlich Objektdateien des Programms dazu. Die Standardbibliothek, die solches Zeug wie malloc/free oder printf enthält, wird libc genannt. Um manche Funktionen implementieren zu können, ruft diese libc natürlich gelegentlich den Kernel auf, z.B. über einen Software-Interrupt - das ist dann ein Syscall.

Ist das so ungefähr der grobe Überblick, den du gesucht hast?
Titel: Re: Paging
Beitrag von: rizor am 08. January 2009, 22:43
Ja, super.
Danke.
Das bringt Licht ins Dunkel.
Dann werde ich also erst mal die libc schreiben.
Kannst du mir jetzt noch sagen, was da so alles reinkommen sollte.
Ich dachte mir folgendes:
- Speichermethoden
- Printmethoden
- Filesystemmethoden

[Edit]
Wie binde ich das ganze denn dann ein?
Also wie bringe ich dem gcc bei, dass an dieser Stelle meine Includes sind?
Ganz normal über -Include... als Parameter?
Titel: Re: Paging
Beitrag von: kevin am 08. January 2009, 23:29
Was da reingehört kann man dir genauer sagen als es dir lieb ist: Auf jeden Fall alle Funktionen, die der C-Standard vorschreibt. ;) Je nachdem, wie du weiter vorgehen willst, kannst du für alles weitere dann entweder deine eigenen Funktionen basteln oder einen vorhandenen Standard wie POSIX übernehmen.

Vorerst willst du vermutlich einen Teil von stdio.h (printf und Verwandte) und stdlib.h (malloc/free) implementieren. Stringfunktionen (string.h) kann man auch recht früh brauchen. Was sonst fehlt, merkst du ja nach und nach und implementierst dann halt die entsprechende Funktion. Die Linux-Manpages geben meistens recht brauchbare und trotzdem kompakte Informationen dazu, wie eine Funktion definiert ist (z.B. Verhalten im Fehlerfall und sowas), die du berücksichtigen solltest - je mehr du nach Standards arbeitest, um so leichter wird es später, Programme zu portieren.
Titel: Re: Paging
Beitrag von: rizor am 26. February 2009, 13:55
Hallo,

ich habe ein Problem mit meiner Initialisierung des Pagings.
Ich habe meinen Code ein wenig umgeschrieben und habe nun ein Problem mit dem Mappen der Bitmap.

Die Bitmap wird laut Anzeige auf 0 gemappt.
Leider bekomme ich dabei einen panic, da das System angeblich versucht die Page zu remappen.
Ich weiß leider nicht woran das liegt, denn  die Ausgaben sagen mir, dass in dem Bereich nichts gemappt wird außer der Bitmap.

Die Methoden sehen wie folgt aus:
void map_init(phys_t paddr , virt_t vaddr , size_t size){
size_t i , offset , overflow = 0;
uint32_t phys;
page_table_t table;

offset = ((uint32_t)vaddr >> PAGING_SHIFT_TABLE) % PAGING_TABLE_SIZE;

if(size > PAGING_TABLE_SIZE - offset){
if(kernel_dir[(uint32_t)vaddr >> PAGING_SHIFT_DIRECTORY + 1] == EMPTY)
create_table(kernel_dir , (uint32_t)vaddr >> PAGING_SHIFT_DIRECTORY + 1);

table = (page_table_t)((uint32_t)kernel_dir[(uint32_t)vaddr >> PAGING_SHIFT_DIRECTORY + 1] & PAGING_REMOVEFLAGS);

overflow = size - PAGING_TABLE_SIZE + offset;

for(i = 0; i < overflow; i++){
phys = (uint32_t)paddr + PAGING_TABLE_SIZE - offset + i * PAGING_PAGESIZE;

if(table[i] & PAGING_INUSE)
panic("Tried to map a mapped page");

table[i] = phys | PAGING_KERNEL;
}
}

if(kernel_dir[(uint32_t)vaddr >> PAGING_SHIFT_DIRECTORY] == EMPTY)
create_table(kernel_dir , (uint32_t)vaddr >> PAGING_SHIFT_DIRECTORY);

table = (page_table_t)(kernel_dir[(uint32_t)vaddr >> PAGING_SHIFT_DIRECTORY] & PAGING_REMOVEFLAGS);
for(i = 0; i < size - overflow; i++){
phys = (uint32_t)paddr + i * PAGING_PAGESIZE;

if(table[i + offset] & PAGING_INUSE)
panic("Tried to map a mapped page");

table[i + offset] = phys | PAGING_KERNEL;
}
puts("from %p to %p\n" , vaddr , (vaddr + size * PAGING_PAGESIZE));
}

und die Methode, die die Tabellen erstellt:

void create_table(directory_table_t directory , size_t dir_offset){
page_table_t table;

table = (page_table_t)palloc(PAGING_TABLE_SIZE * sizeof(page_table_t) / PAGING_PAGESIZE);

if(table == EMPTY)
//TODO call swapping
panic("Not enough physical memory");

memset(table , EMPTY , PAGING_TABLE_SIZE);

if(dir_offset >= PAGING_KERNEL_DIR_SIZE)
directory[dir_offset] = (uint32_t)table | PAGING_USER;
else
directory[dir_offset] = (uint32_t)table | PAGING_KERNEL;
}

Der Aufruf sieht wie folgt aus:
kernel_dir = (directory_table_t)palloc(PAGING_KERNEL_DIR_SIZE * sizeof(directory_table_t) / PAGING_PAGESIZE);
memset(kernel_dir , EMPTY , PAGING_KERNEL_DIR_SIZE);

//map the kernel
size = ((uint32_t)kernel_end - (uint32_t)kernel_start) / PAGING_PAGESIZE;
puts("\tMapped the kernel ");
map_init(kernel_start , kernel_mem_start , size);

//map the txt-video-memory
size = 80 * 25 * 2 / PAGING_PAGESIZE + 1;
puts("\tMapped the video-memory ");
map_init((phys_t)0xB8000 , (virt_t)0xB8000 , size);

//map the kernel_directory
puts("\tMapped the kernel-directory ");
map_init(kernel_dir , kernel_dir , 1);

//map the bitmap
size = bitmap_size / PAGING_PAGESIZE;
puts("\tMapped the bitmap ");
map_init(bitmap_entry, bitmap_entry , size);

PAGING_KERNEL setzt das Present, Readwrite und den Kernel-Flag in use

Vllt findet ihr den Fehler
Titel: Re: Paging
Beitrag von: rizor am 26. February 2009, 15:46
Mittlerweile habe ich herausgefunden woran es liegt.
Ich finde nur nicht den Fehler im Code.
Es steht an dem Eintrag 0 in der Tabelle bereits ein Eintrag (Adresse der Tabelle).
Ich weiß leider nicht warum
Titel: Re: Paging
Beitrag von: rizor am 03. March 2009, 22:16
Ich habe mal wieder ein wenig versucht den Fehler zu debuggen.
Nun weiß ich, dass der Fehler mit dem falschen Eintrag an der ersten Stelle einer Tabelle nur bei der ersten Tabelle auftritt.
Alle anderen stimmen überein.
Woran kann das liegen.
Der Fehler ist für mich völlig unlogisch.
Titel: Re: Paging
Beitrag von: rizor am 05. March 2009, 21:26
Ich habe mal versucht die Bitmap an eine andere Stelle zu mappen.
Das hat leider auch nicht funktioniert (bekomme einen triple fault).
Woran kann es liegen, dass das Problem allgemein mit der Bitmap besteht?

Ich habe leider überhaupt keine Idee.
Wenn ich mir das recht überlege, dürfte es an sich ja nicht an der Bitmap liegen, denn ich greife momentan nicht mehr auf die Bitmap zu und wenn ich die nicht mitmappe, dann funktioniert alles einwandfrei.
Titel: Re: Paging
Beitrag von: tarrox am 06. March 2009, 14:48
Wenn du weißt wo der Fehler auftrit, würde ich versuchen ihn zu finden. Daher ich würde schaun wann der erste Eintrag in der ersten Tabelle gesetzt wird. Dies musst du kannst du machen indem du nach jedem Schritt in dem der Speicher geändert wird schaust, ob sich der Wert geändert hat. Anstrangend aber meist nicht anders machbar.

PS: Ist Paging schon aktiviert oder machst du das erst jetzt.
Titel: Re: Paging
Beitrag von: rizor am 06. March 2009, 16:27
Paging ist nicht aktiviert.
Das Problem ist, dass ich mir die Adressen ausgeben lasse, die in die Einträge geschrieben werden.
Dort sehe ich definitiv, dass es keinen Eintrag gibt (außer den der Bitmap).
Sobald die Bitmap eingetragen werden soll, ist alles hinüber.
Keine Ahnung wieso.

Nein, Paging ist noch nicht aktiviert
Titel: Re: Paging
Beitrag von: tarrox am 06. March 2009, 18:48
Stürzt es in der Funktion ab ader dannach?
Wenn es in der Funktion abstürzt, musst du suchen wo es Abstürzt, also die genaue Zeile. Ansonaten muss man woanders schaun, je nachdem wo es abstürtzt^^.
Titel: Re: Paging
Beitrag von: rizor am 06. March 2009, 19:59
Ich habe es eben einmal gedebugged und dabei ist mir auufgefallen, dass er mir zweimal den gleichen Speicherbereich bekomme.
Das wundert mich, denn die physikalische Speicherverwaltung habe ich getestet.
Da ist mir kein Fehler aufgefallen.

Hier ist mal der Code, vllt fällt euch auf, wo der Fehler liegen kann:

phys_t palloc(size_t size){
lock_spin(mem_lock);
phys_t block = find_free(0 , bitmap_size , size);

if(block)
mark_res(block , size);
unlock_spin(mem_lock);

return block;
}

phys_t find_free(size_t lowest , size_t highest , size_t size){
size_t i , k;
size_t found_blocks = 0;
phys_t block;

for(i = lowest; i < highest; i++){
// these blocks are full
if(!bitmap_entry[i]){
found_blocks = 0;
continue;
}

if(bitmap_entry[i] == ~0x0){
if(found_blocks == 0)
block = (phys_t)(i * BLOCKS_PER_STDSIZE * BITMAP_SIZE);
found_blocks += BLOCKS_PER_STDSIZE;
}
else{
for(k = 0; k < BLOCKS_PER_STDSIZE; k++){
if(bitmap_entry[i] & (1 << k)){
if(found_blocks == 0)
block = (phys_t)((i * BLOCKS_PER_STDSIZE + k) * BITMAP_SIZE);
found_blocks++;

if(found_blocks > size)
break;
}
else
found_blocks = 0;
}
}

if(found_blocks > size)
return block;
}

return NULL;
}

void mark_res(phys_t addr , size_t num){
size_t i , index , d_block;

for(i = 0; i < num; i++){
d_block = (size_t)addr + i * BITMAP_SIZE;
index = d_block / BITMAP_SIZE / BLOCKS_PER_STDSIZE;
bitmap_entry[index] &= ~(1 << ((d_block / BITMAP_SIZE) & (BLOCKS_PER_STDSIZE - 1)));
}
}

Edit:
Das System stürzt erst ab, wenn ich Paging aktiviere.
Titel: Re: Paging
Beitrag von: rizor am 06. March 2009, 20:27
Ich habe den Fehler gefunden....
Das Problem lag daran, dass ich bei palloc 0 Seiten anfordere....
Titel: Re: Paging
Beitrag von: rizor am 06. March 2009, 22:15
Habe mal noch eine Frage.
Bin gerade dabei, den Code zu testen und dabei fällt mir auf, dass wenn ich eine Page suche, damit ich die dann mappen kann, dass ich einen Pagefault bekomme.
Der gdb meldet auch, dass er auf die Seite nicht zugreifen kann.
Die Tabelle ist gemappt.
Das ist kein Problem.

Der code, der den Fehler auslöst:
table[k] == EMPTY

Die Tabelle wurde ordentlich aus der Directory kopiert.
Wieso kann ich nicht darauf zugreifen?
An sich müsste in diesem Eintrag eine 0 stehen.
Titel: Re: Paging
Beitrag von: rizor am 07. March 2009, 22:06
Ich habe eben gesehen, dass an dieser Stelle schon ein Eintrag stehen sollte.
Das ist die erste Tabelle, in der auch der Kernel liegt.
Wie kann es dann sein, dass ich beim Zugriff einen Pagefault bekomme.
An sich müsste ich die einzelnen Tabellen nicht mitmappen, oder?
Falls doch, wie kann man das machen?
Titel: Re: Paging
Beitrag von: kevin am 07. March 2009, 23:01
Speicher auf den du zugreifst, muss gemappt sein, egal was da drin steht.
Titel: Re: Paging
Beitrag von: tarrox am 07. March 2009, 23:06
Am einfachsten ist es den 1023 Direktory Eintrag, selbst auf die Directory zu zeigen. Dadurch ist jeder ist jede Tabelle automatisch gemappt, wenn du sie in den Direktory reinschreibst.
//Alle Page-Tabels sind nun ab der Position 0xFFC00000 zu finden, und muss nicht extra gemappt werden.
kernel_dir[1023]=(kernel_dir|0x3);
addresse = 0xFFC00000+(i*0x1000);//gib die Addresse des i-ten Tabelle aus, um sie zu bearbeiten.
Titel: Re: Paging
Beitrag von: rizor am 07. March 2009, 23:09
Wie kann ich das Mapping ansonsten machen?
Also wie mappe ich jede einzelne Tabelle?
An sich mappe ich die Directory ja selbst in der Directory.
Also muss ich nach der Erstellung der Tabelle die Tabelle selbst noch einmal mappen?
Das wirkt für mich wie eine endlose Rekursion.

Edit:
@tarrox:
ich habe die Directory 1:1 gemappt.
Titel: Re: Paging
Beitrag von: rizor am 08. March 2009, 01:39
Ich finde es ein wenig ineffektiv, dass wenn ich meine Tabelle in die Directory eintrage, dass ich diese Tabellen und Pages einzeln mappen muss, damit ich auf sie zugreifen kann.
Muss das echt so gemacht werden?
Titel: Re: Paging
Beitrag von: kevin am 08. March 2009, 12:02
Wie tarrox schon angemerkt hat, kannst du im PD das PD selbst als PT eintragen. Ich hatte das erst nicht erwähnt, weil es am Anfang ein etwas verwirrender Hack ist. Wenn du das machst, hast du alle Page Tables hintereinander weg gemappt. Die Adressen der PTs stehen ja alle im PD drin, ganz normal. Wenn du jetzt das PD auch noch als PT benutzt, wird der Inhalt nicht mehr als Page-Table-Adressen interpretiert, die zum weiteren Auflösen der Adresse benutzt werden, sondern als die Adresse der Pages, die die Page Tables enthalten, selbst. Damit hast du alle im PD vorhandenen PTs gemappt.

Mal dir das am besten einfach mal auf ein Blatt Papier auf, wenn es dich verwirrt.
Titel: Re: Paging
Beitrag von: rizor am 08. March 2009, 12:17
Das habe ich gemacht.
Also meine PD in die PD selbst eingetragen.
Nur wie muss ich dann damit weiter umgehen (mein Schema funktioniert ja leider nicht)?

Ich habe es bisher so gemacht, dass ich beim Erstellen einer Tabelle diese in die PD eingetragen.
Muss ich das in die PD eintragen, die in der PD steht?
Hoffentlich konnte ich mich halbwegs ausdrücken.
Der Satz verwirrt mich selbst ;).
Dann habe ich aber glaub ich ein Problem.
Wenn Paging aktiviert ist, trage ich ja virtuelle Adressen in die PD ein.
Das müssten aber physikalische sein, oder?
Titel: Re: Paging
Beitrag von: kevin am 08. March 2009, 12:37
In PDs und PTs stehen immer physische Adressen, nie virtuelle.
Titel: Re: Paging
Beitrag von: rizor am 08. March 2009, 13:08
Hmm....

Dann mache ich irgendwas anderes falsch.

Ich bschreibe mal die Initialisierung.

Ich reserviere mir eine PD die alle Teile für den Kernelspace mappt.
Dann schreibe ich den Kernel, die Bitmap, den VGA-Speicher und die PD selbst.
Alles wird 1:1 gemappt.
Dann aktiviere ich paging.
So weit funktioniert auch alles.

Wenn ich nun Pages allozieren möchte, schaue ich in der PD nach und suche eine freie Seite oder erstelle mir eine neue Tabelle.
Diese neue Tabellen wird natürlich auch in die PD eingetragen.
Wenn ich nun versuche auf eine allozierte Seite zuzugreifen, bekomme ich einen Pagefault.
Wieso?
An sich nehme ich diesen Hack ja auch vor.
Titel: Re: Paging
Beitrag von: kevin am 08. March 2009, 14:20
Das kann ich so jetzt nicht sagen, wo der Fehler liegt. Deinen Code debuggen mußt du schon selbst. Am besten hältst du die qemu-VM mal an, nachdem du den PF bekommen hast. Dann schaust du nach, was cr2 ist, und versuchst diese Adresse im Monitor mit xp von Hand aufzulösen (auch auf die Flags achten). Vielleicht fällt dir dabei was auf.
Titel: Re: Paging
Beitrag von: rizor am 08. March 2009, 16:17
Also ich habe halt mehrere PF.
Den einen kann ich beheben, indem ich jede Tabelle, die ich in die PD eintrage, auch noch in die PD als gemappt eintrage.
Also nicht einfach PD = PT sondern dann auch noch einmal die Adresse der PT in der PD eintrage.
Das macht an sich auch sinn, auch wenn ich denke, dass es ein wenig ineffektiv ist.
Wieso geht es nicht, dass ich die Tabelle einfach in der PD eintrage?

Der andere Pagefault taucht beim Zugriff auf einen angeblich gemappten Bereich auf. Den muss ich aber erst noch genauer debuggen
Titel: Re: Paging
Beitrag von: kevin am 08. March 2009, 16:37
Den einen kann ich beheben, indem ich jede Tabelle, die ich in die PD eintrage, auch noch in die PD als gemappt eintrage.
Also nicht einfach PD = PT sondern dann auch noch einmal die Adresse der PT in der PD eintrage.
Das macht an sich auch sinn, auch wenn ich denke, dass es ein wenig ineffektiv ist.
Versteh ich nicht. Gib mir mal einen Speicherdump, damit ich sehe, was du meinst. Oder gleich ein Floppy-Image, wo man das Problem sieht.
Titel: Re: Paging
Beitrag von: rizor am 08. March 2009, 17:00
Naja, das sieht momentan so aus:
Ich habe meine PD mit 1024 Einträgen.
In jeden Eintrag kommt ja eine PT mit 1024 Einträgen.
Eine neue PT trage ich in die PD ein.
Wenn ich nun auf ein Element der PT zugreifen möchte um zu schauen, ob der Speicher frei ist, damit ich ihn belegen kann, bekomme ich den Pagefault.
Wenn ich aber die PT selbst mappe, dann kann ich darauf zugreifen.

table = (page_table_t)((uint32_t)krn_dir[i] & PAGING_REMOVEFLAGS);
for(k = 0; k < PAGING_TABLE_SIZE; k++){
//found a free page
if(table[k] == EMPTY && dir == -1){
dir = i;
tab = k;
}

Bei dem Zugriff table[k] bekomme ich einen Pagefault, wenn ich die table nicht selbst gemappt habe.

Ein image kann ich dir leider nicht geben, da ich das ganze schon wieder ein wenig überarbeitet habe.
Titel: Re: Paging
Beitrag von: kevin am 08. March 2009, 17:06
Jo, das ist logisch. Aber das sollte eigentlich kein Problem darstellen, weil du ja sowieso alle PTs gemappt hast, wenn du das PD nochmal als PT wiederverwendest.
Titel: Re: Paging
Beitrag von: rizor am 08. March 2009, 17:09
Das mache ich ja auch.
Ich mappe die PD selbst in der PD an der Stelle, an der sie auch physikalisch liegt.
Deshalb verstehe ich den Fehler ja auch nicht.
Titel: Re: Paging
Beitrag von: kevin am 08. March 2009, 17:14
Du hast physisch Speicher für alle 1024 Page Tables reserviert? Mal abgesehen davon, daß die PTs natürlich nicht mehr physisch an derselben Stelle liegen können, sobald du mehrere Prozesse mit eigenem Speicherkontext hast.
Titel: Re: Paging
Beitrag von: rizor am 08. March 2009, 17:20
Nein, ich alloziere Speicher nur dann, wenn ich eine Tabelle benötige.
Diese Tabelle wird dann in der PD eingetragen.
Dann kann ich aber die obige Abfrage nicht machen.

Edit:
Habe mir nochmal Gedanken gemacht und es ist an sich auhc selbstverständlich, dass ich die Tabelle selbst mappen muss, damit ich auf sie zugreifen kann.
Die Frage ist, was kann ich machen, damit ich die Tabelle nicht 1:1 mappen muss?
Ich möchte also dafür sorgen, dass die Tabelle immer im Kernelspace liegt.
Also wie ich sie mappen muss ist mir klar.
Ich verstehe nur nicht, wie ich dann wieder auf sie zugreifen kann.
Ich kann die virtuelle Adresse ja nicht in der PD eintragen
Titel: Re: Paging
Beitrag von: rizor am 08. March 2009, 19:23
Ich habe das ganze mal ein wenig umgeschrieben.
Ich habe mir nun die PD in die PD gemappt und verwende sie als Abbild der PD.
ist das soweit richtig?
Ich mache es jetzt also so, dass ich jede Seite, die ich alloziere gleichzeitig im Abbild auch "alloziere".
Dadurch müssten die Seiten gleich richtig gemappt sein, oder?
Das ganze wirkt aber recht aufwendig und unhandlich.
Deshalb frage ich mich, ob das Konzept passt.

Ist es möglich das so zu machen oder geht es einfacher?

Edit:
Bei meinem Konzept sind mir noch ein Problem eingefallen, auf die ich keine Lösung habe.
Mit der Abbildmethode kann ich nur eine PD abbilden, da das Abbild im Kernelspace liegt und ich dadurch in jeder PD das gleiche Abbild habe (Kernel in jeder PD)
Titel: Re: Paging
Beitrag von: rizor am 08. March 2009, 23:14
Am einfachsten ist es den 1023 Direktory Eintrag, selbst auf die Directory zu zeigen. Dadurch ist jeder ist jede Tabelle automatisch gemappt, wenn du sie in den Direktory reinschreibst.
//Alle Page-Tabels sind nun ab der Position 0xFFC00000 zu finden, und muss nicht extra gemappt werden.
kernel_dir[1023]=(kernel_dir|0x3);
addresse = 0xFFC00000+(i*0x1000);//gib die Addresse des i-ten Tabelle aus, um sie zu bearbeiten.

Ich habe mir noch einmal Gedanken gemacht.
Wie würde ich das denn implementieren, wenn ich nach einer freien Page suche.
Wenn ich in der PD selbst nachschaue bekomme ich einen Pagefault.
Muss ich dann in der PT nachschauen (die an sich die PD ist)?
Das mit der Adressberechnung verstehe ich noch nicht.
An sich schreibe ich doch in die PT-Einträge die physikalischen Adressen der wahren PTs, oder?
Titel: Re: Paging
Beitrag von: jgraef am 11. March 2009, 17:26
Wenn ich dich richtig verstanden habe, suchst du nach einer Methode, freie virtuelle Adressen zu suchen.

meinOS macht das so:
'gefunden' = 0
gehe durch PD bis 'gefunden' = 'suche' {
  wenn PDE present dann {
    gehe durch PT {
      wenn PTE present dann {
        'gefunden' = 0
      }
      ansonsten {
        'gefunden'++
      }
    }
  }
  ansonsten {
    'gefunden' += 1024
  }
}
'gefunden' ist eine variable, die die anzahl an zusammenhängenden freien virtuellen pages angibt. 'suche' gibt an, wie viele pages gesucht werden.

Wenn man 1024 PDEs durch hat und immer noch nicht genug, dann sollte man natürlich auch abbrechen... aber dann hat man wohl auch ein problem ;)

Ist wohl nicht das schnellst (ohne caching und so), aber die einfachste methode.
Titel: Re: Paging
Beitrag von: rizor am 11. March 2009, 21:26
Hallo, danke.
Soweit habe ich das Problem mitlerweile gelöst.
Jetzt habe ich nur gerade das Problem, dass ich nicht weiß, wie ich neue PTs eintragen soll.
Ich habe mir folgendes Schema überlegt.
Ich habe die PD an eine bestimmte Stelle in der PD gemappt.
Das mache ich für jeden einzelnen Task.
Wenn ich nun Paging aktiviert habe und herusgefunden habe, dass eine Stelle in der PD keine Tabelle besitzt, kann ich die ja einfach erstellen.
Genau das ist mein Problem.
Ich Interpretiere die PD ja als PD und nun frage ich mich, wie ich die neue PT eintragen kann.

Ein Beispiel zur Verdeutlichung:
Die PD ist an 0x1000 gemappt.
Nun finde ich heraus, dass an 0x2000 keine Tabelle ist.
Diese möchte ich nun erstellen.
Kann ich dann einfach sagen, dass ich an 0x2000 eine PT mit den Flags setze?
Wird diese neue Tabelle dann auch in der "echten" PD gesetzt ist?
Müsste doch an sich, oder?
Titel: Re: Paging
Beitrag von: kevin am 12. March 2009, 18:30
Ja, du schreibst du physische Adresse deiner neu allozierten PT nach 0x1008, also den dritten Eintrag des PDs.
Titel: Re: Paging
Beitrag von: rizor am 13. March 2009, 00:45
Ich wollte noch ein wenig Speicher sparen und habe die gesamte PD auf das letzte Element der letzten Tabelle gemappt.
Das müsste gehen, oder?
Mein Problem ist nur, dass ich einen PF bekomme, wenn ich versuche diese Seite anzusprechen.

Finde den Fehler leider nicht.

create_table(dir , PAGING_TABLE((uint32_t)PAGING_VIRT_DIR_ADDR));
table = (page_table_t)dir[PAGING_TABLE((uint32_t)PAGING_VIRT_DIR_ADDR)];
table[PAGING_PAGE((uint32_t)PAGING_VIRT_DIR_ADDR)] = (uint32_t)dir | PAGING_KERNEL;

void create_table(directory_table_t directory , size_t dir_offset){
page_table_t new_table = (page_table_t)palloc(1);

if(dir_offset <= PAGING_KERNEL_DIR_END)
directory[dir_offset] = (uint32_t)new_table | PAGING_KERNEL;
else
directory[dir_offset] = (uint32_t)new_table | PAGING_USER;

new_table = (page_table_t)directory[dir_offset];
memset(new_table , EMPTY , PAGING_TABLE_SIZE);

invalid_tlb((virt_t)(directory + sizeof(uint32_t) * dir_offset));
}

Der Aufruf findet wie folgt statt:

ret_addr = alloc_pages((directory_table_t)PAGING_VIRT_DIR_ADDR ,
   (virt_t)0x0 , (virt_t)PAGING_KERNEL_MEM_END , size);

Keine Ahnung woran das liegt.
Habe es auch mal gedebuggt aber leider nicht den Fehler gefunden.
Titel: Re: Paging
Beitrag von: Jidder am 13. March 2009, 00:57
Wie sparst du Platz? (<- die einzige rhetorische Frage^^) Also man kann maximal eine Page sparen, wenn man self-mapping page tables verwendet. Kann man machen, muss man aber nicht. Vor allem wenn es nicht klappt. ;) Aber irgendwie machst du das auch gar nicht.

Zum Thema:

Weißt du, welche C-Instruktion genau den Page Fault verursacht?

table = (page_table_t)dir[PAGING_TABLE((uint32_t)PAGING_VIRT_DIR_ADDR)];Enthält table dann nicht ein physische Adresse? Ist die garantiert gemappt? Und sind nicht die Flags noch dabei?

Wo kommt da der Aufruf von alloc_pages ins Spiel?
Titel: Re: Paging
Beitrag von: rizor am 13. March 2009, 11:27
Mir ist der Fehler aufgefallen.
Jetzt funktioniert es.
Trotzdem danke.