Refactoring assembly entry point

This commit is contained in:
Marco Cetica
2021-02-03 15:59:42 +01:00
parent dc3803491e
commit 1b207add8c
61 changed files with 4782 additions and 4779 deletions

View File

@@ -1,9 +1,9 @@
OBJS = paging.o kheap.o ordered_array.o
CC = i686-elf-gcc # cross-compiler
CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c
all:${OBJS}
%.o: %.c
OBJS = paging.o kheap.o ordered_array.o
CC = i686-elf-gcc # cross-compiler
CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c
all:${OBJS}
%.o: %.c
${CC} ${CFLAGS} $< -o $@

View File

@@ -1,329 +1,329 @@
#include "kheap.h"
#include "paging.h"
#include "../libc/panic.h"
extern uint32_t end;
uint32_t placement_addr = (uint32_t)&end;
extern page_directory_t *kernel_directory;
heap_t *kheap = 0;
uint32_t kmalloc_int(uint32_t sz, int32_t align, uint32_t *phys) {
if(kheap != 0) {
void *addr = alloc(sz, (uint8_t)align, kheap);
if(phys != 0) {
page_t *page = get_page((uint32_t)addr, 0, kernel_directory);
*phys = page->fr*0x1000 + ((uint32_t)addr&0xFFF);
}
return (uint32_t)addr;
} else {
if(align == 1 && (placement_addr & 0xFFFFF000)) {
placement_addr &= 0xFFFFF000;
placement_addr += 0x1000;
}
if(phys)
*phys = placement_addr;
uint32_t tmp = placement_addr;
placement_addr += sz;
return tmp;
}
}
void kfree(void *p) {
free(p, kheap);
}
uint32_t kmalloc_a(uint32_t sz) {
return kmalloc_int(sz, 1, 0);
}
uint32_t kmalloc_p(uint32_t sz, uint32_t *phys) {
return kmalloc_int(sz, 0, phys);
}
uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys) {
return kmalloc_int(sz, 1, phys);
}
uint32_t kmalloc(uint32_t sz) {
return kmalloc_int(sz, 0, 0);
}
static void expand(uint32_t new_size, heap_t *heap) {
// First check if new size is greater than older one
ASSERT(new_size > heap->end_address - heap->start_address);
// Get nearest page boundary
if((new_size&0xFFFFF000) != 0) {
new_size &= 0xFFFFF000;
new_size += 0x1000;
}
// Check if new size is not greater than maximum size
ASSERT(heap->start_address+new_size <= heap->max_address);
uint32_t old_size = heap->end_address - heap->start_address;
uint32_t it = old_size;
while(it < new_size) {
alloc_frame(get_page(heap->start_address+it, 1, kernel_directory),
(heap->supervisor) ? 1 : 0, (heap->readonly) ? 0 : 1);
it += 0x1000; // Page size
}
heap->end_address = heap->start_address+new_size;
}
static uint32_t contract(uint32_t new_size, heap_t *heap) {
ASSERT(new_size < heap->end_address-heap->start_address);
if(new_size&0x1000) {
new_size &= 0x1000;
new_size += 0x1000;
}
if(new_size < HEAP_MIN_SIZE)
new_size = HEAP_MIN_SIZE;
uint32_t old_size = heap->end_address - heap->start_address;
uint32_t it = old_size - 0x1000;
while(new_size < it) {
free_frame(get_page(heap->start_address+it, 0, kernel_directory));
it -= 0x1000;
}
heap->end_address = heap->start_address + new_size;
return new_size;
}
static uint32_t find_smallest_hole(uint32_t size, uint8_t page_align, heap_t *heap) {
uint32_t it = 0;
// Find smallest hole that fit our request
while(it < heap->index.size) {
header_t *head = (header_t*)lookup_ordered_array(it, &heap->index);
if(page_align > 0) {
// page must be aligned?
uint32_t location = (uint32_t)head;
uint32_t offset = 0;
if(((location+sizeof(header_t)) & 0xFFFFF000) != 0)
offset = 0x1000 - (location+sizeof(header_t))%0x1000;
uint32_t hole_size = (uint32_t)head->size - offset;
// Check if we can fit this page in that hole
if(hole_size >= (uint32_t)size)
break;
} else if(head->size >= size)
break;
it++;
}
// If we didn't find anything
if(it == heap->index.size)
return -1;
else
return it;
}
static uint8_t header_t_less_than(void *a, void *b) {
return (((header_t*)a)->size < ((header_t*)b)->size)?1:0;
}
heap_t *create_heap(uint32_t start, uint32_t end_addr, uint32_t max, uint8_t supervisor, uint8_t readonly) {
heap_t *heap = (heap_t*)kmalloc(sizeof(heap_t));
ASSERT(start%0x1000 == 0);
ASSERT(end_addr%0x1000 == 0);
// Initialize the index
heap->index = place_ordered_array((void*)start, HEAP_INDEX_SIZE, &header_t_less_than);
// Shift start address to the right
start += sizeof(type_t) * HEAP_INDEX_SIZE;
// Check if start address is page-aligned
if ((start & 0xFFFFF000) != 0) {
start &= 0xFFFFF000;
start += 0x1000;
}
// Store vars into heap
heap->start_address = start;
heap->end_address = end_addr;
heap->max_address = max;
heap->supervisor = supervisor;
heap->readonly = readonly;
header_t *hole = (header_t*)start;
hole->size = end_addr - start;
hole->magic = HEAP_MAGIC;
hole->is_hole = 1;
insert_ordered_array((void*)hole, &heap->index);
return heap;
}
void *alloc(uint32_t size, uint8_t page_align, heap_t *heap) {
uint32_t new_size = size + sizeof(header_t) + sizeof(footer_t);
// Find smallest hole suitable
uint32_t it = find_smallest_hole(new_size, page_align, heap);
if((int32_t)it == -1) {
uint32_t old_len = heap->end_address - heap->start_address;
uint32_t old_end_addr = heap->end_address;
// Allocate more space
expand(old_len+new_size, heap);
uint32_t new_len = heap->end_address - heap->start_address;
it = 0;
uint32_t idx = -1; uint32_t value = 0x0;
while(it < heap->index.size) {
uint32_t tmp = (uint32_t)lookup_ordered_array(it, &heap->index);
if(tmp > value) {
value = tmp;
idx = it;
}
it++;
}
// If no headers has been found, add a new one
if((int32_t)idx == -1) {
header_t *head = (header_t*)old_end_addr;
head->magic = HEAP_MAGIC;
head->size = new_len - old_len;
head->is_hole = 1;
footer_t *foot = (footer_t*)(old_end_addr + head->size - sizeof(footer_t));
foot->magic = HEAP_MAGIC;
foot->header = head;
insert_ordered_array((void*)head, &heap->index);
} else {
header_t *head = lookup_ordered_array(idx, &heap->index);
head->size += new_len - old_len;
// Update the footer
footer_t *foot = (footer_t*)((uint32_t)head + head->size - sizeof(footer_t));
foot->header = head;
foot->magic = HEAP_MAGIC;
}
// Now we have enough space, so recall this function again
return alloc(size, page_align, heap);
}
header_t *origin_hole_head = (header_t*)lookup_ordered_array(it, &heap->index);
uint32_t origin_hole_p = (uint32_t)origin_hole_head;
uint32_t origin_hole_s = origin_hole_head->size;
// Check if we should split the hole into two parts
if(origin_hole_s-new_size < sizeof(header_t)+sizeof(footer_t)) {
// Increase the requested size to the size of the hole we found
size += origin_hole_s-new_size;
new_size = origin_hole_s;
}
// Check if we need to page-align data
if(page_align && origin_hole_p&0xFFFFF000) {
uint32_t new_loc = origin_hole_p + 0x1000 - (origin_hole_p&0xFFF) - sizeof(header_t);
header_t *hole_header = (header_t*)origin_hole_p;
hole_header->size = 0x1000 - (origin_hole_p&0xFFF) - sizeof(header_t);
hole_header->magic = HEAP_MAGIC;
hole_header->is_hole = 1;
footer_t *hole_footer = (footer_t*)((uint32_t)new_loc - sizeof(header_t));
hole_footer->magic = HEAP_MAGIC;
hole_footer->header = hole_header;
origin_hole_p = new_loc;
origin_hole_s = origin_hole_s - hole_header->size;
} else
remove_ordered_array(it, &heap->index); // Remove hole, since we don't need it anymore
// Rewrite original header
header_t *block_head = (header_t*)origin_hole_p;
block_head->magic = HEAP_MAGIC;
block_head->is_hole = 0;
block_head->size = new_size;
// and the footer
footer_t *block_foot = (footer_t*)(origin_hole_p + sizeof(header_t) + size);
block_foot->magic = HEAP_MAGIC;
block_foot->header = block_head;
// Check if we need to write a new hole after the allocated block
if(origin_hole_s - new_size > 0) {
header_t *hole_head = (header_t*)(origin_hole_p + sizeof(header_t) + size + sizeof(footer_t));
hole_head->magic = HEAP_MAGIC;
hole_head->is_hole = 1;
hole_head->size = origin_hole_s - new_size;
footer_t *hole_foot = (footer_t*)((uint32_t)hole_head + origin_hole_s - new_size - sizeof(footer_t));
if((uint32_t)hole_foot < heap->end_address) {
hole_foot->magic = HEAP_MAGIC;
hole_foot->header = hole_head;
}
// Add new hole to the data structure
insert_ordered_array((void*)hole_head, &heap->index);
}
// Return the block header
return (void*)((uint32_t)block_head+sizeof(header_t));
}
void free(void *p, heap_t *heap) {
// Check null pointers
if(p == 0)
return;
// Retrieve data
header_t *head = (header_t*)((uint32_t)p - sizeof(header_t));
footer_t *foot = (footer_t*)((uint32_t)head + head->size - sizeof(footer_t));
ASSERT(head->magic == HEAP_MAGIC);
ASSERT(foot->magic == HEAP_MAGIC);
head->is_hole = 1; // Make this a hole
int8_t add_to_free_hole = 1; // Add this header to free holes
// Left unify
footer_t *test_foot = (footer_t*)((uint32_t)head - sizeof(footer_t));
if(test_foot->magic == HEAP_MAGIC && test_foot->header->is_hole == 1 ) {
uint32_t cache_s = head->size; // Store current size
head = test_foot->header; // Rewrite header into new one
foot->header = head; // Point footer to the new header
head->size += cache_s; // Increase size
add_to_free_hole = 0; // Header already in the structure.
}
// Right unify
header_t *test_head = (header_t*)((uint32_t)foot + sizeof(footer_t));
if(test_head->magic == HEAP_MAGIC && test_head->is_hole) {
head->size += test_head->size; // Increase size
test_foot = (footer_t*)((uint32_t)test_foot + test_head->size - sizeof(footer_t));
foot = test_foot;
// Find and remove this header from the structure
uint32_t it = 0;
while((it < heap->index.size) && (lookup_ordered_array(it, &heap->index) != (void*)test_head))
it++;
// Check if we actually found something
ASSERT(it < heap->index.size);
// Remove that item
remove_ordered_array(it, &heap->index);
}
// If footer is located at the end, we can contract the heap
if((uint32_t)foot+sizeof(footer_t) == heap->end_address) {
uint32_t old_len = heap->end_address-heap->start_address;
uint32_t new_len = contract((uint32_t)head - heap->start_address, heap);
// Check dimensions after resizing
if(head->size - (old_len-new_len) > 0) {
// Dimensions is still a positive value, so we can resize
head->size -= old_len-new_len;
foot = (footer_t*)((uint32_t)head + head->size - sizeof(footer_t));
foot->magic = HEAP_MAGIC;
foot->header = head;
} else {
// Remove block from the structure
uint32_t it = 0;
while((it < heap->index.size) && (lookup_ordered_array(it, &heap->index) != (void*)test_head))
it++;
// If we didn't find that block we haven't nothing to remove
if(it < heap->index.size)
remove_ordered_array(it, &heap->index);
}
}
// If required by the user, add that block to the structure
if(add_to_free_hole == 1)
insert_ordered_array((void*)head, &heap->index);
}
#include "kheap.h"
#include "paging.h"
#include "../libc/panic.h"
extern uint32_t end;
uint32_t placement_addr = (uint32_t)&end;
extern page_directory_t *kernel_directory;
heap_t *kheap = 0;
uint32_t kmalloc_int(uint32_t sz, int32_t align, uint32_t *phys) {
if(kheap != 0) {
void *addr = alloc(sz, (uint8_t)align, kheap);
if(phys != 0) {
page_t *page = get_page((uint32_t)addr, 0, kernel_directory);
*phys = page->fr*0x1000 + ((uint32_t)addr&0xFFF);
}
return (uint32_t)addr;
} else {
if(align == 1 && (placement_addr & 0xFFFFF000)) {
placement_addr &= 0xFFFFF000;
placement_addr += 0x1000;
}
if(phys)
*phys = placement_addr;
uint32_t tmp = placement_addr;
placement_addr += sz;
return tmp;
}
}
void kfree(void *p) {
free(p, kheap);
}
uint32_t kmalloc_a(uint32_t sz) {
return kmalloc_int(sz, 1, 0);
}
uint32_t kmalloc_p(uint32_t sz, uint32_t *phys) {
return kmalloc_int(sz, 0, phys);
}
uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys) {
return kmalloc_int(sz, 1, phys);
}
uint32_t kmalloc(uint32_t sz) {
return kmalloc_int(sz, 0, 0);
}
static void expand(uint32_t new_size, heap_t *heap) {
// First check if new size is greater than older one
ASSERT(new_size > heap->end_address - heap->start_address);
// Get nearest page boundary
if((new_size&0xFFFFF000) != 0) {
new_size &= 0xFFFFF000;
new_size += 0x1000;
}
// Check if new size is not greater than maximum size
ASSERT(heap->start_address+new_size <= heap->max_address);
uint32_t old_size = heap->end_address - heap->start_address;
uint32_t it = old_size;
while(it < new_size) {
alloc_frame(get_page(heap->start_address+it, 1, kernel_directory),
(heap->supervisor) ? 1 : 0, (heap->readonly) ? 0 : 1);
it += 0x1000; // Page size
}
heap->end_address = heap->start_address+new_size;
}
static uint32_t contract(uint32_t new_size, heap_t *heap) {
ASSERT(new_size < heap->end_address-heap->start_address);
if(new_size&0x1000) {
new_size &= 0x1000;
new_size += 0x1000;
}
if(new_size < HEAP_MIN_SIZE)
new_size = HEAP_MIN_SIZE;
uint32_t old_size = heap->end_address - heap->start_address;
uint32_t it = old_size - 0x1000;
while(new_size < it) {
free_frame(get_page(heap->start_address+it, 0, kernel_directory));
it -= 0x1000;
}
heap->end_address = heap->start_address + new_size;
return new_size;
}
static uint32_t find_smallest_hole(uint32_t size, uint8_t page_align, heap_t *heap) {
uint32_t it = 0;
// Find smallest hole that fit our request
while(it < heap->index.size) {
header_t *head = (header_t*)lookup_ordered_array(it, &heap->index);
if(page_align > 0) {
// page must be aligned?
uint32_t location = (uint32_t)head;
uint32_t offset = 0;
if(((location+sizeof(header_t)) & 0xFFFFF000) != 0)
offset = 0x1000 - (location+sizeof(header_t))%0x1000;
uint32_t hole_size = (uint32_t)head->size - offset;
// Check if we can fit this page in that hole
if(hole_size >= (uint32_t)size)
break;
} else if(head->size >= size)
break;
it++;
}
// If we didn't find anything
if(it == heap->index.size)
return -1;
else
return it;
}
static uint8_t header_t_less_than(void *a, void *b) {
return (((header_t*)a)->size < ((header_t*)b)->size)?1:0;
}
heap_t *create_heap(uint32_t start, uint32_t end_addr, uint32_t max, uint8_t supervisor, uint8_t readonly) {
heap_t *heap = (heap_t*)kmalloc(sizeof(heap_t));
ASSERT(start%0x1000 == 0);
ASSERT(end_addr%0x1000 == 0);
// Initialize the index
heap->index = place_ordered_array((void*)start, HEAP_INDEX_SIZE, &header_t_less_than);
// Shift start address to the right
start += sizeof(type_t) * HEAP_INDEX_SIZE;
// Check if start address is page-aligned
if ((start & 0xFFFFF000) != 0) {
start &= 0xFFFFF000;
start += 0x1000;
}
// Store vars into heap
heap->start_address = start;
heap->end_address = end_addr;
heap->max_address = max;
heap->supervisor = supervisor;
heap->readonly = readonly;
header_t *hole = (header_t*)start;
hole->size = end_addr - start;
hole->magic = HEAP_MAGIC;
hole->is_hole = 1;
insert_ordered_array((void*)hole, &heap->index);
return heap;
}
void *alloc(uint32_t size, uint8_t page_align, heap_t *heap) {
uint32_t new_size = size + sizeof(header_t) + sizeof(footer_t);
// Find smallest hole suitable
uint32_t it = find_smallest_hole(new_size, page_align, heap);
if((int32_t)it == -1) {
uint32_t old_len = heap->end_address - heap->start_address;
uint32_t old_end_addr = heap->end_address;
// Allocate more space
expand(old_len+new_size, heap);
uint32_t new_len = heap->end_address - heap->start_address;
it = 0;
uint32_t idx = -1; uint32_t value = 0x0;
while(it < heap->index.size) {
uint32_t tmp = (uint32_t)lookup_ordered_array(it, &heap->index);
if(tmp > value) {
value = tmp;
idx = it;
}
it++;
}
// If no headers has been found, add a new one
if((int32_t)idx == -1) {
header_t *head = (header_t*)old_end_addr;
head->magic = HEAP_MAGIC;
head->size = new_len - old_len;
head->is_hole = 1;
footer_t *foot = (footer_t*)(old_end_addr + head->size - sizeof(footer_t));
foot->magic = HEAP_MAGIC;
foot->header = head;
insert_ordered_array((void*)head, &heap->index);
} else {
header_t *head = lookup_ordered_array(idx, &heap->index);
head->size += new_len - old_len;
// Update the footer
footer_t *foot = (footer_t*)((uint32_t)head + head->size - sizeof(footer_t));
foot->header = head;
foot->magic = HEAP_MAGIC;
}
// Now we have enough space, so recall this function again
return alloc(size, page_align, heap);
}
header_t *origin_hole_head = (header_t*)lookup_ordered_array(it, &heap->index);
uint32_t origin_hole_p = (uint32_t)origin_hole_head;
uint32_t origin_hole_s = origin_hole_head->size;
// Check if we should split the hole into two parts
if(origin_hole_s-new_size < sizeof(header_t)+sizeof(footer_t)) {
// Increase the requested size to the size of the hole we found
size += origin_hole_s-new_size;
new_size = origin_hole_s;
}
// Check if we need to page-align data
if(page_align && origin_hole_p&0xFFFFF000) {
uint32_t new_loc = origin_hole_p + 0x1000 - (origin_hole_p&0xFFF) - sizeof(header_t);
header_t *hole_header = (header_t*)origin_hole_p;
hole_header->size = 0x1000 - (origin_hole_p&0xFFF) - sizeof(header_t);
hole_header->magic = HEAP_MAGIC;
hole_header->is_hole = 1;
footer_t *hole_footer = (footer_t*)((uint32_t)new_loc - sizeof(header_t));
hole_footer->magic = HEAP_MAGIC;
hole_footer->header = hole_header;
origin_hole_p = new_loc;
origin_hole_s = origin_hole_s - hole_header->size;
} else
remove_ordered_array(it, &heap->index); // Remove hole, since we don't need it anymore
// Rewrite original header
header_t *block_head = (header_t*)origin_hole_p;
block_head->magic = HEAP_MAGIC;
block_head->is_hole = 0;
block_head->size = new_size;
// and the footer
footer_t *block_foot = (footer_t*)(origin_hole_p + sizeof(header_t) + size);
block_foot->magic = HEAP_MAGIC;
block_foot->header = block_head;
// Check if we need to write a new hole after the allocated block
if(origin_hole_s - new_size > 0) {
header_t *hole_head = (header_t*)(origin_hole_p + sizeof(header_t) + size + sizeof(footer_t));
hole_head->magic = HEAP_MAGIC;
hole_head->is_hole = 1;
hole_head->size = origin_hole_s - new_size;
footer_t *hole_foot = (footer_t*)((uint32_t)hole_head + origin_hole_s - new_size - sizeof(footer_t));
if((uint32_t)hole_foot < heap->end_address) {
hole_foot->magic = HEAP_MAGIC;
hole_foot->header = hole_head;
}
// Add new hole to the data structure
insert_ordered_array((void*)hole_head, &heap->index);
}
// Return the block header
return (void*)((uint32_t)block_head+sizeof(header_t));
}
void free(void *p, heap_t *heap) {
// Check null pointers
if(p == 0)
return;
// Retrieve data
header_t *head = (header_t*)((uint32_t)p - sizeof(header_t));
footer_t *foot = (footer_t*)((uint32_t)head + head->size - sizeof(footer_t));
ASSERT(head->magic == HEAP_MAGIC);
ASSERT(foot->magic == HEAP_MAGIC);
head->is_hole = 1; // Make this a hole
int8_t add_to_free_hole = 1; // Add this header to free holes
// Left unify
footer_t *test_foot = (footer_t*)((uint32_t)head - sizeof(footer_t));
if(test_foot->magic == HEAP_MAGIC && test_foot->header->is_hole == 1 ) {
uint32_t cache_s = head->size; // Store current size
head = test_foot->header; // Rewrite header into new one
foot->header = head; // Point footer to the new header
head->size += cache_s; // Increase size
add_to_free_hole = 0; // Header already in the structure.
}
// Right unify
header_t *test_head = (header_t*)((uint32_t)foot + sizeof(footer_t));
if(test_head->magic == HEAP_MAGIC && test_head->is_hole) {
head->size += test_head->size; // Increase size
test_foot = (footer_t*)((uint32_t)test_foot + test_head->size - sizeof(footer_t));
foot = test_foot;
// Find and remove this header from the structure
uint32_t it = 0;
while((it < heap->index.size) && (lookup_ordered_array(it, &heap->index) != (void*)test_head))
it++;
// Check if we actually found something
ASSERT(it < heap->index.size);
// Remove that item
remove_ordered_array(it, &heap->index);
}
// If footer is located at the end, we can contract the heap
if((uint32_t)foot+sizeof(footer_t) == heap->end_address) {
uint32_t old_len = heap->end_address-heap->start_address;
uint32_t new_len = contract((uint32_t)head - heap->start_address, heap);
// Check dimensions after resizing
if(head->size - (old_len-new_len) > 0) {
// Dimensions is still a positive value, so we can resize
head->size -= old_len-new_len;
foot = (footer_t*)((uint32_t)head + head->size - sizeof(footer_t));
foot->magic = HEAP_MAGIC;
foot->header = head;
} else {
// Remove block from the structure
uint32_t it = 0;
while((it < heap->index.size) && (lookup_ordered_array(it, &heap->index) != (void*)test_head))
it++;
// If we didn't find that block we haven't nothing to remove
if(it < heap->index.size)
remove_ordered_array(it, &heap->index);
}
}
// If required by the user, add that block to the structure
if(add_to_free_hole == 1)
insert_ordered_array((void*)head, &heap->index);
}

