diff --git a/boot/boot.S b/boot/boot.S index 276dee5..18bf4bb 100644 --- a/boot/boot.S +++ b/boot/boot.S @@ -19,7 +19,7 @@ forced to be within the first 8 KiB of the kernel file. .long CHECKSUM #.include "gdt.S" -.section .data +.section .data.boot gdt: .quad 0x0000000000000000 .quad 0x00CF9A000000FFFF @@ -42,7 +42,7 @@ System V ABI standard and de-facto extensions. The compiler will assume the stack is properly aligned and failure to align the stack will result in undefined behavior. */ -.section .bss +.section .bss.boot .align 16 stack_bottom: .skip 16384 # 16 KiB @@ -53,7 +53,7 @@ The linker script specifies _start as the entry point to the kernel and the bootloader will jump to this position once the kernel has been loaded. It doesn't make sense to return from this function as the bootloader is gone. */ -.section .text +.section .text.boot .global _start .type _start, @function _start: @@ -103,6 +103,25 @@ _start: continue_boot: sti + + // setting up paging + // id map first 4MB using PSE. With + movl $135, kernel_page_directory - 0xC0000000 + movl $135, kernel_page_directory - 0xC0000000 + 3072 + // load into cr3 + movl $kernel_page_directory - 0xC0000000, %eax + movl %eax, %cr3 + // enable PSE TODO validate if PSE is actually supported + movl %cr4, %eax + orl $0x10, %eax + movl %eax, %cr4 + // enable paging + movl %cr0, %eax + orl $0x80000000, %eax + movl %eax, %cr0 + nop + pushl 0 + popl %eax /* Enter the high-level kernel. The ABI requires the stack is 16-byte aligned at the time of the call instruction (which afterwards pushes diff --git a/include/myke/mem/paging.h b/include/myke/mem/paging.h index 1a5f3a6..ce73066 100644 --- a/include/myke/mem/paging.h +++ b/include/myke/mem/paging.h @@ -5,4 +5,39 @@ #ifndef NEW_KERNEL_PAGING_H #define NEW_KERNEL_PAGING_H +#define PAGING_MASK_4K 0xFFFFF000 +#define PAGING_MASK_4M 0xFFC00000 + +#define DIRECTORY_PRESENT_BIT (0) +#define DIRECTORY_RW_BIT (1) +#define DIRECTORY_US_BIT (2) +#define DIRECTORY_WT_BIT (3) +#define DIRECTORY_CACHE_BIT (4) +#define DIRECTORY_ACCESSED_BIT (5) +#define DIRECTORY_PAGE_SIZE_BIT (7) + +#define DIRECTORY_ADDR_MASK 0xFFFFF000 +#define DIRECTORY_PRESENT_MASK (1 << DIRECTORY_PRESENT_BIT) +#define DIRECTORY_RW_MASK (1 << DIRECTORY_RW_BIT) +#define DIRECTORY_US_MASK (1 << DIRECTORY_US_BIT) +#define DIRECTORY_WT_MASK (1 << DIRECTORY_WT_BIT) +#define DIRECTORY_CACHE_MASK (1 << DIRECTORY_CACHE_BIT) +#define DIRECTORY_ACCESSED_MASK (1 << DIRECTORY_ACCESSED_BIT) +#define DIRECTORY_PAGE_SIZE_MASK (1 << DIRECTORY_PAGE_SIZE_BIT) + +#define DIRECTORY_SIZE 1024 + +#define PAGING_MODE_4M (1 << 0) +#define PAGING_MODE_RW (1 << 1) +#define PAGING_MODE_US (1 << 2) + +#define PAGING_RESULT_OK 0 +#define PAGING_RESULT_INUSE 1 +#define PAGING_RESULT_ALIGN 2 +#define PAGING_RESULT_ERR 99 + +typedef uint32_t page_directory_entry; + +typedef uint32_t page_table_entry; + #endif //NEW_KERNEL_PAGING_H diff --git a/include/myke/mem/vmm.h b/include/myke/mem/vmm.h new file mode 100644 index 0000000..522d716 --- /dev/null +++ b/include/myke/mem/vmm.h @@ -0,0 +1,10 @@ +// +// Created by rick on 17-10-21. +// + +#ifndef NEW_KERNEL_VMM_H +#define NEW_KERNEL_VMM_H + +void vmm_init(multiboot_info_t *multiboot_info); + +#endif //NEW_KERNEL_VMM_H diff --git a/kernel/kernel.c b/kernel/kernel.c index d361391..f47163c 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include @@ -21,15 +21,6 @@ const int version_major = 0, version_minor = 0, version_patch = 1; -void init_mmap(multiboot_info_t *multiboot_info) { - if (multiboot_info->flags & (1 << 6)) { - mmap_init_multiboot((struct multiboot_mmap_entry *) multiboot_info->mmap_addr, - multiboot_info->mmap_length / sizeof(struct multiboot_mmap_entry)); - } else { - k_panics("mmap invalid!\n"); - } -} - void init_pci_system() { pci_scan(); pci_init_drivers(); @@ -38,6 +29,9 @@ void init_pci_system() { void att_noreturn att_used kmain(multiboot_info_t *multiboot_info, uint32_t mb_name) { // early init isr_install(); + // initialize memory management + vmm_init(multiboot_info); + // initialize early modules (kprint etc.) init_execute_all(INIT_STAGE_EARLY_BOOT_0); @@ -48,8 +42,6 @@ void att_noreturn att_used kmain(multiboot_info_t *multiboot_info, uint32_t mb_n store_bootloader_info(multiboot_info); - // initialize memory management - init_mmap(multiboot_info); // safe multiboot info for later use debug_store_info(multiboot_info); diff --git a/kernel/mem/paging.c b/kernel/mem/paging.c index fecd022..9e6846f 100644 --- a/kernel/mem/paging.c +++ b/kernel/mem/paging.c @@ -2,58 +2,80 @@ // Created by rick on 21-02-21. // -#include -#include #include +#include #include +#include -#define TABLE_ADDR_MASK 0xFFFFF000 -#define DIRECTORY_SIZE 1024 +#define PAGING_DIR_INDEX(virt) ((virt) >> 22) +#define PAGING_TABLE_INDEX(virt) ((virt) >> 12 & 0x03FF) -const uint32_t x = TABLE_ADDR_MASK; -typedef struct { - union { - struct { - bool present: 1; - bool read_write: 1; - bool user_mode: 1; - bool write_through: 1; - bool cache_disabled: 1; - bool accessed: 1; - char ignored: 1; - bool page_size: 1; - bool global: 1; // ignored - uint8_t avail: 3; - } att_packed; - uint32_t addr; - }; -} att_packed page_directory_entry; +#define KERNEL_OFFSET 0xC0000000 -typedef struct { - union { - struct { - bool present: 1; - bool read_write: 1; - bool user_supervisor: 1; - bool write_through: 1; - bool cache_disabled: 1; - bool accessed: 1; - bool dirty: 1; - char ignored: 1; - bool global: 1; - uint8_t available: 3; - } att_packed; - uint32_t addr; - }; -} att_packed page_table_entry; +// One page table, only 4M +#define PAGING_STATE_EARLY 0 +#define PAGING_STATE_FULL 60 -page_directory_entry page_directory[DIRECTORY_SIZE] att_aligned(4096); +page_directory_entry att_aligned(4096) kernel_page_directory[DIRECTORY_SIZE] = {0}; -void page_pre_init() { - for (int i = 0; i < DIRECTORY_SIZE; ++i) { - page_directory[i].read_write = true; - page_directory[i].user_mode = false; - page_directory[i].present = false; +int paging_state = PAGING_STATE_EARLY; + +void paging_load_directory(uintptr_t physical_address) { + asm volatile("mov %%eax, %%cr3" : : "a" (physical_address)); +} + +uintptr_t paging_get_current_directory_physical() { + uintptr_t directory_address; + asm volatile("mov %%cr3, %%eax" : "=a" (directory_address)); + return directory_address; +} + +page_directory_entry *paging_get_current() { + return kernel_page_directory; +} + +int paging_map_4m(uintptr_t physical_address, uintptr_t virtual_address, int count, int mode) { + if (virtual_address & ~PAGING_MASK_4M || physical_address & PAGING_MASK_4M) { + // address not 4M aligned + return PAGING_RESULT_ALIGN; } + page_directory_entry *dir = paging_get_current(); + for (int i = 0; i < count; ++i) { + page_directory_entry current_val = dir[PAGING_DIR_INDEX(virtual_address) + i]; + if (current_val & DIRECTORY_PRESENT_MASK) { + return PAGING_RESULT_INUSE; + } + } + page_directory_entry mask = DIRECTORY_PAGE_SIZE_MASK; + if (mode & PAGING_MODE_RW) { + mask |= DIRECTORY_RW_MASK; + } + if (mode & PAGING_MODE_US) { + mask |= DIRECTORY_US_MASK; + } + for (int i = 0; i < count; ++i) { + dir[PAGING_DIR_INDEX(virtual_address) + i] = physical_address & mask; + } + paging_load_directory((uintptr_t) dir); + return PAGING_RESULT_OK; +} + +int paging_map_memory(uintptr_t physical_address, uintptr_t virtual_address, int count, int mode) { + if (mode & PAGING_MODE_4M) { + return paging_map_4m(physical_address, virtual_address, count, mode); + } + if (paging_state < PAGING_STATE_FULL) { + // can't allocate 4K pages yet + if ((virtual_address & ~PAGING_MASK_4M) != (physical_address & ~PAGING_MASK_4M)) { + return PAGING_RESULT_ERR; // not in same pos in 4M page + } + int table_index = PAGING_TABLE_INDEX(virtual_address); + int pages = DIV_ROUND_UP(table_index + count, 1024); + return paging_map_4m(physical_address & PAGING_MASK_4M, + virtual_address & PAGING_MASK_4M, + pages, + mode | PAGING_MODE_4M); + } + return PAGING_RESULT_ERR; } \ No newline at end of file diff --git a/kernel/mem/vmm.c b/kernel/mem/vmm.c new file mode 100644 index 0000000..ab23c08 --- /dev/null +++ b/kernel/mem/vmm.c @@ -0,0 +1,24 @@ +// +// Created by rick on 17-10-21. +// +#include +#include +#include +#include + +void vmm_init(multiboot_info_t *multiboot_info) { + if (!(multiboot_info->flags & MULTIBOOT_INFO_MEM_MAP)) { + k_panics("No MMAP info available"); + } + mmap_init_multiboot((struct multiboot_mmap_entry *) multiboot_info->mmap_addr, + multiboot_info->mmap_length / sizeof(struct multiboot_mmap_entry)); +} + +void* vmm_map_physical(uintptr_t physical) { +} + +void* vmm_unmap_physical(uintptr_t physical) { +} + +void* vmm_unmap_virtual(uintptr_t virtual) { +} \ No newline at end of file diff --git a/linker.ld b/linker.ld index 796290e..938cd31 100644 --- a/linker.ld +++ b/linker.ld @@ -6,66 +6,76 @@ ENTRY(_start) kernel image. */ SECTIONS { - /* Begin putting sections at 1 MiB, a conventional place for kernels to be - loaded at by the bootloader. */ - . = 1M; - _kernel_start = .; + /* Begin putting sections at 1 MiB, a conventional place for kernels to be + loaded at by the bootloader. */ + . = 1M; + _kernel_start = .; + .data.boot ALIGN(4K) : { + *(.multiboot) + *(.data.boot) + } + .text.boot ALIGN(4K) : { + *(.text.boot) + } + .bss.boot ALIGN(4K) : { + *(.bss.boot) + } - /* First put the multiboot header, as it is required to be put very early - early in the image or the bootloader won't recognize the file format. - Next we'll put the .text section. */ - .text BLOCK(4K) : ALIGN(4K) - { - *(.multiboot) - *(.text) - } + . += 0xC0000000; + /* First put the multiboot header, as it is required to be put very early + early in the image or the bootloader won't recognize the file format. + Next we'll put the .text section. */ + .text ALIGN(4K) : AT(ADDR(.text)-0xC0000000) + { + *(.text) + } - /* Read-only data. */ - .rodata BLOCK(4K) : ALIGN(4K) - { - *(.rodata) - } + /* Read-only data. */ + .rodata ALIGN(4K) : AT(ADDR(.rodata)-0xC0000000) + { + *(.rodata) + } - /* Read-write data (initialized) */ - .data BLOCK(4K) : ALIGN(4K) - { - *(.data) + /* Read-write data (initialized) */ + .data ALIGN(4K) : AT(ADDR(.data)-0xC0000000) + { + *(.data) - . = ALIGN(16); - __start_pci_driver = .; - *(SORT(.pci_driver.*)) - __stop_pci_driver = .; + . = ALIGN(16); + __start_pci_driver = .; + *(SORT(.pci_driver.*)) + __stop_pci_driver = .; - . = ALIGN(16); - __start_block_dev_driver = .; - *(SORT(.block_dev_driver.*)) - __stop_block_dev_driver = .; + . = ALIGN(16); + __start_block_dev_driver = .; + *(SORT(.block_dev_driver.*)) + __stop_block_dev_driver = .; - . = ALIGN(16); - __start_vfs_driver = .; - *(SORT(.vfs_driver.*)) - __stop_vfs_driver = .; + . = ALIGN(16); + __start_vfs_driver = .; + *(SORT(.vfs_driver.*)) + __stop_vfs_driver = .; - . = ALIGN(16); - __start_init = .; - *(SORT(.init.*)) - __stop_init = .; - } + . = ALIGN(16); + __start_init = .; + *(SORT(.init.*)) + __stop_init = .; + } - /* Read-write data (uninitialized) and stack */ - .bss BLOCK(4K) : ALIGN(4K) - { - *(COMMON) - *(.bss) - } - _kernel_end = .; + /* Read-write data (uninitialized) and stack */ + .bss ALIGN(4K) : AT(ADDR(.bss)-0xC0000000) + { + *(COMMON) + *(.bss) + } + _kernel_end = . - 0xC0000000; - /DISCARD/ : { - *(.eh_frame); - *(.comment); - *(.note.gnu.build-id); - } + /DISCARD/ : { + *(.eh_frame); + *(.comment); + *(.note.gnu.build-id); + } - /* The compiler may produce other sections, by default it will put them in - a segment with the same name. Simply add stuff here as needed. */ + /* The compiler may produce other sections, by default it will put them in + a segment with the same name. Simply add stuff here as needed. */ } \ No newline at end of file