1 Commits

Author SHA1 Message Date
f0cc2c73b7 feat: initial paging setup 2021-08-06 20:46:44 +02:00
15 changed files with 257 additions and 114 deletions

View File

@@ -20,7 +20,7 @@ set(CMAKE_C_STANDARD 99)
FILE(GLOB_RECURSE kernel_src kernel/**.c) FILE(GLOB_RECURSE kernel_src kernel/**.c)
FILE(GLOB_RECURSE kernel_asm kernel/**.S) FILE(GLOB_RECURSE kernel_asm kernel/**.S)
FILE(GLOB_RECURSE boot_asm boot/boot.S) FILE(GLOB_RECURSE boot_asm boot/boot.S boot/bootpaging.S)
add_compile_definitions(__kernel__) add_compile_definitions(__kernel__)

View File

@@ -19,7 +19,7 @@ forced to be within the first 8 KiB of the kernel file.
.long CHECKSUM .long CHECKSUM
#.include "gdt.S" #.include "gdt.S"
.section .data .section .boot.data, "aw", @progbits
gdt: gdt:
.quad 0x0000000000000000 .quad 0x0000000000000000
.quad 0x00CF9A000000FFFF .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 stack is properly aligned and failure to align the stack will result in
undefined behavior. undefined behavior.
*/ */
.section .bss .section .boot.bss, "aw", @nobits
.align 16 .align 16
stack_bottom: stack_bottom:
.skip 16384 # 16 KiB .skip 16384 # 16 KiB
@@ -53,7 +53,10 @@ 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 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. doesn't make sense to return from this function as the bootloader is gone.
*/ */
.section .text .section .boot.text, "ax", @progbits
.extern _boot_paging
.global _start .global _start
.type _start, @function .type _start, @function
_start: _start:
@@ -77,6 +80,8 @@ _start:
*/ */
mov $stack_top, %esp mov $stack_top, %esp
call _boot_paging
// store multiboot on stack // store multiboot on stack
pushl 0 pushl 0
pushl %eax // MB code pushl %eax // MB code
@@ -101,6 +106,13 @@ _start:
movw %ax,%gs movw %ax,%gs
ljmp $0x8, $continue_boot ljmp $0x8, $continue_boot
/*
Set the size of the _start symbol to the current location '.' minus its start.
This is useful when debugging or when you implement call tracing.
*/
.size _start, . - _start
.section .text
continue_boot: continue_boot:
sti sti
/* /*
@@ -129,9 +141,3 @@ continue_boot:
cli cli
1: #hlt 1: #hlt
jmp 1b jmp 1b
/*
Set the size of the _start symbol to the current location '.' minus its start.
This is useful when debugging or when you implement call tracing.
*/
.size _start, . - _start

51
boot/bootpaging.S Normal file
View File

@@ -0,0 +1,51 @@
.code32
.extern boot_paging_directory
.extern boot_primary_table
.section .boot.text, "ax", @progbits
.global _boot_paging
.type _boot_paging, @function
_boot_paging:
push %ebp
mov %esp, %ebp
pusha
# Physical address of paging table 1
# movl $(boot_primary_table - 0xC0000000), %edi
movl $(boot_primary_table - 0xC0000000), %edi
movl $0, %esi
movl $1024, %ecx
cmpl %esi, %ecx
_boot_paging_loop:
# stop when after kernel's last address
# cmpl $(_kernel_end -0xC0000000), %esi
cmpl $(_kernel_end), %esi
jge _boot_paging_after_kernel
# make address present and writable
movl %esi, %edx
orl $0x003, %edx
movl %edx, (%edi)
# next address
addl $4096, %esi
addl $4, %edi
loop _boot_paging_loop
_boot_paging_after_kernel:
# write to directory
movl $(boot_primary_table - 0xC0000000 + 0x003), boot_paging_directory - 0xC0000000 + 0
movl $(boot_primary_table - 0xC0000000 + 0x003), boot_paging_directory - 0xC0000000 + 768 * 4
# write paging directory to cr3
movl $(boot_paging_directory - 0xC0000000), %ecx
movl %ecx, %cr3
# enable paging and write protect in cr0
movl %cr0, %ecx
orl $0x80010000, %ecx
movl %ecx, %cr0
_boot_pagin_end:
popa
pop %ebp
ret

View File

@@ -1,8 +0,0 @@
//
// Created by rick on 21-02-21.
//
#ifndef NEW_KERNEL_PAGING_H
#define NEW_KERNEL_PAGING_H
#endif //NEW_KERNEL_PAGING_H

19
include/myke/mem/pm.h Normal file
View File

@@ -0,0 +1,19 @@
//
// Created by rick on 23-02-21.
//
#ifndef NEW_KERNEL_PM_H
#define NEW_KERNEL_PM_H
#include <sys/types.h>
// 4k blocks
#define PAGE_SIZE 4096
void pm_init(void *start_addr, size_t size);
void *pm_get_pages(uint32_t num_pages);
void pm_free_pages(void *page, uint32_t num_pages);
#endif //NEW_KERNEL_PM_H

View File

@@ -1,19 +0,0 @@
//
// Created by rick on 23-02-21.
//
#ifndef NEW_KERNEL_PMM_H
#define NEW_KERNEL_PMM_H
#include <sys/types.h>
// 4k blocks
#define PAGE_SIZE 4096
void pmm_init(void *start_addr, size_t size);
void *pmm_get_pages(uint32_t num_pages);
void pmm_free_pages(void *page, uint32_t num_pages);
#endif //NEW_KERNEL_PMM_H

13
include/myke/mem/vmm.h Normal file
View File

@@ -0,0 +1,13 @@
//
// Created by rick on 21-02-21.
//
#ifndef NEW_KERNEL_VMM_H
#define NEW_KERNEL_VMM_H
#include <sys/types.h>
void vmm_assign_page(void *paddr, void *vaddr, size_t number_of_pages);
void vmm_unassign_page(void *vaddr, size_t number_of_pages);
#endif //NEW_KERNEL_VMM_H

View File

@@ -6,7 +6,7 @@
#include <myke/tasks/task.h> #include <myke/tasks/task.h>
#include <myke/mem/malloc.h> #include <myke/mem/malloc.h>
#include <myke/mem/pmm.h> #include <myke/mem/pm.h>
// retrieved from https://github.com/blanham/liballoc // retrieved from https://github.com/blanham/liballoc
@@ -41,7 +41,7 @@ int liballoc_unlock() {
* \return A pointer to the allocated memory. * \return A pointer to the allocated memory.
*/ */
void *liballoc_alloc(size_t size) { void *liballoc_alloc(size_t size) {
return pmm_get_pages(size); return pm_get_pages(size);
} }
/** This frees previously allocated memory. The void* parameter passed /** This frees previously allocated memory. The void* parameter passed
@@ -53,7 +53,7 @@ void *liballoc_alloc(size_t size) {
* \return 0 if the memory was successfully freed. * \return 0 if the memory was successfully freed.
*/ */
int liballoc_free(void *addr, size_t size) { int liballoc_free(void *addr, size_t size) {
pmm_free_pages(addr, size); pm_free_pages(addr, size);
return 0; return 0;
} }

View File

@@ -8,7 +8,7 @@
#include <myke/libk/libk.h> #include <myke/libk/libk.h>
#include <myke/mem/mem.h> #include <myke/mem/mem.h>
#include <myke/mem/pmm.h> #include <myke/mem/pm.h>
#define MEMMAP_ENTRIES 16 #define MEMMAP_ENTRIES 16
@@ -84,7 +84,7 @@ void mmap_init_multiboot(struct multiboot_mmap_entry *entries, uint32_t count) {
continue; // skip for now continue; // skip for now
} }
pmm_init((void *) entry->address, entry->length); pm_init((void *) entry->address, entry->length);
entry->type = MMAP_TYPE_PAGING; entry->type = MMAP_TYPE_PAGING;
} }
} }

