Added initial paging support.

This commit is contained in:
Xnoe 2021-10-11 12:26:11 +01:00
parent e9f610d4aa
commit 65b8e7773e
6 changed files with 193 additions and 52 deletions

View File

@ -2,7 +2,7 @@ CFLAGS = -m32 -mgeneral-regs-only -nostdlib -fno-builtin -fno-exceptions -fno-le
LDFLAGS = LDFLAGS =
DISK_IMG_FILES = kernel.bin DISK_IMG_FILES = kernel.bin
KERNEL32_OBJS = screenstuff.o io.o idt.o keyboard.o strings.o atapio.o c_code_entry.o kernel.o KERNEL32_OBJS = screenstuff.o io.o idt.o keyboard.o strings.o atapio.o c_code_entry.o kernel.o paging.o
run: disk.img run: disk.img
qemu-system-x86_64 disk.img qemu-system-x86_64 disk.img
@ -26,7 +26,7 @@ boot.sector: boot.asm
boot.stage2: boot_stage2.ld boot.stage2.o boot.stage2: boot_stage2.ld boot.stage2.o
ld $(LDFLAGS) -T $< boot.stage2.o ld $(LDFLAGS) -T $< boot.stage2.o
boot.stage2.o: src/boot_stage2/main.c io.o atapio.o strings.o c_code_entry.o screenstuff.o boot.stage2.o: src/boot_stage2/main.c io.o atapio.o strings.o c_code_entry.o screenstuff.o paging.o
gcc $(CFLAGS) -o $@ -c $< gcc $(CFLAGS) -o $@ -c $<
%.bin: %.asm %.bin: %.asm

View File

