Autor Thema: Problem mit Paging  (Gelesen 3660 mal)

Hobby Programmiere

  • Beiträge: 42
    • Profil anzeigen
Gespeichert
« am: 29. April 2010, 21:40 »
Abend zusammen.
Ich bin zur Zeit beim Speichermanager. Der Physikalische funktioniert auch schon, allerdings habe ich jetzt schon seit Wochen Schwierigkeiten mit Paging. Ich habe dieses Tut http://www.jamesmolloy.co.uk/tutorial_html/6.-Paging.html gelesen, und versucht, auf diesen Anregungen einen Virtuellen Speichermanager zu schreiben. Allerdings endet es immer in einer Reboot Schleife, und zwar, direkt, nach dem, Paging aktiviert wurde. Es gibt keine Pagfault, nichts! Ich habe auch schon die Forensuche bemüht, allerdings habe ich dort nichts gefunden, was mit helfen könnte.
Meine Vermutung ist, dass es entweder am Aufbau meiner Pagetables oder aber beim erstellen dieser liegen muss. Da ich aber nicht weis, ob ich mit dieser Vermutung richtig liege, poste ich hier den ganzen Code, damit ihr mir möglichst gut helfen könnt.
Physikalischer Speichermanager:
// Defines
#define PAGESIZE 0x1000

/* Initialize the PMM
 * Returnvalue: TRUE if all was ok, FALSE if smth. went wrong
 */
int PMMInit();

/* Alloc a frame
 * Arguments: The frame to alloc
 * Returnvalue: TRUE if all was ok, FALSE if smth. went wrong
 */
int MallocFrame(const u_long Frame);

/* Free a frame
 * Arguments: The frame to free
 * Returnvalue: TRUE if all was ok, FALSE if smth. went wrong
 */
int FreeFrame(const u_long Frame);

/* Get the value of a frame
 * Arguments: The frame to get
 * Returnvalue: The value of the frame
 */
int GetFrame(const u_long Frame);

/* Malloc ram
 * Arguments: Size of ram to malloc; Pagealing?; Pointer to the startaddr
 * Returnvalue: The addr of the ram
 */
u_long PMM_Malloc(const u_long Size, const int Align, u_long* Phys);

/* Free ram
 * Arguments: The start addr of the the ram; Size of the ram
 */
void PMM_Free(const u_long StartAddr, const u_long Size);

/* Initialize the bitmap (bitset)
 */
void InitBitmap();

/* Get the actually placement addr
 * Returnvalue: The placement addr
 */
u_long GetPlacementAddr();

/* Get the first free frame in the bitmap (bitset)
 * Returnvalue: The first free frame
 */
u_long GetFirstFreeFrame();

// Vars
u_long* Bitmap;           // The Bitmap
u_long  NFrames;          // The number of frames in the bitmap
int     IsBitsetCreated;  // Is the bitset created?


u_long PlacementAddr = (u_long) &kernel_end;     // Address of the first free memory
u_long OldPlacementAddr = (u_long) &kernel_end;  // The old address of the first free memory

// Create the Bitmap
void CreateBitmap()
{
    // Compute the number of frames
    NFrames = 0x0;
    struct SMbs_MMap_Entry* MMap = (struct SMbs_MMap_Entry*) pMultibootstruct->MMap_addr;
    while(MMap < (struct SMbs_MMap_Entry*) pMultibootstruct->MMap_addr + pMultibootstruct->MMap_length)
    {
        if(MMap->Type == 1)
        {
            // Vars
            u_int64 EndAddr = MMap->Length;

            // Save the addr
            NFrames = EndAddr;
        }

        MMap = (struct SMbs_MMap_Entry*) ((u_int32) MMap + MMap->Size + sizeof(u_int32));
    }
    NFrames = NFrames / PAGESIZE;
    //NFrames = (CMOSRead(0x30) | CMOSRead(0x31) << 8) / PAGESIZE;

    // Create the bitmap
    Bitmap = (u_long*) PMM_Malloc(NFrames / 32, 0, 0);

    // Init the bitmap
    InitBitmap();

    // The bitmap is now created
    IsBitsetCreated = TRUE;
}

// Init the PMM
int PMMInit()
{
    // Create the Bitmap
    CreateBitmap();

    return TRUE;
}

// Malloc a frame
int MallocFrame(const u_long Frame)
{
    // Set the bit
    Bitmap[Frame / 32] |= (1 << Frame % 32);

    return TRUE;
}

// Free a frame
int FreeFrame(const u_long Frame)
{
    // Delete the bit
    Bitmap[Frame / 32] &= ~(1 << Frame % 32);

    return TRUE;
}

