[OSDEV] Problem ze stronnicowaniem

0

Witam
Pracuję nad Memorry Manager'em dla mojego OS'a.
Napisałem obsługę tablic bitowych, ale za to zatrzymałem się na pagingu.

#include "mm/fm.h"
#include "mm/flags.h"
#include "console.h"

#define PT_START 0x200000 //Adres, w którym zaczynają się PT
#define PT_SIZE 0x1000 //Rozmiar 1 PT

#define PD_ADDR 0x29000 //Adres, w którym znajduje się PD
#define PD_SIZE 0x1000 //Rozmiar PD

#define PAGE_SIZE 0x1000 //Rozmiar 1 strony 

long * pagedir = (long *)PD_ADDR;
long freekernelmem = 0x800000; //8 MB
long freeusermem = 0xC0000000; //3 GB

/*****************************************************************************/
/* Funkcja wstawia stronę o adresie wirtualnym vaddr do podanego pd          */
/*****************************************************************************/
void put_page( long * pd, long vaddr, long addr, long flags )
{
    long pd_entry, pt_entry;
    long * pagetable;
    
    pd_entry = vaddr / ( PAGE_SIZE * 1024 ); //Numer PAGE TABLE
    pagetable = (long *)pd[pd_entry]; //Wskaźnik na wybrany PT
    
    pt_entry = ( vaddr % ( 1024 * PAGE_SIZE ) ) / PAGE_SIZE; //Numer wpisu w PT
    
    pagetable[pt_entry] = addr | flags; //Ustawienie fizycznego adresu i flag
}

/*****************************************************************************/
/* Funkcja alokująca n stron (strony użytkownika)                            */
/*****************************************************************************/
void * ualloc_pages( long n )
{
    long i;
    long retval;
    long freeframe;
    
    retval = freeusermem;
    
    for ( i = 0; i < n; i++ ) //Zaalokowanie wybranych stron
    {
        freeframe = find_free_frame();
        put_page( pagedir, freeusermem, ( freeframe * 4096 ), PTE_PRESENT | PTE_WRITE ); //Ustawienie strony
        set_frame_status( freeframe, 1 ); //Ustawienie statusu ramki na 1 (zajęta)
        freeusermem += 0x1000;
    }
    
    return retval;
}

/*****************************************************************************/
/* Funkcja inicjująca MM niskiego poziomu. Inicjuje FM, tworzy tablice       */
/* stron, włącza stronnicowanie i wyświetla odpowiedni komunikat ;)          */
/*****************************************************************************/
void init_paging( void )
{
    printf( "Initializing low-level MM... " );

    init_fm(); //Inicjuje Frame Manager'a
    
    long i;
    long * pagetable;
    
    for ( i = 0; i < 1024; i++ ) //Tworzy Page Tables
    { 
        pagedir[i] = ( PT_START + ( i * PT_SIZE ) ) | PDE_PRESENT | PDE_WRITE; //Ustawia flagi
    }
    
    pagetable = (long *) pagedir[0];
    
    for ( i = 0; i < 1024; i++ ) //Mapuje pierwsze 4 MB
    {
        pagetable[i] = ( i * 4096 ) | PTE_SUPERVISOR | PTE_PRESENT | PTE_WRITE;
    }
    
    pagetable = (long *) pagedir[1];
    
    for ( i = 0; i < 1024; i++ ) //Mapuje następne 4 MB
    {
        pagetable[i] = ( i * 4096 + 0x400000 ) | PTE_SUPERVISOR | PTE_PRESENT | PTE_WRITE;
    }
    
    extern enable_paging();
    enable_paging();
    
    printf( "done\n" );
}

Paging inicjuje kodem

GLOBAL enable_paging
enable_paging:
  mov eax, 0x29000
  mov cr3, eax
  mov eax, cr0
  ;or eax, 0x80000000
  or eax, 0x80010000
  mov cr0, eax
  jmp .enabled
  .enabled:
  ret

Rezultatem włączenia stronnicowania jest triplefault. Wykłada się przy enable_paging

Ma może ktoś pomysł, jak to naprawić??

0

Fajnie jeszcze jakbys napisal na ktorej instrukcji sie sypie.

0

w logach bosha EIP wskazuje na jmp .enabled

0

czy zamiast or eax, 0x80010000 nie powinno być or eax, 0x80000000 ? :>

0

Bez zmian, dalej reset.

0

Z doświadzeń przy moim OS'ie wiem, że błąd nie musi leżeć w kodzie stronnicowania. U mnie na przykład działo się identycznie a winą był zły adres GDT w GDTR, posprawdzaj pozostałe moduły OS'a, może tam leży błąd ;)

0

@milyges: to co podalem to nowa wersja stronnicowania. Poprzednio mialem prosty paging fizyczny = wirtualny i bez tablic bitowych. Wtedy - żadnych błędów. Więc gdzie ma tkwić błąd jak nie w kodzie stronnicowania?

