diff --git a/Makefile b/Makefile index 621dfc5..41d90b0 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,6 @@ drivers/serial_port.o \ interrupts.o \ kmain.o \ multiboot_utils.o \ -page_allocator.o \ stdio.o \ string.o diff --git a/data_structures/page_table.c b/data_structures/page_table.c index d47ce45..d2b675c 100644 --- a/data_structures/page_table.c +++ b/data_structures/page_table.c @@ -1,17 +1,34 @@ #include "page_table.h" #include "../loader.h" +#include "../multiboot_utils.h" +#define PAGE_DIRECTORY_OFFSET_BITS 10 +#define PAGE_TABLE_OFFSET_BITS 10 +#define PAGE_OFFSET_BITS 12 + +#define PAGE_SIZE_BYTES 4096 +#define PAGE_SIZE_DWORDS 1024 + +#define KERNEL_PAGE_TABLE_NUMBER 768 + +// #define BITMAP_SIZE 32768 +// Enough room for 512 MB of RAM +// TODO: Find a more efficient way to initialize page allocator +#define BITMAP_SIZE 4096 + +uint32_t free_pages; +uint32_t free_page_bitmap[BITMAP_SIZE]; + +void mark_free(uint32_t page_number); +void mark_unavailable(uint32_t page_number); +uint32_t page_number(uint32_t address); enum page_size_t {FOUR_KB, FOUR_MB}; enum page_privilege_t {SUPERVISOR, USER}; enum page_permissions_t {READ_ONLY, READ_WRITE}; -struct page_directory_entry_t { - uint32_t page_table_address; -} __attribute__((packed)); - uint32_t make_page_directory_entry( - uint32_t page_table_address, + void* page_table_physical_address, enum page_size_t page_size, bool cache_disabled, bool write_through, @@ -19,7 +36,7 @@ uint32_t make_page_directory_entry( enum page_permissions_t permissions, bool present ) { - uint32_t entry = page_table_address; + uint32_t entry = (uint32_t) page_table_physical_address; entry |= page_size << 7; entry |= cache_disabled << 4; entry |= write_through << 3; @@ -31,7 +48,7 @@ uint32_t make_page_directory_entry( } uint32_t make_page_table_entry( - uint32_t page_frame_address, + void* page_frame_address, bool global, bool cache_disabled, bool write_through, @@ -39,7 +56,7 @@ uint32_t make_page_table_entry( enum page_permissions_t permissions, bool present ) { - uint32_t entry = page_frame_address; + uint32_t entry = (uint32_t) page_frame_address; entry |= global << 8; entry |= cache_disabled << 6; entry |= write_through << 3; @@ -54,8 +71,83 @@ uint32_t make_page_table_entry( // 1 page table = 1024 pages = 4 mB // 1 page directory = 1024 page tables = 4 gB +// Find a free physical page and return it's physical address +// This does NOT zero out the page +void* allocate_physical_page() { + for (uint32_t index = 0; index < BITMAP_SIZE; index++) { + if (free_page_bitmap[index] != 0) { + // There is at least one free page in this chunk + for (uint8_t bit = 0; bit < 32; bit++) { + if ((free_page_bitmap[index] & (1 << bit)) != 0) { + uint32_t page_number = index * 32 + bit; + mark_unavailable(page_number); + void* page_start = (void*) (page_number << PAGE_OFFSET_BITS); + return page_start; + } + } + } + } + + // Out of physical memory + // TODO: Evict a page + return 0; +} + +// Assumes we are using recursive page tables. +// Last entry in page directory points to itself +void* page_table_virtual_address(uint16_t page_table_number) { + // First 10 bits are set to 1 + uint32_t virtual_address = 0xFFC00000; + + // Next 10 bits index index into page directory + virtual_address |= (page_table_number << PAGE_OFFSET_BITS); + + return (void*) virtual_address; +} + page_directory_t initialize_page_directory() { - page_directory_t pd = (page_directory_t) &BootPageDirectory; + page_directory_t pd = (page_directory_t) &PageDirectoryVirtualAddress; + + // Make the last entry in the pd a pointer to itself + uint32_t pde = make_page_directory_entry( + (void*) &PageDirectoryPhysicalAddress, + FOUR_KB, + false, + false, + SUPERVISOR, + READ_WRITE, + true + ); + pd[1023] = pde; + + // dedicate one page table for memory for the kernel + void* page_table_physical_address = allocate_physical_page(); + pd[KERNEL_PAGE_TABLE_NUMBER] = make_page_directory_entry( + page_table_physical_address, + FOUR_KB, + false, + false, + SUPERVISOR, + READ_WRITE, + true + ); + + // From here on out, we can access page tables with `page_table_virtual_address()` + // Fill in the kernel page table entirely. + page_table_t pt = (page_table_t) page_table_virtual_address(KERNEL_PAGE_TABLE_NUMBER); + for (uint16_t i = 0; i < 1024; i++) { + void* page_physical_address = allocate_physical_page(); + pt[i] = make_page_table_entry( + page_physical_address, + false, + false, + false, + SUPERVISOR, + READ_WRITE, + true + ); + } + return pd; } @@ -71,3 +163,77 @@ void print_page_directory(FILE stream, page_directory_t pd) { } } } + +uint32_t round_up_to_nearest_page_start(uint32_t address) { + if ((address & 0xFFF) != 0) { + address &= 0xFFFFF000; + address += 0x00001000; + } + return address; +} + +uint32_t round_down_to_nearest_page_start(uint32_t address) { + if ((address & 0xFFF) != 0) { + address &= 0xFFFFF000; + address -= 0x00001000; + } + return address; +} + +uint32_t page_number(uint32_t address) { + return address >> PAGE_OFFSET_BITS; +} + +void mark_free(uint32_t page_number) { + uint32_t index = page_number >> 5; + uint32_t bit = page_number & 0b11111; + uint32_t value = free_page_bitmap[index]; + value |= (1 << bit); + free_page_bitmap[index] = value; + free_pages++; +} + +void mark_unavailable(uint32_t page_number) { + uint32_t index = page_number >> 5; + uint32_t bit = page_number & 0b11111; + uint32_t value = free_page_bitmap[index]; + value &= ~(1 << bit); + free_page_bitmap[index] = value; + free_pages--; +} + +uint32_t initialize_page_allocator(struct kernel_memory_descriptor_t kernel_memory, multiboot_info_t* mbinfo) { + memory_map_t * memory_map = (memory_map_t *) p_to_v(mbinfo->mmap_addr); + uint32_t num_entries = mbinfo->mmap_length / sizeof(memory_map_t); + + for (uint32_t i = 0; i < num_entries; i++) { + if (memory_map[i].type == 1) { + // Available + uint32_t first_addr = memory_map[i].base_addr_low; + uint32_t one_past_last_addr = first_addr + memory_map[i].length_low; + uint32_t first_full_page = page_number(round_up_to_nearest_page_start(first_addr)); + uint32_t one_past_last_full_page = page_number(round_down_to_nearest_page_start(one_past_last_addr)); + + for(uint32_t i = first_full_page; i < one_past_last_full_page; i++) { + mark_free(i); + } + } else { + // Unavailable + } + } + + uint32_t first_partial_page = page_number(round_down_to_nearest_page_start(kernel_memory.kernel_physical_start)); + uint32_t one_past_last_partial_page = page_number(round_up_to_nearest_page_start(kernel_memory.kernel_physical_end)); + + for(uint32_t i = first_partial_page; i < one_past_last_partial_page; i++) { + mark_unavailable(i); + } + + // for(uint16_t i = 0; i < BITMAP_SIZE; i++) { + // print_uint16(LOG, i); + // print_uint32(LOG, free_page_bitmap[i]); + // log("\n"); + // } + + return free_pages; +} diff --git a/data_structures/page_table.h b/data_structures/page_table.h index 9385f15..9307031 100644 --- a/data_structures/page_table.h +++ b/data_structures/page_table.h @@ -1,8 +1,20 @@ #ifndef INCLUDE_PAGE_TABLE_H #define INCLUDE_PAGE_TABLE_H -#include "../types.h" +#include "../multiboot.h" #include "../stdio.h" +#include "../types.h" + + +struct kernel_memory_descriptor_t { + uint32_t kernel_virtual_start; + uint32_t kernel_virtual_end; + uint32_t kernel_physical_start; + uint32_t kernel_physical_end; +}; + +void* allocate_page(); +uint32_t initialize_page_allocator(struct kernel_memory_descriptor_t kernel_memory, multiboot_info_t* mbinfo); typedef uint32_t * page_directory_t; typedef uint32_t * page_table_t; diff --git a/data_structures/symbol_table.c b/data_structures/symbol_table.c index c1c51d6..ed79f8c 100644 --- a/data_structures/symbol_table.c +++ b/data_structures/symbol_table.c @@ -1,6 +1,7 @@ #include "symbol_table.h" -#include "../multiboot_utils.h" +#include "../loader.h" +#include "../multiboot_utils.h" #include "../stdio.h" struct symbol_table_descriptor_t { @@ -19,8 +20,8 @@ bool load_symbol_table(struct elf_section_header_t * symbol_table_section, struc } else { symbol_table_descriptor.present = true; symbol_table_descriptor.num_symbols = symbol_table_section->sh_size / sizeof(Elf32_Sym); - symbol_table_descriptor.symbols = (Elf32_Sym *) symbol_table_section->sh_addr; - symbol_table_descriptor.string_table_addr = (char*) string_table_section->sh_addr; + symbol_table_descriptor.symbols = (Elf32_Sym *) p_to_v(symbol_table_section->sh_addr); + symbol_table_descriptor.string_table_addr = (char*) p_to_v(string_table_section->sh_addr); return true; } } diff --git a/kmain.c b/kmain.c index 52adb96..2e2d089 100644 --- a/kmain.c +++ b/kmain.c @@ -7,7 +7,6 @@ #include "drivers/pic.h" #include "drivers/serial_port.h" #include "multiboot_utils.h" -#include "page_allocator.h" #include "stdio.h" #include "types.h" @@ -82,6 +81,13 @@ void kmain(struct kernel_memory_descriptor_t kernel_memory, uint32_t ebx) { pic_init(); log("Initialized PIC\n"); + uint32_t free_pages = initialize_page_allocator(kernel_memory, mbinfo); + log("Initialized page allocator.\n"); + print_uint32(LOG, free_pages); + log(" free pages ("); + print_uint32(LOG, free_pages / 256); + log(" MB)\n"); + page_directory_t pd = initialize_page_directory(); log("Initialized page directory.\n"); log("Address of page directory: "); @@ -90,18 +96,11 @@ void kmain(struct kernel_memory_descriptor_t kernel_memory, uint32_t ebx) { print_page_directory(LOG, pd); - uint32_t free_pages = initialize_page_allocator(kernel_memory, mbinfo); - log("Initialized page allocator.\n"); - print_uint32(LOG, free_pages); - log(" free pages ("); - print_uint32(LOG, free_pages / 256); - log(" MB)\n"); - - bad_function(); + // bad_function(); - void_function_t start_program = first_module_as_a_function(mbinfo); - start_program(); - log("Got past call to start_program()\n"); + // void_function_t start_program = first_module_as_a_function(mbinfo); + // start_program(); + // log("Got past call to start_program()\n"); // Loop forever // User input is accepted asynchronously via interrupts diff --git a/loader.h b/loader.h index 09442e1..4c25a11 100644 --- a/loader.h +++ b/loader.h @@ -5,7 +5,7 @@ uint32_t KERNEL_VIRTUAL_BASE; -void * BootPageDirectory; -void * boot_pagetab1; +void * PageDirectoryVirtualAddress; +void * PageDirectoryPhysicalAddress; #endif /* INCLUDE_LOADER_H */ \ No newline at end of file diff --git a/loader.s b/loader.s index 7489a71..fa2251e 100644 --- a/loader.s +++ b/loader.s @@ -41,8 +41,8 @@ KERNEL_PAGE_NUMBER equ (KERNEL_VIRTUAL_BASE >> 22) ; Page directory index of ke section .data align 0x1000 -global BootPageDirectory -BootPageDirectory: +global PageDirectoryVirtualAddress +PageDirectoryVirtualAddress: ; This page directory entry identity-maps the first 4MB of the 32-bit physical address space. ; All bits are clear except the following: ; bit 7: PS The kernel page is 4MB. @@ -75,7 +75,9 @@ loader equ (_loader - KERNEL_VIRTUAL_BASE) _loader: ; NOTE: Until paging is set up, the code must be position-independent and use physical ; addresses, not virtual ones! - mov ecx, (BootPageDirectory - KERNEL_VIRTUAL_BASE) ; 0x104000 + global PageDirectoryPhysicalAddress + PageDirectoryPhysicalAddress equ (PageDirectoryVirtualAddress - KERNEL_VIRTUAL_BASE) ; 0x104000 + mov ecx, PageDirectoryPhysicalAddress mov cr3, ecx ; Load Page Directory Base Register. mov ecx, cr4 @@ -96,8 +98,8 @@ _loader: higher_half_loader: ; Unmap the identity-mapped first 4MB of physical address space. It should not be needed ; anymore. - ; mov dword [BootPageDirectory], 0 - ; invlpg [0] + mov dword [PageDirectoryVirtualAddress], 0 + invlpg [0] mov esp, kernel_stack + KERNEL_STACK_SIZE ; point esp to the start of the ; stack (end of memory area) @@ -115,7 +117,6 @@ higher_half_loader: call kmain ; use call rather than jmp so C function finds paramters in the correct place hlt ; should never get here. kmain should not return. -global boot_pagetab1 section .bss ; Use the 'bss' section for the stack align 4 ; align at 4 bytes for performance reasons kernel_stack: ; label points to beginning of memory diff --git a/multiboot_utils.c b/multiboot_utils.c index 36dcde9..ed79d80 100644 --- a/multiboot_utils.c +++ b/multiboot_utils.c @@ -26,7 +26,7 @@ struct elf_section_header_t * get_elf_section(multiboot_info_t* info, char * sec uint32_t shndx = section_table.shndx; struct elf_section_header_t * section_header_table = (struct elf_section_header_t *) addr; - uint32_t string_table_start = section_header_table[shndx].sh_addr; + uint32_t string_table_start = p_to_v(section_header_table[shndx].sh_addr); for (uint32_t i = 0; i < num_sections; i++) { uint32_t sh_name = section_header_table[i].sh_name; @@ -51,7 +51,7 @@ void print_elf_section_header_table(FILE stream, elf_section_header_table_t tabl uint32_t shndx = table.shndx; struct elf_section_header_t * section_header_table = (struct elf_section_header_t *) addr; - uint32_t string_table_start = section_header_table[shndx].sh_addr; + uint32_t string_table_start = p_to_v(section_header_table[shndx].sh_addr); for (uint32_t i = 0; i < num; i++) { uint32_t sh_addr = section_header_table[i].sh_addr; @@ -74,7 +74,7 @@ void print_elf_section_header_table(FILE stream, elf_section_header_table_t tabl void print_memory_map(FILE stream, multiboot_info_t* info) { fprintf(stream, "\nmemory map:\n"); - memory_map_t * memory_map = (memory_map_t *) info->mmap_addr; + memory_map_t * memory_map = (memory_map_t *) p_to_v(info->mmap_addr); uint32_t num_entries = info->mmap_length / sizeof(memory_map_t); for (uint32_t i = 0; i < num_entries; i++) { diff --git a/multiboot_utils.h b/multiboot_utils.h index 8c36da1..ea3bc90 100644 --- a/multiboot_utils.h +++ b/multiboot_utils.h @@ -7,6 +7,7 @@ void_function_t first_module_as_a_function(multiboot_info_t* info); struct elf_section_header_t * get_elf_section(multiboot_info_t* info, char * section_name); +uint32_t p_to_v(uint32_t physical_address); void print_multiboot_info(FILE stream, multiboot_info_t* info); #endif diff --git a/page_allocator.c b/page_allocator.c deleted file mode 100644 index c00748c..0000000 --- a/page_allocator.c +++ /dev/null @@ -1,88 +0,0 @@ -#include "page_allocator.h" - -#include "stdio.h" - -uint32_t free_pages; - -// 2^32 address space -// 2^12 page size -// 2^20 pages -// 2^17 bytes in bitmap -// 2^15 uint32_t's = 32768 - -// #define BITMAP_SIZE 32768 -// Enough room for 515 MB of RAM -// TODO: Find a more efficient way to initialize page allocator -#define BITMAP_SIZE 4096 -uint32_t free_page_bitmap[BITMAP_SIZE]; - -uint32_t round_up_to_nearest_page_start(uint32_t address) { - if ((address & 0xFFF) != 0) { - address &= 0xFFFFF000; - address += 0x00001000; - } - return address; -} - -uint32_t round_down_to_nearest_page_start(uint32_t address) { - if ((address & 0xFFF) != 0) { - address &= 0xFFFFF000; - address -= 0x00001000; - } - return address; -} - -uint32_t page_number(uint32_t address) { - return address >> 12; -} - -void mark_free(uint32_t page_number) { - uint32_t index = page_number >> 5; - uint32_t bit = page_number & 0b11111; - uint32_t value = free_page_bitmap[index]; - value |= (1 << bit); - free_page_bitmap[index] = value; - free_pages++; -} - -void mark_unavailable(uint32_t page_number) { - uint32_t index = page_number >> 5; - uint32_t bit = page_number & 0b11111; - uint32_t value = free_page_bitmap[index]; - value &= ~(1 << bit); - free_page_bitmap[index] = value; - free_pages--; -} - -uint32_t initialize_page_allocator(struct kernel_memory_descriptor_t kernel_memory, multiboot_info_t* mbinfo) { - if(kernel_memory.kernel_virtual_start){} - if(mbinfo){} - - memory_map_t * memory_map = (memory_map_t *) mbinfo->mmap_addr; - uint32_t num_entries = mbinfo->mmap_length / sizeof(memory_map_t); - - for (uint32_t i = 0; i < num_entries; i++) { - if (memory_map[i].type == 1) { - // Available - uint32_t first_addr = memory_map[i].base_addr_low; - uint32_t one_past_last_addr = first_addr + memory_map[i].length_low; - uint32_t first_full_page = page_number(round_up_to_nearest_page_start(first_addr)); - uint32_t one_past_last_full_page = page_number(round_down_to_nearest_page_start(one_past_last_addr)); - - for(uint32_t i = first_full_page; i < one_past_last_full_page; i++) { - mark_free(i); - } - } else { - // Unavailable - } - } - - uint32_t first_partial_page = page_number(round_down_to_nearest_page_start(kernel_memory.kernel_physical_start)); - uint32_t one_past_last_partial_page = page_number(round_up_to_nearest_page_start(kernel_memory.kernel_physical_end)); - - for(uint32_t i = first_partial_page; i < one_past_last_partial_page; i++) { - mark_unavailable(i); - } - - return free_pages; -} \ No newline at end of file diff --git a/page_allocator.h b/page_allocator.h deleted file mode 100644 index d0f8e07..0000000 --- a/page_allocator.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef PAGE_ALLOCATOR_H -#define PAGE_ALLOCATOR_H - -#include "types.h" -#include "multiboot.h" - -struct kernel_memory_descriptor_t { - uint32_t kernel_virtual_start; - uint32_t kernel_virtual_end; - uint32_t kernel_physical_start; - uint32_t kernel_physical_end; -}; - -bool allocate_page(uint32_t virtual_address); -uint32_t initialize_page_allocator(struct kernel_memory_descriptor_t kernel_memory, multiboot_info_t* mbinfo); - -#endif /* PAGE_ALLOCATOR_H */ \ No newline at end of file