View File

@@ -1,70 +1,70 @@
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
/*** Heap implementation from James Molloy's tutorial:
http://www.jamesmolloy.co.uk/tutorial_html/7.-The%20Heap.html ***/
/* This heap algorithm uses two different data structures: blocks and holes.
* Blocks: Contiguous areas of memory containing user data
* Holes: Special kind of blocks that are not in use, this is the result
* of free() operation. Those spaces lend to a common problem called "Fragmentation";
* where malloc() cannot use those spaces anymore because they are too small for any
* kind of program. Any modern OS must have a solution to avoid this problem, but to keep
* things simple as possible i wont implement anything like that.
* Blocks/holes contains informations like the magic number(error checking), the type of
* chunk(hole or block) and the size, while the footer contains only a pointer to the header
* (and obviously an error checking flag).
*/
#ifndef KHEAP_H
#define KHEAP_H
#define KHEAP_START 0xC0000000
#define KHEAP_INITIAL_SIZE 0x100000
#define HEAP_INDEX_SIZE 0x20000
#define HEAP_MAGIC 0x123890AB
#define HEAP_MIN_SIZE 0x70000
#include <stdint.h>
#include "ordered_array.h"
// Data structure for single hole/block
typedef struct {
uint32_t magic; // Magic number for error checking
uint8_t is_hole; // 1 if it's an hole, 0 for a block
uint32_t size; // Size of block
} header_t;
typedef struct {
uint32_t magic; // Same as above
header_t *header; // Pointer to the header block
} footer_t;
typedef struct {
ordered_array_t index;
uint32_t start_address; // Begin of allocated space
uint32_t end_address; // End of allocated space
uint32_t max_address; // Maximum size heap can be expanded to
uint8_t supervisor;
uint8_t readonly;
} heap_t;
// Create a new heap
heap_t *create_heap(uint32_t start, uint32_t end, uint32_t max, uint8_t supervisor, uint8_t readonly);
// Allocates a contigious region of memory in size
void *alloc(uint32_t size, uint8_t page_align, heap_t *heap);
// Free a block allocated with alloc
void free(void *p, heap_t *heap);
uint32_t kmalloc_int(uint32_t sz, int32_t align, uint32_t *phys);
uint32_t kmalloc_a(uint32_t sz);
uint32_t kmalloc_p(uint32_t sz, uint32_t *phys);
uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys);
uint32_t kmalloc(uint32_t sz);
void kfree(void *p);
#endif
/*****************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/vulcanos *
*****************************************/
/*** Heap implementation from James Molloy's tutorial:
http://www.jamesmolloy.co.uk/tutorial_html/7.-The%20Heap.html ***/
/* This heap algorithm uses two different data structures: blocks and holes.
* Blocks: Contiguous areas of memory containing user data
* Holes: Special kind of blocks that are not in use, this is the result
* of free() operation. Those spaces lend to a common problem called "Fragmentation";
* where malloc() cannot use those spaces anymore because they are too small for any
* kind of program. Any modern OS must have a solution to avoid this problem, but to keep
* things simple as possible i wont implement anything like that.
* Blocks/holes contains informations like the magic number(error checking), the type of
* chunk(hole or block) and the size, while the footer contains only a pointer to the header
* (and obviously an error checking flag).
*/
#ifndef KHEAP_H
#define KHEAP_H
#define KHEAP_START 0xC0000000
#define KHEAP_INITIAL_SIZE 0x100000
#define HEAP_INDEX_SIZE 0x20000
#define HEAP_MAGIC 0x123890AB
#define HEAP_MIN_SIZE 0x70000
#include <stdint.h>
#include "ordered_array.h"
// Data structure for single hole/block
typedef struct {
uint32_t magic; // Magic number for error checking
uint8_t is_hole; // 1 if it's an hole, 0 for a block
uint32_t size; // Size of block
} header_t;
typedef struct {
uint32_t magic; // Same as above
header_t *header; // Pointer to the header block
} footer_t;
typedef struct {
ordered_array_t index;
uint32_t start_address; // Begin of allocated space
uint32_t end_address; // End of allocated space
uint32_t max_address; // Maximum size heap can be expanded to
uint8_t supervisor;
uint8_t readonly;
} heap_t;
// Create a new heap
heap_t *create_heap(uint32_t start, uint32_t end, uint32_t max, uint8_t supervisor, uint8_t readonly);
// Allocates a contigious region of memory in size
void *alloc(uint32_t size, uint8_t page_align, heap_t *heap);
// Free a block allocated with alloc
void free(void *p, heap_t *heap);
uint32_t kmalloc_int(uint32_t sz, int32_t align, uint32_t *phys);
uint32_t kmalloc_a(uint32_t sz);
uint32_t kmalloc_p(uint32_t sz, uint32_t *phys);
uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys);
uint32_t kmalloc(uint32_t sz);
void kfree(void *p);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,66 +1,66 @@
#include "ordered_array.h"
#include "kheap.h"
#include "../libc/panic.h"
#include "../libc/string.h"
uint8_t standard_lessthan_predicate(type_t a, type_t b) {
if (a < b)
return 1;
else
return 0;
}
ordered_array_t create_ordered_array(uint32_t max_size, lessthan_predicate_t less_than) {
ordered_array_t to_ret;
to_ret.array = (void*)kmalloc(max_size*sizeof(type_t));
memset(to_ret.array, 0, max_size*sizeof(type_t));
to_ret.size = 0;
to_ret.max_size = max_size;
to_ret.less_than = less_than;
return to_ret;
}
ordered_array_t place_ordered_array(void *addr, uint32_t max_size, lessthan_predicate_t less_than) {
ordered_array_t to_ret;
to_ret.array = (type_t*)addr;
memset(to_ret.array, 0, max_size*sizeof(type_t));
to_ret.size = 0;
to_ret.max_size = max_size;
to_ret.less_than = less_than;
return to_ret;
}
void destroy_ordered_array(ordered_array_t *array) {
kfree(array->array);
}
void insert_ordered_array(type_t item, ordered_array_t *array) {
uint32_t it = 0;
while(it < array->size && array->less_than(array->array[it], item))
it++;
if(it == array->size)
array->array[array->size++] = item;
else {
type_t tmp = array->array[it];
array->array[it] = item;
while(it < array->size) {
it++;
type_t tmp2 = array->array[it];
array->array[it] = tmp;
tmp = tmp2;
}
array->size++;
}
}
type_t lookup_ordered_array(uint32_t i, ordered_array_t *array) {
return array->array[i];
}
void remove_ordered_array(uint32_t i, ordered_array_t *array) {
while(i < array->size) {
array->array[i] = array->array[i+1];
i++;
}
array->size--;
}
#include "ordered_array.h"
#include "kheap.h"
#include "../libc/panic.h"
#include "../libc/string.h"
uint8_t standard_lessthan_predicate(type_t a, type_t b) {
if (a < b)
return 1;
else
return 0;
}
ordered_array_t create_ordered_array(uint32_t max_size, lessthan_predicate_t less_than) {
ordered_array_t to_ret;
to_ret.array = (void*)kmalloc(max_size*sizeof(type_t));
memset(to_ret.array, 0, max_size*sizeof(type_t));
to_ret.size = 0;
to_ret.max_size = max_size;
to_ret.less_than = less_than;
return to_ret;
}
ordered_array_t place_ordered_array(void *addr, uint32_t max_size, lessthan_predicate_t less_than) {
ordered_array_t to_ret;
to_ret.array = (type_t*)addr;
memset(to_ret.array, 0, max_size*sizeof(type_t));
to_ret.size = 0;
to_ret.max_size = max_size;
to_ret.less_than = less_than;
return to_ret;
}
void destroy_ordered_array(ordered_array_t *array) {
kfree(array->array);
}
void insert_ordered_array(type_t item, ordered_array_t *array) {
uint32_t it = 0;
while(it < array->size && array->less_than(array->array[it], item))
it++;
if(it == array->size)
array->array[array->size++] = item;
else {
type_t tmp = array->array[it];
array->array[it] = item;
while(it < array->size) {
it++;
type_t tmp2 = array->array[it];
array->array[it] = tmp;
tmp = tmp2;
}
array->size++;
}
}
type_t lookup_ordered_array(uint32_t i, ordered_array_t *array) {
return array->array[i];
}
void remove_ordered_array(uint32_t i, ordered_array_t *array) {
while(i < array->size) {
array->array[i] = array->array[i+1];
i++;
}
array->size--;
}