// Get the value of a frame
int GetFrame(const u_long Frame)
{
    // Is the bit set?
    return (Bitmap[Frame / 32] & (1 << Frame % 32));
}

// Init the bitmap
void InitBitmap()
{
    // Vars
    struct SMbs_MMap_Entry* MMap = (struct SMbs_MMap_Entry*) pMultibootstruct->MMap_addr;

    // Reset the bitmap
    k_memset(Bitmap, 1, NFrames / 32);

    // Search the MMap for free memory
    while(MMap < (struct SMbs_MMap_Entry*) pMultibootstruct->MMap_addr + pMultibootstruct->MMap_length)
    {
        // Is the address free?
        if(MMap->Type == 1)
        {
            // Vars
            u_int64 Addr = MMap->BaseAddr;
            u_int64 EndAddr = MMap->Length;

            // The address is free! Mark the bitmap-entry
            while(Addr < EndAddr)
            {
                FreeFrame(Addr / PAGESIZE);
                Addr += PAGESIZE;
            }
        }

        MMap = (struct SMbs_MMap_Entry*) ((u_int32) MMap + MMap->Size + sizeof(u_int32));
    }
}

// Return the placement addr
u_long GetPlacementAddr()
{
    return PlacementAddr;
}

// Return the first free frame
u_long GetFirstFreeFrame()
{
    // Vars
    u_long Index;
    u_long Offset;

    // Search for a free frame
    for(Index = 0; Index < (NFrames / 32); Index++)
    {
        for(Offset = 0; Offset < 32; Offset++)
        {
            if(!(Bitmap[Index] & 1 << Offset))
                return Index * 32 + Offset;
        }
    }

    // If nothing was found, return -1
    return -1;
}

// Malloc memory
u_long PMM_Malloc(const u_long Size, const int Align, u_long* Phys)
{
    // Vars
    u_long Addr;

    // Page alignt?
    if(Align == TRUE && PlacementAddr & 0xFFFFF000)
    {
        PlacementAddr &= 0xFFFFF000;
        PlacementAddr += PAGESIZE;
    }

    // If Phys, save the start address of the new memory
    if(Phys != 0)
        *Phys = PlacementAddr;

    // Reserv memory
    Addr = PlacementAddr;
    PlacementAddr += Size;

    // If the bitmap is created, mark the bits in the bitset
    if(IsBitsetCreated == TRUE)
    {
        // Temp-Vars
        u_long Temp = Addr;

        while(Temp < PlacementAddr)
        {
            MallocFrame(Temp / PAGESIZE);
            Temp += PAGESIZE;
        }
    }

    return Addr;
}

// Free memory
void PMM_Free(const u_long StartAddr, const u_long Size)
{
    // Vars
    u_long Addr = StartAddr;

    // Clear the bits in the bitset
    while(Addr < StartAddr + Size)
    {
        FreeFrame(Addr / PAGESIZE);
        Addr += PAGESIZE;
    }
}
Virtueller Speichermanager:
// A page
struct SPage
{
    u_int32 Present : 1;    // Is the page present in the memory?
    u_int32 RW : 1;         // Read- or Write-able
    u_int32 User : 1;       // User or supervisor previligs
    u_int32 Accessed : 1;   // Has the page been accessed since the last refresh?
    u_int32 Dirty : 1;      // Has the page been changed since the last refresh?
    u_int32 Reserved : 7;   // Reserved
    u_int32 Frame : 20;     // Frameaddr in the physical memory
};

// A pagetable
struct SPage_Table
{
    struct SPage Pages[1024];   // All pages in the pagetable
};

// Pagediretory
struct SPage_Directory
{
    u_int32 TablesPhysical[1024];        // Pointer to the page tables
    struct SPage_Table* Tables[1024];   // The page tables
    u_int32 PhysicalAddr;                // Physicaladdr
};

/* Initalize the VMM
 * Returnvalue: TRUE if all was ok, FALSE if smth. went wrong
 */
int VMMInit();

/* Malloc a page
 * Arguments: The page to malloc; User?; RW?
 * Returnvalue: TRUE if all was ok, FALSE if smth. went wrong
 */
int MallocPage(struct SPage* Page, int User, int RW);

/* Free a page
 * Arguments: The page to free
 */
void FreePage(struct SPage* Page);

/* Get the page for an addr
 * Arguments:
 * Returnvalue: The page for the addr
 */
struct SPage* GetPage(u_long Addr);

// Vars
struct SPage_Directory* PageDirectory;     // The page directory