0

U mnie tez na Fizyczny = Wirtualny chodziło, ale jak pokombinowałem z pagingiem odkazało sie ze w GDTR mam zły adres GDT (działa adres wirtualny a miałem fizyczny :])

0

Pierwsze 8MB jest fizyczny = wirtualny, a gdt jest w 1 MB

0

Hmmm, a zakomentuj or eax, 0x80010000, i po zainicjowaniu PGDir i PGTabów, zrób dumpa wartosci najpierw PGDir'a (sprawdz czy na pewno są tam adresy tablic) a jesli tam wszystko OK to posprzwdzaj czy w tablicach masz wszystko OK (ja tak zawsze robie :P)

0

Wszystkie PT i PD się zgadzają.

0

Hmm. Czyli jeśli sie nie myle nie ma błędu w tym kodzie (on chyba inicjuje PGDir i PGTabs i włącza stronnicowanie, a jesli adresy sie zgadzają to ... :])

0

Problem rozwiązałem - przepisałem kod :)

Teraz dla odmiany pagefault...

#include "mm/fm.h"
#include "mm/flags.h"
#include "console.h"

#define PD_ADDR 0x9C000 //Adres, w którym znajduje się PD

#define PT_START 0x200000 //Adres, w którym zaczynają się PT
#define PT_SIZE 0x1000 //Rozmiar 1 PT

#define PAGE_SIZE 0x1000 //Rozmiar 1 strony 

long * pagedir = (long *)PD_ADDR;

void put_page( long * pd, long vaddr, long addr, long flags )
{
    long pd_entry, pt_entry;
    long * pagetable;
   
    pd_entry = vaddr / ( PAGE_SIZE * 1024 ); //Numer PAGE TABLE
    pagetable = (long *)pd[pd_entry]; //Wskaźnik na wybrany PT
   
    pt_entry = ( vaddr % ( 1024 * PAGE_SIZE ) ) / PAGE_SIZE; //Numer wpisu w PT
   
    pagetable[pt_entry] = addr | flags; //Ustawienie fizycznego adresu i flag
}

void init_paging( void )
{
    printf( "Initializing paging... " );
    
    unsigned long * pt;
    unsigned long i;
 
    pt = (unsigned long *)PT_START;
    for ( i = 0; i < 2048; i++ )
    {
        pt[i] = ( i * 4096 ) | PTE_PRESENT | PTE_WRITE;
    }

    for ( i = 0; i < 1024; i++ )
    {
        pagedir[i] = ( PT_START + ( PT_SIZE * i ) ) | PDE_PRESENT | PDE_WRITE;
    }
    
    write_cr3( pagedir );
    write_cr0( read_cr0() | 0x80000000 );
    
    printf( "done\n" );
    
    //No i page fault :/
    put_page( pagedir, 0xC0000000, 0x800000, PTE_PRESENT | PTE_WRITE );

    long * test = (long *) 0xC0000000;
    *test = 123;
}

Wyjątek wykonany przez "non-present page", a flagi chyba dobre ustawiam...

Może jeszcze dorzucę kod pliku flags.h

#ifndef FLAGS_H_
#define FLAGS_H_

/* Flagi dla PDE */
#define PDE_PRESENT 0x1 //Present
#define PDE_WRITE 0x2 //Read/Write
#define PDE_SUPERVISOR 0x4 //User/Supervisor
#define PDE_WRITE_THROUGH 0x8 //Write-throught
#define PDE_CACHE_DISABLED 0x10 //Cache disabled
#define PDE_ACCESSED 0x20 //Accessed

/* Flagi dla PTE */
#define PTE_PRESENT 0x1 //Present
#define PTE_WRITE 0x2 //Read/Write
#define PTE_SUPERVISOR 0x4 //User/Supervisor
#define PTE_WRITE_THROUGH 0x8 //Write-throught
#define PTE_CACHE_DISABLED 0x10 //Cache disabled
#define PTE_ACCESSED 0x20 //Accessed
#define PTE_DIRTY 0x40 //Dirty
#define PTE_GLOBAL 0x100 //Global Page

/* Flagi errorcode's dla PF */
#define PF_PAGELEVELPROTECTION 0x1 //The fault was caused by a page-level protection violation.
#define PF_WRITE 0x2 //The access causing the fault was a write.
#define PF_USER 0x4 //The access causing the fault originated when the processor was executing in user mode.
#define PF_RESERVED 0x8 //The fault was caused by reserved bits set to 1 in a page directory.
#define PF_INSTRUCTION 0x10 //The fault was caused by an instruction fetch.


#endif /*FLAGS_H_*/

Gdzie tkwi w tym kodzie błąd ??

1 użytkowników online, w tym zalogowanych: 0, gości: 1