@ -1,7 +1,7 @@
OUTPUT_FORMAT(binary) OUTPUT_FORMAT(binary)
OUTPUT_ARCH(i386:i386) OUTPUT_ARCH(i386:i386)
INPUT(io.o atapio.o strings.o c_code_entry.o screenstuff.o) INPUT(io.o atapio.o strings.o c_code_entry.o screenstuff.o paging.o)
OUTPUT(boot.stage2) OUTPUT(boot.stage2)
SECTIONS { SECTIONS {

View File

@ -4,7 +4,7 @@ OUTPUT_ARCH(i386:i386)
OUTPUT(kernel.bin) OUTPUT(kernel.bin)
SECTIONS { SECTIONS {
. = 0x80000; . = 0xc0000000;
.text : { .text : {
c_code_entry.o(.text) c_code_entry.o(.text)

View File

@ -1,5 +1,6 @@
#include "../kernel/atapio.h" #include "../kernel/atapio.h"
#include "../kernel/screenstuff.h" #include "../kernel/screenstuff.h"
#include "../kernel/paging.h"
typedef struct { typedef struct {
uint32_t base_low; uint32_t base_low;
@ -10,66 +11,128 @@ typedef struct {
uint32_t acpi3_extended; uint32_t acpi3_extended;
}__attribute__((packed)) e820entry; }__attribute__((packed)) e820entry;
void set_bit(uint32_t offset, uint8_t* buffer) { uint8_t* bitmap = 0x100000;
uint32_t index = offset / 8;
uint32_t bit = offset % 8;
buffer[index] |= (1<<(7 - bit)); void set_bit(uint32_t offset, uint8_t* buffer) {
uint32_t index = offset / 8;
uint32_t bit = offset % 8;
buffer[index] |= (1<<(7 - bit));
}
void unset_bit(uint32_t offset, uint8_t* buffer) {
uint32_t index = offset / 8;
uint32_t bit = offset % 8;
buffer[index] &= (255 - (1<<(7 - bit)));
}
void memset(uint8_t* base, uint32_t count, uint8_t to) {
for (int i=0; i<count; i++) {
base[i] = to;
}
}
void mark_unavailble(uint32_t address, uint32_t size) {
// This function takes an address and length and marks the corresponding pages as unavailable.
address -= address % 4096;
if (size % 4096)
size += 4096 - (size % 4096);
address /= 4096;
size /= 4096;
for (int i=0; i<size; i++) {
unset_bit(address + i, bitmap);
}
} }
void main() { void main() {
init_term(); init_term();
init_atapio(); init_atapio();
// e820 memory map exists at 0x20000 // e820 memory map exists at 0x20000
e820entry* e820_entries = 0x20000; e820entry* e820_entries = 0x20000;
uint8_t* bitmap = 0x100000; // Zero out the bitmap.
memset(bitmap, 0x20000, 0);
// Ensure the bitmap data is clear
// Zero out the bitmap. for (int i=0; i<0x20000; i++)
for (int i=0; i<0x20000; i++) if (bitmap[i])
bitmap[i] = 0; printf("Found data in bitmap at %x!\n", (bitmap+i));
// Ensure the bitmap data is clear
for (int i=0; i<0x20000; i++) for (int i=0; e820_entries[i].length_low != 0 || e820_entries[i].length_high != 0; i++) {
if (bitmap[i]) e820entry entry = e820_entries[i];
printf("Found data in bitmap at %x!\n", (bitmap+i)); printf("BIOS-e820: Starting %x%x, length %x%x is %s\n", entry.base_high, entry.base_low, entry.length_high, entry.length_low, entry.type == 1 ? "Available" : "Reserved");
for (int i=0; e820_entries[i].length_low != 0 || e820_entries[i].length_high != 0; i++) { if (entry.type != 1)
e820entry entry = e820_entries[i]; continue;
printf("BIOS-e820: Starting %x%x, length %x%x is %s\n", entry.base_high, entry.base_low, entry.length_high, entry.length_low, entry.type == 1 ? "Available" : "Reserved");
if (entry.type != 1) uint32_t base = entry.base_low;
continue; uint32_t length = entry.length_low;
uint32_t base = entry.base_low; if (base % 4096) {
uint32_t length = entry.length_low; // Memory isn't page aligned, we need to fix that.
uint32_t add_offset = 4096 - (base % 4096);
if (base % 4096) { if (length > add_offset) {
// Memory isn't page aligned, we need to fix that. base += add_offset;
uint32_t add_offset = 4096 - (base % 4096); length -= add_offset;
if (length > add_offset) { }
base += add_offset;
length -= add_offset;
}
}
uint32_t page_index = base / 4096;
printf("Page Index: %d\nLength (Pages): %d\n", page_index, length / 4096);
for (int j=0; length > 4096; length -= 4096, j++) {
uint32_t index = (page_index+j) / 8;
uint32_t bit = (page_index+j) % 8;
bitmap[index] |= (1<<(7 - bit));
}
} }
uint32_t page_index = base / 4096;
uint8_t* kernel_location = 0x80000; printf("Page Index: %d\nLength (Pages): %d\n", page_index, length / 4096);
load_file("KERNEL BIN", kernel_location);
printf("Stage2 success!\n"); for (int j=0; length > 4096; length -= 4096, j++) {
set_bit(page_index + j, bitmap);
}
}
while (1); mark_unavailble(bitmap, 0x20000);
((void(*)(void))kernel_location)();
// Page Directory
PDE* kernel_page_directory = bitmap + 0x20000;
// Clear the PD
memset((uint8_t*)kernel_page_directory, 4096, 0);
// Clear 4MB of RAM from 0x121000 to 0x521000 for the 1024 page tables
memset((uint8_t*)0x121000, 0x400000, 0);
// Construct a 1024 long PTE** at 0x521000
for (int i=0; i<1024; i++) {
((uint32_t*)0x521000)[i] = 0x121000 + 0x1000*i;
}
PTE** kernel_page_tables = 0x521000;
// Mark unavailable bitmap to 0x522000
mark_unavailble(bitmap, 0x522000 - (uint32_t)bitmap);
// Now we want to map some stuff.
// But first, we should load the kernel somewhere
uint8_t* kernel_location = 0x522000; // Just load it at 0x522000 for now
mark_unavailble(0x522000, 32768); // Just treat the kernel as not growing beyong 32k for now.
map_many_4k_phys_to_virt(0x522000, 0xc0000000, kernel_page_directory, kernel_page_tables, 8); // Map 8 pages from 0x522000 to 0xc0000000;
map_4k_phys_to_virt((uint32_t)kernel_page_directory, 0xc0100000, kernel_page_directory, kernel_page_tables); // Map the page directory to 0xc0100000
map_many_4k_phys_to_virt(0x121000, 0xc0101000, kernel_page_directory, kernel_page_tables, 1024); // Map 1024 pages from 0x121000 to 0xc0101000
map_4k_phys_to_virt(0xb8000, 0xc0501000, kernel_page_directory, kernel_page_tables); // Map 0xb8000 (video) to 0xc0501000
map_4k_phys_to_virt(0x8000, 0x8000, kernel_page_directory, kernel_page_tables);
load_file("KERNEL BIN", kernel_location);
printf("Stage2 success!\n");
asm ("mov %0, %%eax;"
"mov %%eax, %%cr3" : : "m" (kernel_page_directory));
asm ("mov %cr0, %eax;"
"or $0x80000001, %eax;"
"mov %eax, %cr0");
while (1);
((void(*)(void))0xc0000000)();
} }

41
src/kernel/paging.c Normal file
View File

@ -0,0 +1,41 @@
#include "paging.h"
void map_4k_phys_to_virt(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables) {
uint32_t pd_index = (virtual & (1023 << 20)) >> 20;
uint32_t pt_index = (virtual & (1023 << 10)) >> 10;
page_directory[pd_index] = (PDE){
.address = (uint32_t)(page_tables[pd_index]) >> 12,
.available = 0,
.page_4mb = 0,
.accessed = 0,
.disable_cache = 0,
.write_through_cache = 0,
.privilege = 0,
.present = 1,
.read_write = 1,
.ignored = 0,
.ignored2 = 0
};
page_tables[pd_index][pt_index] = (PTE){
.address = physical >> 12,
.available = 0,
.global = 0,
.accessed = 0,
.disable_cache = 0,
.dirty = 0,
.write_through_cache = 0,
.privilege = 0,
.present = 1,
.read_write = 1,
.ignored = 0
};
}
void map_many_4k_phys_to_virt(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables, uint32_t count) {
for (int i=0; i<count; i++)
map_4k_phys_to_virt(physical + 4096*i, virtual + 4096*i, page_directory, page_tables);
}

37
src/kernel/paging.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef PAGING_H
#define PAGING_H
#include <stdbool.h>
#include "types.h"
typedef struct {
uint32_t address : 20;
uint32_t available : 3;
uint32_t ignored : 1;
uint32_t page_4mb : 1;
uint32_t ignored2 : 1;
uint32_t accessed : 1;
uint32_t disable_cache : 1;
uint32_t write_through_cache : 1;
uint32_t privilege : 1;
uint32_t read_write : 1;
uint32_t present : 1;
}__attribute__((packed)) PDE;
typedef struct {
uint32_t address : 20;
uint32_t available : 3;
uint32_t global : 1;
uint32_t ignored : 1;
uint32_t dirty : 1;
uint32_t accessed : 1;
uint32_t disable_cache : 1;
uint32_t write_through_cache : 1;
uint32_t privilege : 1;
uint32_t read_write : 1;
uint32_t present : 1;
}__attribute__((packed)) PTE;
void map_4k_phys_to_virt(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables);
void map_many_4k_phys_to_virt(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables, uint32_t count);
#endif