// Init the VMM
int VMMInit()
{
    // Create a page directory
    u_long Phys;
    PageDirectory = (struct SPage_Directory*) PMM_Malloc(sizeof(struct SPage_Directory), TRUE, &Phys);
    k_memset(PageDirectory, 0, sizeof(struct SPage_Directory));
    PageDirectory->PhysicalAddr = Phys;

    // Map the memory from physical to virtual
    // NOTE: We only map the memory which is actually used!
    int Addr = 0;
    while(Addr < GetPlacementAddr())
    {
        MallocPage(GetPage(Addr), FALSE, TRUE);
        Addr += PAGESIZE;
    }

    // Enable paging
    asm ("mov %0, %%cr3":: "r"(&PageDirectory->PhysicalAddr));
    extern void InitPaging();
    InitPaging();

    return TRUE;
}

// Malloc a page
int MallocPage(struct SPage* Page, int User, int RW)
{
    // Is the page already allocated?
    if(Page->Frame != 0)
        return FALSE;

    // Malloc the page
    // Search a free frame
    u_long Frame = GetFirstFreeFrame();

    // If no Frame free?
    if(Frame == -1)
        return FALSE;

    MallocFrame(Frame * PAGESIZE);
    Page->Present = 1;
    Page->User = User ? 1 : 0;
    Page->RW = RW ? 1 : 0;
    Page->Frame = Frame;

    return TRUE;
}

// Get a page
struct SPage* GetPage(u_long Addr)
{
    // Compute the index of the page table
    u_int32 Index = Addr / PAGESIZE / 1024;

    // Is the page already existing?
    if(PageDirectory->Tables[Index])
    {
        // Return the page
        return &PageDirectory->Tables[Index]->Pages[(Addr / PAGESIZE) % 1024];
    }
    else
    {
        // The page is not already existing, create it
        u_long Temp;
        PageDirectory->Tables[Index] = (struct SPage_Table*) PMM_Malloc(sizeof(struct SPage_Table), TRUE, &Temp);
        k_memset(PageDirectory->Tables[Index], 0, PAGESIZE);
        PageDirectory->TablesPhysical[Index] = Temp | 0x7;
        return &PageDirectory->Tables[Index]->Pages[(Addr / PAGESIZE) % 1024];
    }

}

// Free a page
void FreePage(struct SPage* Page)
{
    // Free the frame and the page
    FreeFrame(Page->Frame);
    Page->Frame = 0x0;
}
Ich hoffe, dass mir jemand helfen kann, und bedanke mich schoneinmal für Hilfe im voraus.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 30. April 2010, 09:13 »
Abend zusammen.
Ich bin zur Zeit beim Speichermanager. Der Physikalische funktioniert auch schon, allerdings habe ich jetzt schon seit Wochen Schwierigkeiten mit Paging. Ich habe dieses Tut http://www.jamesmolloy.co.uk/tutorial_html/6.-Paging.html gelesen, und versucht, auf diesen Anregungen einen Virtuellen Speichermanager zu schreiben. Allerdings endet es immer in einer Reboot Schleife, und zwar, direkt, nach dem, Paging aktiviert wurde. Es gibt keine Pagfault, nichts!
Ohne mir deinen Code angeschaut zu haben, widerspreche ich dir hier schonmal. Es gab ganz sicher einen Page Fault. Aber beim Versuch, den Page-Fault-Handler aufzurufen ist der Prozessor in den nächsten Page Fault gerannt (weil der Code nicht korrekt gemappt ist) und hat damit dann einen Double Fault ausgelöst. Gleiches Spielchen für den Double Fault, gibt einen Triple Fault, was einen CPU-Reset bedeutet.

Zitat
Physikalischer Speichermanager:
Englisch "physical", aber deutsch "physisch", nicht "physikalisch" ;)

u_long PMM_Malloc(const u_long Size, const int Align, u_long* Phys)Hat nichts mit deinem Problem zu tun, aber dieses Interface ist komplizierter als es sein müsste: Nicht-alignten physischen Speicher braucht kein Mensch.

// A page
struct SPage
{
    u_int32 Present : 1;    // Is the page present in the memory?
    u_int32 RW : 1;         // Read- or Write-able
    u_int32 User : 1;       // User or supervisor previligs
    u_int32 Accessed : 1;   // Has the page been accessed since the last refresh?
    u_int32 Dirty : 1;      // Has the page been changed since the last refresh?
    u_int32 Reserved : 7;   // Reserved
    u_int32 Frame : 20;     // Frameaddr in the physical memory
};
Bist du dir sicher, dass der Compiler hier das richtige generiert? Die Reihenfolge in Bitfeldern ist im Standard undefiniert, deswegen bin ich da normal eher vorsichtig und nehme einfach einen uint32_t für das ganze zusammen.