View File

@@ -1,39 +1,39 @@
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#ifndef ORDERED_ARRAY_H
#define ORDERED_ARRAY_H
#include <stdint.h>
/* Our list is always in a 'sorted state',
* it can store anything that can be casted
* to void* */
typedef void* type_t;
/* The following predicate should return non-zero
* if the first argument is less than the second */
typedef uint8_t (*lessthan_predicate_t)(type_t,type_t);
typedef struct {
type_t *array;
uint32_t size;
uint32_t max_size;
lessthan_predicate_t less_than;
} ordered_array_t;
uint8_t standard_lessthan_predicate(type_t a, type_t b);
// Create a new ordered array
ordered_array_t create_ordered_array(uint32_t max_size, lessthan_predicate_t less_than);
ordered_array_t place_ordered_array(void *addr, uint32_t max_size, lessthan_predicate_t less_than);
// Destroy an ordered array
void destroy_ordered_array(ordered_array_t *array);
// Add an item into the array
void insert_ordered_array(type_t item, ordered_array_t *array);
type_t lookup_ordered_array(uint32_t i, ordered_array_t *array);
void remove_ordered_array(uint32_t i, ordered_array_t *array);
#endif
/*****************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/vulcanos *
*****************************************/
#ifndef ORDERED_ARRAY_H
#define ORDERED_ARRAY_H
#include <stdint.h>
/* Our list is always in a 'sorted state',
* it can store anything that can be casted
* to void* */
typedef void* type_t;
/* The following predicate should return non-zero
* if the first argument is less than the second */
typedef uint8_t (*lessthan_predicate_t)(type_t,type_t);
typedef struct {
type_t *array;
uint32_t size;
uint32_t max_size;
lessthan_predicate_t less_than;
} ordered_array_t;
uint8_t standard_lessthan_predicate(type_t a, type_t b);
// Create a new ordered array
ordered_array_t create_ordered_array(uint32_t max_size, lessthan_predicate_t less_than);
ordered_array_t place_ordered_array(void *addr, uint32_t max_size, lessthan_predicate_t less_than);
// Destroy an ordered array
void destroy_ordered_array(ordered_array_t *array);
// Add an item into the array
void insert_ordered_array(type_t item, ordered_array_t *array);
type_t lookup_ordered_array(uint32_t i, ordered_array_t *array);
void remove_ordered_array(uint32_t i, ordered_array_t *array);
#endif

