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?
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. –
@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
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. ** _ –