View File

@@ -1,59 +0,0 @@
//
// Created by rick on 21-02-21.
//
#include <attributes.h>
#include <stdbool.h>
#include <sys/types.h>
#include <myke/mem/paging.h>
#define TABLE_ADDR_MASK 0xFFFFF000
#define DIRECTORY_SIZE 1024
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;
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;
page_directory_entry page_directory[DIRECTORY_SIZE] att_aligned(4096);
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;
}
}

View File

@@ -6,7 +6,8 @@
#include <string.h> #include <string.h>
#include <myke/libk/libk.h> #include <myke/libk/libk.h>
#include <myke/mem/pmm.h> #include <myke/mem/pm.h>
#include <myke/mem/vmm.h>
#define NUM_PAGING_INFOS 16 #define NUM_PAGING_INFOS 16
@@ -39,7 +40,7 @@ typedef struct {
uint8_t last_paging_info = 0; uint8_t last_paging_info = 0;
paging_info paging_infos[NUM_PAGING_INFOS]; paging_info paging_infos[NUM_PAGING_INFOS];
void pmm_init(void *start_addr, size_t size) { void pm_init(void *start_addr, size_t size) {
uint32_t num_pages = size / PAGE_SIZE; uint32_t num_pages = size / PAGE_SIZE;
uint32_t bitmap_size = num_pages / 8; uint32_t bitmap_size = num_pages / 8;
uint32_t bitmap_pages = bitmap_size / PAGE_SIZE; uint32_t bitmap_pages = bitmap_size / PAGE_SIZE;
@@ -48,6 +49,10 @@ void pmm_init(void *start_addr, size_t size) {
paging_infos[last_paging_info].size = size; paging_infos[last_paging_info].size = size;
paging_infos[last_paging_info].flags.present = true; paging_infos[last_paging_info].flags.present = true;
// map into memory
vmm_assign_page(start_addr, start_addr, bitmap_pages);
// set state
memset(start_addr, BLOCK_FREE, bitmap_pages); memset(start_addr, BLOCK_FREE, bitmap_pages);
for (uint32_t i = 0; i < bitmap_pages; ++i) { for (uint32_t i = 0; i < bitmap_pages; ++i) {
bitmap_set((uint8_t *) start_addr, i); bitmap_set((uint8_t *) start_addr, i);
@@ -55,7 +60,7 @@ void pmm_init(void *start_addr, size_t size) {
last_paging_info++; last_paging_info++;
} }
void *pmm_get_pages(uint32_t num_pages) { void *pm_get_pages(uint32_t num_pages) {
for (int i = 0; i < last_paging_info; ++i) { for (int i = 0; i < last_paging_info; ++i) {
paging_info *info = &paging_infos[i]; paging_info *info = &paging_infos[i];
if (!info->flags.present) continue; if (!info->flags.present) continue;
@@ -75,7 +80,9 @@ void *pmm_get_pages(uint32_t num_pages) {
for (k = j; k < j + num_pages; ++k) { for (k = j; k < j + num_pages; ++k) {
bitmap_set(info->page_bitmap, k); bitmap_set(info->page_bitmap, k);
} }
return page_to_addr(info->first_page, j); void *paddr = page_to_addr(info->first_page, j);
vmm_assign_page(paddr, paddr, num_pages);
return paddr;
} }
} }
} }
@@ -83,7 +90,7 @@ void *pmm_get_pages(uint32_t num_pages) {
return NULL; return NULL;
} }
void pmm_free_pages(void *page, uint32_t num_pages) { void pm_free_pages(void *page, uint32_t num_pages) {
for (int i = 0; i < last_paging_info; ++i) { for (int i = 0; i < last_paging_info; ++i) {
paging_info *info = &paging_infos[i]; paging_info *info = &paging_infos[i];
if (!info->flags.present) continue; if (!info->flags.present) continue;
@@ -95,5 +102,6 @@ void pmm_free_pages(void *page, uint32_t num_pages) {
for (uint32_t current_page = first_page; current_page < first_page + num_pages; ++current_page) { for (uint32_t current_page = first_page; current_page < first_page + num_pages; ++current_page) {
bitmap_unset(info->page_bitmap, current_page); bitmap_unset(info->page_bitmap, current_page);
} }
vmm_unassign_page(page, num_pages);
} }
} }

6
kernel/mem/vmm.S Normal file
View File

@@ -0,0 +1,6 @@
.code32
.section .text
.global vmm_get_current_page_directory
vmm_get_current_page_directory:
movl %cr3, %eax
ret

116
kernel/mem/vmm.c Normal file
View File

@@ -0,0 +1,116 @@
//
// Created by rick on 21-02-21.
//
#include <attributes.h>
#include <stdbool.h>
#include <sys/types.h>
#include <myke/mem/vmm.h>
#include <myke/mem/pm.h>
#include <myke/libk/libk.h>
#define TABLE_ADDR_MASK 0xFFFFF000
#define TABLE_ADDR_IMASK ~TABLE_ADDR_MASK
#define DIRECTORY_SIZE 1024
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: 1;
bool page_size: 1;
bool global: 1; // ignored
uint8_t avail: 3;
} att_packed;
uint32_t addr;
};
} att_packed page_directory_entry;
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: 1;
bool global: 1;
uint8_t available: 3;
} att_packed;
uint32_t addr;
};
} att_packed page_table_entry;
//#define in_dir(dir, vaddr) ((page_table_entry*)(((page_directory_entry*)((dir)[(vaddr)/4096/1024].addr & TABLE_ADDR_MASK))[(vaddr)/4096%1024]))
#define dir_index(vaddr) (((uint32_t)(vaddr)) / PAGE_SIZE / DIRECTORY_SIZE)
#define page_index(vaddr) (((uint32_t)(vaddr)) / PAGE_SIZE % DIRECTORY_SIZE)
page_directory_entry boot_paging_directory[DIRECTORY_SIZE] att_aligned(4096);
page_table_entry boot_primary_table[DIRECTORY_SIZE] att_aligned(4096);
extern page_directory_entry *vmm_get_current_page_directory();
void vmm_assign_page_one(uint32_t paddr, uint32_t vaddr) {
page_directory_entry *curr = vmm_get_current_page_directory();
page_directory_entry *dentry = &curr[dir_index(vaddr)];
if (!dentry->present || (dentry->addr & TABLE_ADDR_MASK) == 0) {
// todo allocate table
k_panics("need to allocate new table");
}
page_table_entry *first_entry = (page_table_entry *) (dentry->addr & TABLE_ADDR_MASK);
page_table_entry *pentry = &first_entry[page_index(vaddr)];
if (pentry->present) {
// todo already present
k_panics("virtual address already in use");
}
pentry->addr = (pentry->addr & TABLE_ADDR_IMASK) | paddr;
pentry->present = true;
pentry->read_write = true;
}
void vmm_unassign_page_one(uint32_t vaddr) {
page_directory_entry *curr = vmm_get_current_page_directory();
page_directory_entry *dentry = &curr[dir_index(vaddr)];
if (!dentry->present || (dentry->addr & TABLE_ADDR_MASK) == 0) {
// todo allocate table
k_panics("need to allocate new table");
}
page_table_entry *first_entry = (page_table_entry *) (dentry->addr & TABLE_ADDR_MASK);
page_table_entry *pentry = &first_entry[page_index(vaddr)];
if (!pentry->present) {
// todo already present
k_panics("virtual address not in use");
}
pentry->present = false;
pentry->read_write = false;
pentry->addr = pentry->addr & TABLE_ADDR_IMASK;
}
void vmm_assign_page(void *paddr, void *vaddr, size_t number_of_pages) {
for (size_t i = 0; i < number_of_pages; ++i) {
vmm_assign_page_one(((uint32_t) paddr) + PAGE_SIZE * i, ((uint32_t) vaddr) + PAGE_SIZE * i);
}
}
void vmm_unassign_page(void *vaddr, size_t number_of_pages) {
for (size_t i = 0; i < number_of_pages; ++i) {
vmm_unassign_page_one(((uint32_t) vaddr) + PAGE_SIZE * i);
}
}