View File

@@ -1,141 +1,141 @@
#include "paging.h"
#include "../libc/string.h"
#include "../libc/panic.h"
#include "../libc/stdio.h"
#include "../drivers/tty.h"
// External definitions from kheap.c
extern uint32_t placement_addr;
extern heap_t *kheap;
// Bitset of frames, used or free
uint32_t *frame_allocations;
uint32_t nframes; // Number of physical frames
page_directory_t *kernel_directory = 0;
page_directory_t *current_directory = 0;
static void set_frame(uint32_t addr) {
uint32_t frame = FRAME(addr);
uint32_t frame_alloc_s = FRAME_SECTION(frame);
uint32_t frame_alloc_o = FRAME_OFFSET(frame);
frame_allocations[frame_alloc_s] |= (1 << frame_alloc_o);
}
static void clear_frame(uint32_t addr) {
uint32_t frame = FRAME(addr);
uint32_t frame_alloc_s = FRAME_SECTION(frame);
uint32_t frame_alloc_o = FRAME_OFFSET(frame);
frame_allocations[frame_alloc_s] &= ~(1 << frame_alloc_o);
}
static uint32_t first_frame() {
uint32_t nsections = nframes / FRAME_ALLOCATIONS_SECTION_SIZE;
for(uint32_t sec = 0; sec < nsections; sec++)
if(frame_allocations[sec] != USED_FRAME_SECTION)
for(uint32_t idx = 0; idx < FRAME_ALLOCATIONS_SECTION_SIZE; idx++)
if(!(frame_allocations[sec] & (0x1 << idx)))
return (sec*FRAME_ALLOCATIONS_SECTION_SIZE) + idx;
return nsections * FRAME_ALLOCATIONS_SECTION_SIZE;
}
void alloc_frame(page_t *page, int32_t is_super, int32_t is_write) {
if(page->fr != 0)
return;
else {
uint32_t fframe = first_frame();
if(fframe == (uint32_t)-1) {
PANIC("No free frames availables!");
} else {
// Set free frames to the page
page->pr = PAGE_PRESENT;
page->rw = (is_write) ? PAGE_READ_WRITE : PAGE_READ_ONLY;
page->us = (is_super) ? PAGE_SUPERVISOR : PAGE_USER;
page->fr = fframe;
// Set new frames as used
uint32_t physical_addr = fframe * FRAME_SIZE;
set_frame(physical_addr);
}
}
}
void free_frame(page_t *page) {
uint32_t frame;
if(!(frame=page->fr))
return; // page doesn't have a frame in first place
else {
clear_frame(frame);
page->fr = 0x0;
}
}
void init_paging() {
// Setup frame allocation
nframes = PHYSICAL_MEM_SIZE / FRAME_SIZE;
frame_allocations = (uint32_t*)kmalloc(nframes/FRAME_ALLOCATIONS_SECTION_SIZE);
memset(frame_allocations, 0, nframes/FRAME_ALLOCATIONS_SECTION_SIZE);
// Setup page directory
kernel_directory = (page_directory_t*)kmalloc_a(sizeof(page_directory_t));
memset(kernel_directory, 0, sizeof(page_directory_t));
current_directory = kernel_directory;
// Map heap pages
for(uint32_t i = KHEAP_START; i < KHEAP_START + KHEAP_INITIAL_SIZE; i += FRAME_SIZE)
get_page(i, 1, kernel_directory);
// Setup identity map
for(uint32_t i = 0; i < placement_addr + FRAME_SIZE; i += FRAME_SIZE)
alloc_frame(get_page(i, 1, kernel_directory), 0, 0);
// Allocate heap pages
for(uint32_t i = KHEAP_START; i < KHEAP_START+KHEAP_INITIAL_SIZE; i += FRAME_SIZE)
alloc_frame(get_page(i, 1, kernel_directory), 0, 0);
// Register a new ISR to listen to IRQ 14
register_interrupt_handler(14, page_fault);
enable_paging(kernel_directory);
kheap = create_heap(KHEAP_START, KHEAP_START+KHEAP_INITIAL_SIZE, 0xCFFFF000, 0, 0);
}
void enable_paging(page_directory_t *dir) {
current_directory = dir;
asm volatile("mov %0, %%cr3" :: "r"(&dir->page_tables_physical));
uint32_t cr0;
asm volatile("mov %%cr0, %0" : "=r"(cr0));
cr0 |= 0x80000000; // Correct code to enable paging
asm volatile("mov %0, %%cr0" :: "r"(cr0));
}
page_t *get_page(uint32_t address, int32_t make, page_directory_t *dir) {
address /= 0x1000; // turn address into an index
uint32_t table_idx = address / 1024; // Find page that contains the address
if(dir->page_tables_virtual[table_idx])
return &dir->page_tables_virtual[table_idx]->pages[address%1024];
else if(make) {
uint32_t tmp;
dir->page_tables_virtual[table_idx] = (page_table_t*)kmalloc_ap(sizeof(page_table_t), &tmp);
memset(dir->page_tables_virtual[table_idx], 0, 0x1000);
dir->page_tables_physical[table_idx] = tmp | 0x7;
return &dir->page_tables_virtual[table_idx]->pages[address%1024];
} else
return 0;
}
void page_fault(registers_t regs) {
// Handle a page fault
uint32_t faulting_addr;
asm volatile("mov %%cr2, %0" : "=r" (faulting_addr));
// Gracefully print the error
kprint((uint8_t*)"\nPage fault! ( ");
if(!(regs.err_code & 0x1))
kprint((uint8_t*)"Present ");
if(regs.err_code & 0x2)
kprint((uint8_t*)"Read-Only ");
if(regs.err_code & 0x4)
kprint((uint8_t*)"User-Mode ");
if(regs.err_code & 0x8)
kprint((uint8_t*)"Reserved");
printf(") at %x\n", faulting_addr);
PANIC("Page fault");
}
#include "paging.h"
#include "../libc/string.h"
#include "../libc/panic.h"
#include "../libc/stdio.h"
#include "../drivers/tty.h"
// External definitions from kheap.c
extern uint32_t placement_addr;
extern heap_t *kheap;
// Bitset of frames, used or free
uint32_t *frame_allocations;
uint32_t nframes; // Number of physical frames
page_directory_t *kernel_directory = 0;
page_directory_t *current_directory = 0;
static void set_frame(uint32_t addr) {
uint32_t frame = FRAME(addr);
uint32_t frame_alloc_s = FRAME_SECTION(frame);
uint32_t frame_alloc_o = FRAME_OFFSET(frame);
frame_allocations[frame_alloc_s] |= (1 << frame_alloc_o);
}
static void clear_frame(uint32_t addr) {
uint32_t frame = FRAME(addr);
uint32_t frame_alloc_s = FRAME_SECTION(frame);
uint32_t frame_alloc_o = FRAME_OFFSET(frame);
frame_allocations[frame_alloc_s] &= ~(1 << frame_alloc_o);
}
static uint32_t first_frame() {
uint32_t nsections = nframes / FRAME_ALLOCATIONS_SECTION_SIZE;
for(uint32_t sec = 0; sec < nsections; sec++)
if(frame_allocations[sec] != USED_FRAME_SECTION)
for(uint32_t idx = 0; idx < FRAME_ALLOCATIONS_SECTION_SIZE; idx++)
if(!(frame_allocations[sec] & (0x1 << idx)))
return (sec*FRAME_ALLOCATIONS_SECTION_SIZE) + idx;
return nsections * FRAME_ALLOCATIONS_SECTION_SIZE;
}
void alloc_frame(page_t *page, int32_t is_super, int32_t is_write) {
if(page->fr != 0)
return;
else {
uint32_t fframe = first_frame();
if(fframe == (uint32_t)-1) {
PANIC("No free frames availables!");
} else {
// Set free frames to the page
page->pr = PAGE_PRESENT;
page->rw = (is_write) ? PAGE_READ_WRITE : PAGE_READ_ONLY;
page->us = (is_super) ? PAGE_SUPERVISOR : PAGE_USER;
page->fr = fframe;
// Set new frames as used
uint32_t physical_addr = fframe * FRAME_SIZE;
set_frame(physical_addr);
}
}
}
void free_frame(page_t *page) {
uint32_t frame;
if(!(frame=page->fr))
return; // page doesn't have a frame in first place
else {
clear_frame(frame);
page->fr = 0x0;
}
}
void init_paging() {
// Setup frame allocation
nframes = PHYSICAL_MEM_SIZE / FRAME_SIZE;
frame_allocations = (uint32_t*)kmalloc(nframes/FRAME_ALLOCATIONS_SECTION_SIZE);
memset(frame_allocations, 0, nframes/FRAME_ALLOCATIONS_SECTION_SIZE);
// Setup page directory
kernel_directory = (page_directory_t*)kmalloc_a(sizeof(page_directory_t));
memset(kernel_directory, 0, sizeof(page_directory_t));
current_directory = kernel_directory;
// Map heap pages
for(uint32_t i = KHEAP_START; i < KHEAP_START + KHEAP_INITIAL_SIZE; i += FRAME_SIZE)
get_page(i, 1, kernel_directory);
// Setup identity map
for(uint32_t i = 0; i < placement_addr + FRAME_SIZE; i += FRAME_SIZE)
alloc_frame(get_page(i, 1, kernel_directory), 0, 0);
// Allocate heap pages
for(uint32_t i = KHEAP_START; i < KHEAP_START+KHEAP_INITIAL_SIZE; i += FRAME_SIZE)
alloc_frame(get_page(i, 1, kernel_directory), 0, 0);
// Register a new ISR to listen to IRQ 14
register_interrupt_handler(14, page_fault);
enable_paging(kernel_directory);
kheap = create_heap(KHEAP_START, KHEAP_START+KHEAP_INITIAL_SIZE, 0xCFFFF000, 0, 0);
}
void enable_paging(page_directory_t *dir) {
current_directory = dir;
asm volatile("mov %0, %%cr3" :: "r"(&dir->page_tables_physical));
uint32_t cr0;
asm volatile("mov %%cr0, %0" : "=r"(cr0));
cr0 |= 0x80000000; // Correct code to enable paging
asm volatile("mov %0, %%cr0" :: "r"(cr0));
}
page_t *get_page(uint32_t address, int32_t make, page_directory_t *dir) {
address /= 0x1000; // turn address into an index
uint32_t table_idx = address / 1024; // Find page that contains the address
if(dir->page_tables_virtual[table_idx])
return &dir->page_tables_virtual[table_idx]->pages[address%1024];
else if(make) {
uint32_t tmp;
dir->page_tables_virtual[table_idx] = (page_table_t*)kmalloc_ap(sizeof(page_table_t), &tmp);
memset(dir->page_tables_virtual[table_idx], 0, 0x1000);
dir->page_tables_physical[table_idx] = tmp | 0x7;
return &dir->page_tables_virtual[table_idx]->pages[address%1024];
} else
return 0;
}
void page_fault(registers_t regs) {
// Handle a page fault
uint32_t faulting_addr;
asm volatile("mov %%cr2, %0" : "=r" (faulting_addr));
// Gracefully print the error
kprint((uint8_t*)"\nPage fault! ( ");
if(!(regs.err_code & 0x1))
kprint((uint8_t*)"Present ");
if(regs.err_code & 0x2)
kprint((uint8_t*)"Read-Only ");
if(regs.err_code & 0x4)
kprint((uint8_t*)"User-Mode ");
if(regs.err_code & 0x8)
kprint((uint8_t*)"Reserved");
printf(") at %x\n", faulting_addr);
PANIC("Page fault");
}

