2016-07-02 38 views
3

Ich implementiere meinen eigenen Kernel und ich stecke fest. Ich versuche meinen Kernel in die hohen virtuellen Adressen zu laden. Ich habe das Problem der Identität Adressen durch Identity Mapping der niedrigen 1M von RAM angegangen. Ich habe einen init Abschnitt erstellt, der an die physikalische Adresse des Kernels verschoben wird, um die Paging-Initialisierung zu übernehmen. Der virtuelle Offset meines Kerns ist 0xc0000000. Das ist meine Linker-Skript:QEMU dreifache Fehler beim Aktivieren von Paging

OUTPUT_FORMAT(elf32-i386) 
ENTRY(start) 

KERNEL_VIRTUAL_OFFSET = 0xC0000000; 

SECTIONS 
{ 
    . = 1M; 
    kernel_start = .; 

    start_init = .; 
    .init ALIGN(4K) : 
          { *(.multiboot); 
          *(.init); 
          *(.tables); 
          } 
    end_init = .; 

    . += KERNEL_VIRTUAL_OFFSET; 

    kernel_high_half_start = .; 
    .text ALIGN(4K) : AT(ADDR(.text) - KERNEL_VIRTUAL_OFFSET) 
         {*(.text) } 
    .data ALIGN(4K) : AT(ADDR(.data) - KERNEL_VIRTUAL_OFFSET) 
         { *(.data) } 
    .rodata ALIGN(4K) : AT(ADDR(.rodata) - KERNEL_VIRTUAL_OFFSET) 
         { *(.rodata) } 
    .bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_VIRTUAL_OFFSET) 
         { *(.bss) } 
    kernel_high_half_end = .; 

    kernel_end = . - KERNEL_VIRTUAL_OFFSET; 
} 

Hier ist mein Einstiegspunkt. Ich verwende GRUB als meinen Bootloader. Es erfolgreich Stiefel und springt in meinen Einstiegspunkt wegen des init Abschnitts:

its 32 
    section .multiboot 
    ;grub bootloader header 
      align 4 
      dd 0x1BADB002   ;magic 
      dd 0x00     ;flags 
      dd - (0x1BADB002 + 0x00) ;checksum. m+f+c should be zero 

    ; Declarations 
    global start 
    extern kmain 
    extern paging_init 
    extern kernel_page_directory 

    section .init 

    enable_paging: 
     mov eax, kernel_page_directory 
     mov cr3, eax 
     mov eax, cr0 
     or eax, 0x80000000 
     mov cr0, eax ; ***** PAGING ENABLED HERE ***** 
     ret 

    start: 
     cli   ;block interrupts 
     mov esp, init_stack 
     call paging_init 
     call enable_paging 

     ;mov eax, 0xb8000 
     ;mov byte[eax], 'h' 
     ;mov byte[eax+1], 0x7 

     ; Now high half kernel is mapped to the page directory 
     mov esp, stack_space ;set stack pointer 
     push ebx ; grub boot info 
     call kmain 

    loop: 
     hlt   ;halt the CPU 
     jmp loop 

    resb 4096; 4KB small stack for my init section. 
    init_stack: 

    section .bss 
    resb 8192 ;8KB for stack 
    stack_space: 

Hier ist mein Code der die Seitentabelle und das Seitenverzeichnis des Kernels füllt. Wie Sie sehen können, ist der gesamte Code in den init Abschnitt verknüpft, Verlagerung Probleme zu vermeiden:

page_table_t kernel_page_directory[PAGE_DIR_SIZE] 
__attribute__((aligned(PAGE_SIZE))) __attribute__((section(".tables"))) = {0}; 

page_pointer_t kernel_page_tables[PAGE_TABLE_SIZE] 
__attribute__((aligned(PAGE_SIZE))) __attribute__((section(".tables"))) = {0}; 

page_pointer_t identity_page_table[PAGE_TABLE_SIZE] 
__attribute__((aligned(PAGE_SIZE))) __attribute__((section(".tables"))) = {0}; 

/* Identity map the low 1M 
* In early boot stage. 
*/ 
static void __attribute__((section(".init"))) map_identity() 
{ 
    //map bios 
    unsigned int current_page = 0; 
    for(int i = 0; i < BIOS_PAGE_TABLE_ENTRIES; i++, current_page += PAGE_SIZE) 
    { 
     identity_page_table[i] = (current_page) | 0x3; 
    } 

    //map init 
    current_page = INIT_START; 
    for(int i = INIT_START >> 12 & 0x3FF; 
     i < ((INIT_START >> 12 & 0x3FF) + (INIT_SIZE/PAGE_SIZE)); 
     i++, current_page += PAGE_SIZE) 
    { 
     identity_page_table[i] = (current_page) | 0x3; 
    } 

    kernel_page_directory[0] = ((unsigned long)(identity_page_table)) | 0x3; 
} 