View File

@@ -9,7 +9,7 @@
#include <myke/cpu/cpu.h> #include <myke/cpu/cpu.h>
#include <myke/libk/libk.h> #include <myke/libk/libk.h>
#include <myke/mem/pmm.h> #include <myke/mem/pm.h>
#include <myke/tasks/task.h> #include <myke/tasks/task.h>
#define stack_end(task) ((task)->stack + ((task)->stack_page_count * PAGE_SIZE)) #define stack_end(task) ((task)->stack + ((task)->stack_page_count * PAGE_SIZE))
@@ -204,7 +204,7 @@ task_t *task_create(task_entrypoint entrypoint, void *entry_data) {
new_task->tid = last_tid++; new_task->tid = last_tid++;
new_task->state = TASK_STATE_RUNNABLE; new_task->state = TASK_STATE_RUNNABLE;
new_task->stack = pmm_get_pages(16); new_task->stack = pm_get_pages(16);
new_task->stack_page_count = 16; new_task->stack_page_count = 16;
// todo check for null // todo check for null

View File

@@ -10,24 +10,34 @@ SECTIONS
loaded at by the bootloader. */ loaded at by the bootloader. */
. = 1M; . = 1M;
_kernel_start = .; _kernel_start = .;
.boot.data ALIGN(4K) : {
*(.multiboot)
*(.boot.data)
}
.boot.text ALIGN(4K) : {
*(.boot.text)
}
.boot.bss ALIGN(4K) : {
*(.boot.bss)
}
. += 0xC0000000;
/* First put the multiboot header, as it is required to be put very early /* 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. early in the image or the bootloader won't recognize the file format.
Next we'll put the .text section. */ Next we'll put the .text section. */
.text BLOCK(4K) : ALIGN(4K) .text ALIGN(4K) : AT(ADDR(.text)-0xC0000000)
{ {
*(.multiboot)
*(.text) *(.text)
} }
/* Read-only data. */ /* Read-only data. */
.rodata BLOCK(4K) : ALIGN(4K) .rodata ALIGN(4K) : AT(ADDR(.rodata)-0xC0000000)
{ {
*(.rodata) *(.rodata)
} }
/* Read-write data (initialized) */ /* Read-write data (initialized) */
.data BLOCK(4K) : ALIGN(4K) .data ALIGN(4K) : AT(ADDR(.data)-0xC0000000)
{ {
*(.data) *(.data)
. = ALIGN(16); . = ALIGN(16);
@@ -41,12 +51,12 @@ SECTIONS
} }
/* Read-write data (uninitialized) and stack */ /* Read-write data (uninitialized) and stack */
.bss BLOCK(4K) : ALIGN(4K) .bss ALIGN(4K) : AT(ADDR(.bss)-0xC0000000)
{ {
*(COMMON) *(COMMON)
*(.bss) *(.bss)
} }
_kernel_end = .; _kernel_end = . - 0xC0000000;
/DISCARD/ : { /DISCARD/ : {
*(.eh_frame); *(.eh_frame);