asm ("mov %0, %%cr3":: "r"(&PageDirectory->PhysicalAddr));Das ist ein & zu viel, glaube ich.

Ansonsten würde ich dir mal empfehlen, an der Stelle bevor du Paging einschaltest, eine Endlosschleife hinzusetzen und dir dann im qemu-Monitor mal genau anzuschauen, ob das alles Sinn ergibt. Also per info registers anschauen, ob cr3 vernünftig aussieht, und dann z.B. mit xp /20 0x123000 den Speicher anschauen und manuell eine virtuelle Adresse (von Kernelcode) aufzulösen. Dabei sieht man meistens, was noch falsch ist.
« Letzte Änderung: 30. April 2010, 09:15 von taljeth »
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Hobby Programmiere

  • Beiträge: 42
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 30. April 2010, 18:29 »
Das mit der Pagestruct habe ich überprüft. Sie ist insgesamt 32Bit also 4 Byte groß, was ja auch theoretisch zutreffen sollte.
Was cr3 angeht, da steht ebenfalls die richtige Adresse drin. Aber da bin ich mir jetzt nicht mehr so sicher. In dem Tut, was ich gelesen habe, schreibt der ja die gesamte Struktur rein. Aber in einem Tut von OsDev.org schreiben die, dass nur die Adresse des Pagedirectories rein muss. Was stimmt den da?
Und wie soll ich nachsehen, ob eine Adresse falsch umgerechnet wird, er rebootet doch, sobald Paging aktiviert wird?

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 30. April 2010, 19:20 »
Das mit der Pagestruct habe ich überprüft. Sie ist insgesamt 32Bit also 4 Byte groß, was ja auch theoretisch zutreffen sollte.
Ja, schon. Aber die Frage ist, ob Present korrekt 0x1 ist oder 0x80000000. Die Reihenfolge ist nicht definiert und ich bin mir nicht sicher, was gcc auf x86 macht.

Zitat
Was cr3 angeht, da steht ebenfalls die richtige Adresse drin. Aber da bin ich mir jetzt nicht mehr so sicher. In dem Tut, was ich gelesen habe, schreibt der ja die gesamte Struktur rein. Aber in einem Tut von OsDev.org schreiben die, dass nur die Adresse des Pagedirectories rein muss. Was stimmt den da?
Im Zweifel das Intel-Manual fragen. :) Es reicht dir eigentlich anzunehmen, dass in cr3 die Adresse des PD ist, auch wenn in Wirklichkeit in den unteren Bits ein paar Flags sind - aber wenn du nichts spezielles vorhast, bleiben die auf 0.

Zitat
Und wie soll ich nachsehen, ob eine Adresse falsch umgerechnet wird, er rebootet doch, sobald Paging aktiviert wird?
Wie gesagt, Paging nicht einschalten, sondern davor eine Endlosschleife hinbauen.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Hobby Programmiere

  • Beiträge: 42
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 02. May 2010, 21:17 »
Vielleicht hast du ja Recht. Ich werde es auf jeden Fall noch einmal mit einem einfachen int probieren.
Wie genau meinst du das mit dem Umrechnen von Adressen, bevor das Paging aktiviert ist? Soll ich mir irgendeine Adresse nehmen, und diese von Hand umrechnen, und es dann noch einmal den Kernel versuchen lassen? Ich glaube, wir reden in diesem Punkt etwas an einander vorbei.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 02. May 2010, 22:35 »
Von Hand umrechnen, anhand des Page Directory und der Page Table im Speicher der VM. Du machst also von Hand das, was der Prozessor normal machen würde. Normalerweise fällt dir dabei dann der Fehler auf.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Hobby Programmiere

  • Beiträge: 42
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 04. May 2010, 21:32 »
Werde ich dann mal ausprobieren.

Hobby Programmiere

  • Beiträge: 42
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 06. May 2010, 21:51 »
Mh, habe mal nach Infos gesucht, aber nirgendwo was gefunden. Wie soll man den einen physische Adresse in eine virtuelle umrechnen. Die kann man doch überall hin mappen. Umgekehrt ist ja einfach.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 06. May 2010, 22:32 »
Die kann man überall hinmappen, richtig. Also merkst du dir einfach, wo du sie hingemappt hast, schon stellt sich das Problem nicht. ;-)

 

Einloggen