/* Map the kernel memory to its page directory, 
* **in early boot stage. 
* We don't need to map the init section, we don't need it anymore. 
*/ 

__attribute__((section(".init"))) static void map_kernel_memory() 
{ 
    //Identity map the init section 
    //Start at 1MB i.e. its page aligned. 
    unsigned int start_index = 256; 
    unsigned long current_page = KERNEL_START; 

    for(int i = start_index; 
     i < start_index + (KERNEL_SIZE/PAGE_SIZE) + 1; 
     i++, current_page += PAGE_SIZE) 
    { 
     kernel_page_tables[i] = current_page | 0x3; 
    } 

    kernel_page_directory[KERNEL_DIRECTORY_ENTRY] = ((unsigned long)kernel_page_tables) | 0x3; 
} 

__attribute__((section(".init"))) void paging_init() 
{ 
    map_identity(); 

    map_kernel_memory(); 
} 

ich auf die genaue Montageanleitung Punkt versucht, aber das macht meine Kernel-Arbeit falsch, und ich denke, es liegt daran, von mov cr0, eax wenn ich Paging aktivieren. CR3 enthält die Adresse kernel_page_directory oder 0x3. Sobald ich Paging aktiviere, reagiert QEMU nicht mehr und das System wird ständig neu gestartet. Der Bildschirm wird geleert und dann wiederholt gedruckt. Irgendwelche Ideen, warum das passiert? Wie kann ich es reparieren?

+1

Was kann helfen, liefert ein minimales vollständiges überprüfbares Beispiel. Sie stellen nicht alle Ihre _C_ Datei zur Verfügung (es ist teilweise), und Sie haben die von Ihnen verwendeten Definitionen nicht zur Verfügung gestellt. Ich kann schätzen, was einige sind, aber wir wissen nicht, ob sie richtig definiert sind oder nicht. Stellen Sie genügend Code zur Verfügung, damit jeder selbständig kompilieren/assemblieren/verknüpfen kann. Auch von Vorteil - was sind die eigentlichen Befehle, die Sie zum Kompilieren/Assemblieren/Verknüpfen verwenden? Auch das ist in einer solchen Frage oft wertvoll. –

+1

@MichaelPetch Nach einer schrecklichen Nacht des Debugging kam ich zu einer Lösung. Das Problem war, dass ich GRUBs GDT benutzte, anstatt meine eigene zu verwenden. Meine Vermutung ist, dass eine der linearen Adressen, auf die ich mich bezog, in meinem Seitenverzeichnis nicht zugeordnet war, und dies verursachte einen Seitenfehler oder undefiniertes Verhalten. – Delights

+2

Die [Multibootspezifikation] (https://www.gnu.org/software/grub/manual/multiboot/multiboot.html) besagt ziemlich genau das. Relevantes Zitat: _GDTR Obwohl die Segmentregister wie oben beschrieben eingerichtet sind, ist der 'GDTR' möglicherweise ungültig, so dass das ** OS-Image keine Segmentregister ** laden darf (auch wenn nur die gleichen Werte neu geladen werden!) ** bis er seine eigene "GDT" einrichtet. ** _ –

Antwort

0

Ist die Adresse Ihres Seitenverzeichnisses Page-Aligned? Die Größe jeder Seite (Frame) beträgt 4 KB. Ich schlage vor, eine Struktur für Seite Verzeichnis wie diese zu erstellen:

typedef struct page_directory{ 
    page_table_t *tables[1024]; 
    size_t tablesPhysical[1024]; // Physical address of page tables 
    size_t physicalAddr;   // Physical address of `tablesPhysical' 
} page_directory_t; 

So, Ihre Adresse des Verzeichnisses muss das Vielfache von 4 KB (0x1000) sein. James Molloy's Tutorial kann Ihnen helfen.

+0

Er benutzt '__attribute __ ((aligned (PAGE_SIZE)))'. Es kann aus dem Rest des Codes abgeleitet werden, dass PAGE_SIZE 4096 ist. Daher richtet sich das ausgerichtete Attribut, das er verwendet, an einer Grenze von 4k aus. In den Kommentaren erwähnt er, dass er sein Problem gefunden hat und dass es mit der Verwendung von GRUBs GDT und nicht mit einem von ihm zusammenhängt. –