View File

@@ -1,81 +1,81 @@
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#ifndef PAGING_H
#define PAGING_H
#include <stdint.h>
#include "../drivers/isr.h"
#include "kheap.h"
#define FRAME_SIZE 4096
#define PAGE_TABLE_SIZE 1024
#define PAGE_DIRECTORY_SIZE 1024
#define PAGE_NOT_PRESENT 0
#define PAGE_PRESENT 1
#define PAGE_READ_ONLY 0
#define PAGE_READ_WRITE 1
#define PAGE_USER 0
#define PAGE_SUPERVISOR 0
#define PAGE_SIZE_4KB 0
#define PAGE_SIZE_4MB 1
// Frames macros
#define FRAME_ALLOCATIONS_SECTION_SIZE 32
#define USED_FRAME_SECTION 0xFFFFFFFF
#define FREE_FRAME_SECTION 0x00000000
#define FRAME(addr) (addr/FRAME_SIZE)
#define FRAME_SECTION(frame) (frame/FRAME_ALLOCATIONS_SECTION_SIZE)
#define FRAME_OFFSET(frame) (frame%FRAME_ALLOCATIONS_SECTION_SIZE)
// Set physical memory to 15 MiB
#define PHYSICAL_MEM_SIZE 0x10000000
struct page { // Single page structure, from intel's developer manual
uint8_t pr : 1; // Present: 1 to map 4KB page
uint8_t rw : 1; // Read/Write mode
uint8_t us : 1; // if 0, user mode access aren't allowed to the page
uint8_t pw : 1; // Page-level write through
uint8_t pc : 1; // Page-level cache disable
uint8_t ac : 1; // 1 if we have accessed 4kb page
uint8_t di : 1; // 1 if page has been written(dirty)
uint8_t pa : 1; // Unused bit
uint8_t gl : 1; // 1 if page is global
uint8_t ig : 3; // Unused bit
uint32_t fr: 20; // Physical address of frame
} __attribute__((packed));
typedef struct page page_t;
typedef struct page_table {
page_t pages[PAGE_TABLE_SIZE];
} page_table_t;
/* Holds 2 arrays for each page directory
* one holds the physical address, while
* the other one holds the virtual address
* (to write/read to it) */
typedef struct page_directory {
page_table_t *page_tables_virtual[PAGE_DIRECTORY_SIZE];
uint32_t page_tables_physical[PAGE_DIRECTORY_SIZE];
} page_directory_t;
// Setup environment, page directories and enable paging
void init_paging();
// Perform the "enable-paging" operation to the right register
void enable_paging(page_directory_t *dir);
// Retrieve a pointer from the given page
page_t *get_page(uint32_t address, int32_t make, page_directory_t *dir);
// Identity map(phys = virtual addr) to access it as if paging wasn't enabled
void identity_map();
// Delete a frame
void free_frame(page_t *page);
// Allocate a new frame
void alloc_frame(page_t *page, int32_t is_super, int32_t is_write);
// Page faults handler(ISR recorder)
void page_fault(registers_t regs);
#endif
/*****************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/vulcanos *
*****************************************/
#ifndef PAGING_H
#define PAGING_H
#include <stdint.h>
#include "../drivers/isr.h"
#include "kheap.h"
#define FRAME_SIZE 4096
#define PAGE_TABLE_SIZE 1024
#define PAGE_DIRECTORY_SIZE 1024
#define PAGE_NOT_PRESENT 0
#define PAGE_PRESENT 1
#define PAGE_READ_ONLY 0
#define PAGE_READ_WRITE 1
#define PAGE_USER 0
#define PAGE_SUPERVISOR 0
#define PAGE_SIZE_4KB 0
#define PAGE_SIZE_4MB 1
// Frames macros
#define FRAME_ALLOCATIONS_SECTION_SIZE 32
#define USED_FRAME_SECTION 0xFFFFFFFF
#define FREE_FRAME_SECTION 0x00000000
#define FRAME(addr) (addr/FRAME_SIZE)
#define FRAME_SECTION(frame) (frame/FRAME_ALLOCATIONS_SECTION_SIZE)
#define FRAME_OFFSET(frame) (frame%FRAME_ALLOCATIONS_SECTION_SIZE)
// Set physical memory to 15 MiB
#define PHYSICAL_MEM_SIZE 0x10000000
struct page { // Single page structure, from intel's developer manual
uint8_t pr : 1; // Present: 1 to map 4KB page
uint8_t rw : 1; // Read/Write mode
uint8_t us : 1; // if 0, user mode access aren't allowed to the page
uint8_t pw : 1; // Page-level write through
uint8_t pc : 1; // Page-level cache disable
uint8_t ac : 1; // 1 if we have accessed 4kb page
uint8_t di : 1; // 1 if page has been written(dirty)
uint8_t pa : 1; // Unused bit
uint8_t gl : 1; // 1 if page is global
uint8_t ig : 3; // Unused bit
uint32_t fr: 20; // Physical address of frame
} __attribute__((packed));
typedef struct page page_t;
typedef struct page_table {
page_t pages[PAGE_TABLE_SIZE];
} page_table_t;
/* Holds 2 arrays for each page directory
* one holds the physical address, while
* the other one holds the virtual address
* (to write/read to it) */
typedef struct page_directory {
page_table_t *page_tables_virtual[PAGE_DIRECTORY_SIZE];
uint32_t page_tables_physical[PAGE_DIRECTORY_SIZE];
} page_directory_t;
// Setup environment, page directories and enable paging
void init_paging();
// Perform the "enable-paging" operation to the right register
void enable_paging(page_directory_t *dir);
// Retrieve a pointer from the given page
page_t *get_page(uint32_t address, int32_t make, page_directory_t *dir);
// Identity map(phys = virtual addr) to access it as if paging wasn't enabled
void identity_map();
// Delete a frame
void free_frame(page_t *page);
// Allocate a new frame
void alloc_frame(page_t *page, int32_t is_super, int32_t is_write);
// Page faults handler(ISR recorder)
void page_fault(registers_t regs);
#endif