Trying to fix kheap...
This commit is contained in:
parent
8ff8d71af8
commit
3e0e8043d5
6
Makefile
6
Makefile
@ -1,7 +1,7 @@
|
|||||||
LD = i686-elf-ld
|
LD = i686-elf-ld
|
||||||
LFLAGS = -melf_i386 -nostdlib -O2 -T link.ld
|
LFLAGS = -melf_i386 -nostdlib -O2 -T link.ld
|
||||||
|
|
||||||
all: prepare cpu kernel_code drivers libc shell link iso
|
all: prepare cpu kernel_code drivers libc shell mem link iso
|
||||||
|
|
||||||
prepare:
|
prepare:
|
||||||
mkdir -p obj/
|
mkdir -p obj/
|
||||||
@ -28,6 +28,10 @@ shell:
|
|||||||
make -C kernel/shell
|
make -C kernel/shell
|
||||||
cp kernel/shell/*.o obj/
|
cp kernel/shell/*.o obj/
|
||||||
|
|
||||||
|
mem:
|
||||||
|
make -C kernel/mem
|
||||||
|
cp kernel/mem/*.o obj/
|
||||||
|
|
||||||
link:
|
link:
|
||||||
$(LD) $(LFLAGS) -o isodir/boot/iceOS.bin obj/*.o
|
$(LD) $(LFLAGS) -o isodir/boot/iceOS.bin obj/*.o
|
||||||
|
|
||||||
|
@ -1,14 +1,8 @@
|
|||||||
OBJS = multiboot.asm.o kernel_loader.asm.o ports.asm.o \
|
OBJS = multiboot.asm.o kernel_loader.asm.o ports.asm.o \
|
||||||
gdt.asm.o idt.asm.o interrupts.asm.o assert.o
|
gdt.asm.o idt.asm.o interrupts.asm.o
|
||||||
|
|
||||||
ASM = nasm
|
ASM = nasm
|
||||||
ASMFLAGS = -f elf
|
ASMFLAGS = -f elf
|
||||||
CC = i686-elf-gcc # cross-compiler
|
|
||||||
CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c
|
|
||||||
|
|
||||||
all: $(OBJS)
|
all: $(OBJS)
|
||||||
%.asm.o: %.asm
|
%.asm.o: %.asm
|
||||||
$(ASM) $(ASMFLAGS) $< -o $@
|
$(ASM) $(ASMFLAGS) $< -o $@
|
||||||
|
|
||||||
%.o: %.c
|
|
||||||
$(CC) $(CFLAGS) $< -o $@
|
|
@ -1,5 +1,5 @@
|
|||||||
OBJS = tty.o gdt.o idt.o isr.o timer.o keyboard.o \
|
OBJS = tty.o gdt.o idt.o isr.o timer.o keyboard.o \
|
||||||
fs.o ordered_list.o kheap.o paging.o
|
fs.o
|
||||||
|
|
||||||
CC = i686-elf-gcc # cross-compiler
|
CC = i686-elf-gcc # cross-compiler
|
||||||
CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c
|
CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c
|
||||||
|
@ -1,320 +0,0 @@
|
|||||||
#include "kheap.h"
|
|
||||||
|
|
||||||
// end is declared in the linker script
|
|
||||||
extern uint32_t end;
|
|
||||||
extern page_directory_t *kernel_directory;
|
|
||||||
uint32_t placement_addr = (uint32_t)&end;
|
|
||||||
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->frame*0x1000 + (uint32_t)addr)&0xFFF;
|
|
||||||
}
|
|
||||||
return (uint32_t)addr;
|
|
||||||
} else {
|
|
||||||
if(align == 1 && (placement_addr & 0xFFFFF000)) {
|
|
||||||
// Align
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The following function is a simple method to find the smallest hole that
|
|
||||||
* fit user space request, since we will do this process many times, it's a good
|
|
||||||
* idea to wrap it in a function */
|
|
||||||
static int32_t find_smallest_hole(uint32_t size, uint8_t page_align, heap_t *heap) {
|
|
||||||
uint32_t i = 0;
|
|
||||||
while(i < heap->index.size) {
|
|
||||||
header_t *header = (header_t*)lookup_ordered_list(i, &heap->index);
|
|
||||||
if(page_align > 0) {
|
|
||||||
uint32_t loc = (uint32_t)header;
|
|
||||||
int32_t offset = 0;
|
|
||||||
if(((loc+sizeof(header_t)) & 0xFFFFF000) != 0) // Page aligned memory
|
|
||||||
offset = 0x1000 - (loc+sizeof(header_t))%0x1000;
|
|
||||||
int32_t hole_size = (int32_t)header->size - offset;
|
|
||||||
if(hole_size >= (int32_t)size)
|
|
||||||
break;
|
|
||||||
} else if(header->size >= size)
|
|
||||||
break;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
// Return something according to the iterator
|
|
||||||
if(i == heap->index.size)
|
|
||||||
return -1; // Nothing found
|
|
||||||
else
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int8_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, uint32_t max, uint8_t supervisor, uint8_t readonly) {
|
|
||||||
heap_t *heap = (heap_t*)kmalloc(sizeof(heap_t));
|
|
||||||
|
|
||||||
ASSERT(start%0x1000 == 0);
|
|
||||||
ASSERT(end%0x1000 == 0);
|
|
||||||
|
|
||||||
// Init heap's index
|
|
||||||
heap->index = place_ordered_list((void*)start, HEAP_INDEX_SIZE, &header_t_less_than);
|
|
||||||
|
|
||||||
// Shift start address to the corrent position, where we can put on data
|
|
||||||
start += sizeof(type_t)*HEAP_INDEX_SIZE;
|
|
||||||
|
|
||||||
// Check if start address is page-aligned
|
|
||||||
if((start & 0xFFFFF000) != 0) {
|
|
||||||
start &= 0xFFFFF000;
|
|
||||||
start += 0x1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill the heap structure with start, end and max addresses
|
|
||||||
heap->start_address = start;
|
|
||||||
heap->end_address = end;
|
|
||||||
heap->max_address = max;
|
|
||||||
heap->supervisor = supervisor;
|
|
||||||
heap->readonly = readonly;
|
|
||||||
|
|
||||||
// Let's create one large hole in the new index
|
|
||||||
header_t *hole = (header_t*)start;
|
|
||||||
hole->size = end-start;
|
|
||||||
hole->magic = HEAP_MAGIC;
|
|
||||||
hole->is_hole = 1;
|
|
||||||
insert_ordered_list((void*)hole, &heap->index);
|
|
||||||
|
|
||||||
return heap;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void expand(uint32_t new_size, heap_t *heap) {
|
|
||||||
// Before anything else let's check that new size is greater than older one
|
|
||||||
ASSERT(new_size > heap->end_address - heap->start_address);
|
|
||||||
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 i = old_size;
|
|
||||||
while(i < new_size) {
|
|
||||||
alloc_frame(get_page(heap->start_address+i, 1, kernel_directory),
|
|
||||||
(heap->supervisor)?1:0, (heap->readonly)?0:1);
|
|
||||||
i += 0x1000; // pAge size
|
|
||||||
}
|
|
||||||
heap->end_address = heap->start_address+new_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t contract(uint32_t new_size, heap_t *heap) {
|
|
||||||
// This function will be literally the opposite of the previous one
|
|
||||||
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 i = old_size - 0x1000;
|
|
||||||
while(new_size < i) {
|
|
||||||
free_frame(get_page(heap->start_address+i, 0, kernel_directory));
|
|
||||||
i -= 0x1000;
|
|
||||||
}
|
|
||||||
heap->end_address = heap->start_address + new_size;
|
|
||||||
return new_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *alloc(uint32_t size, uint8_t page_align, heap_t *heap) {
|
|
||||||
uint32_t new_size = size + sizeof(header_t) + sizeof(footer_t);
|
|
||||||
uint32_t i = find_smallest_hole(new_size, page_align, heap);
|
|
||||||
// Error checking for "no hole available"
|
|
||||||
if((int32_t)i == -1) {
|
|
||||||
// Save previous data
|
|
||||||
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;
|
|
||||||
|
|
||||||
i = 0; // Endmost header in location
|
|
||||||
uint32_t idx = -1; // Endmost header's index
|
|
||||||
uint32_t value = 0x0; // Endmost header's value
|
|
||||||
while(i < heap->index.size) {
|
|
||||||
uint32_t tmp = (uint32_t)lookup_ordered_list(i, &heap->index);
|
|
||||||
if(tmp > value) {
|
|
||||||
value = tmp;
|
|
||||||
idx = i;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
// In case we did not find any headers, we need to add 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_list((void*)head, &heap->index);
|
|
||||||
} else {
|
|
||||||
header_t *head = lookup_ordered_list(idx, &heap->index);
|
|
||||||
head->size += new_len - old_len;
|
|
||||||
// Rewrite the footer
|
|
||||||
footer_t *foot = (footer_t*) ((uint32_t)head + head->size - sizeof(footer_t));
|
|
||||||
foot->header = head;
|
|
||||||
foot->magic = HEAP_MAGIC;
|
|
||||||
}
|
|
||||||
// Now that we have enough space, use recursing to call this function again
|
|
||||||
return alloc(size, page_align, heap);
|
|
||||||
}
|
|
||||||
|
|
||||||
header_t *origin_hole_header = (header_t*)lookup_ordered_list(i, &heap->index);
|
|
||||||
uint32_t origin_hole_p = (uint32_t)origin_hole_header;
|
|
||||||
uint32_t origin_hole_s = origin_hole_header->size;
|
|
||||||
// Now check if we should split the hole into two parts
|
|
||||||
if(origin_hole_s-new_size < sizeof(header_t)+sizeof(header_t)) {
|
|
||||||
size += origin_hole_s-new_size;
|
|
||||||
new_size = origin_hole_s;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now check if we need page-aligned data
|
|
||||||
if(page_align && origin_hole_p&0xFFFFF000) {
|
|
||||||
uint32_t new_location = 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_location - sizeof(footer_t));
|
|
||||||
hole_footer->magic = HEAP_MAGIC;
|
|
||||||
hole_footer->header = hole_header;
|
|
||||||
origin_hole_p = new_location;
|
|
||||||
origin_hole_s = origin_hole_s - hole_header->size;
|
|
||||||
} else // Otherwise delete this hole from the index since we don't need it anymore
|
|
||||||
remove_ordered_list(i, &heap->index);
|
|
||||||
|
|
||||||
// Since we're creating a new hole at the old hole's address we can reuse the old hole
|
|
||||||
header_t *block_header = (header_t*)origin_hole_p;
|
|
||||||
block_header->magic = HEAP_MAGIC;
|
|
||||||
block_header->is_hole = 0;
|
|
||||||
block_header->size = new_size;
|
|
||||||
// Now overwrite original footer
|
|
||||||
footer_t *block_footer = (footer_t*)(origin_hole_p + sizeof(header_t) + size);
|
|
||||||
block_footer->magic = HEAP_MAGIC;
|
|
||||||
block_footer->header = block_header;
|
|
||||||
|
|
||||||
// If the new block have positive size, then write a new hole after new 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;
|
|
||||||
}
|
|
||||||
insert_ordered_list((void*)hole_head, &heap->index);
|
|
||||||
}
|
|
||||||
// Finally, return the new hole
|
|
||||||
return (void*)((uint32_t)block_header+sizeof(header_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
void free(void *p, heap_t *heap) {
|
|
||||||
// Exit for null pointer
|
|
||||||
if(p == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Retrieve the header and the footer for this pointer
|
|
||||||
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);
|
|
||||||
|
|
||||||
// Set hole flag
|
|
||||||
head->is_hole = 1;
|
|
||||||
// Add header to free hole's index.
|
|
||||||
int8_t add_to_free_hole = 1;
|
|
||||||
|
|
||||||
// If left-most thing is a footer, then perform left unification
|
|
||||||
footer_t *test_footer = (footer_t*) ((uint32_t)head - sizeof(footer_t));
|
|
||||||
if(test_footer->magic == HEAP_MAGIC &&
|
|
||||||
test_footer->header->is_hole == 1) {
|
|
||||||
uint32_t cache_size = head->size; // Save size
|
|
||||||
head = test_footer->header; // Change header's size with new one
|
|
||||||
foot->header = head; // Update header's pointer
|
|
||||||
head->size += cache_size;
|
|
||||||
add_to_free_hole = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
header_t *test_header = (header_t*) ((uint32_t)foot + sizeof(footer_t));
|
|
||||||
if(test_header->magic == HEAP_MAGIC && test_header->is_hole) {
|
|
||||||
head->size += test_header->size; // Increase size
|
|
||||||
test_footer = (footer_t*) ((uint32_t)test_header + test_header->size - sizeof(footer_t));
|
|
||||||
foot = test_footer;
|
|
||||||
// remove this header from the index
|
|
||||||
uint32_t it = 0;
|
|
||||||
while((it < heap->index.size) && (lookup_ordered_list(it, &heap->index) != (void*)test_header))
|
|
||||||
it++;
|
|
||||||
|
|
||||||
// Check if we found the item
|
|
||||||
ASSERT(it < heap->index.size);
|
|
||||||
// Then remove it
|
|
||||||
remove_ordered_list(it, &heap->index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Contract footer if it is at end address
|
|
||||||
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 header size after resizing
|
|
||||||
if(head->size - (old_len-new_len) > 0) {
|
|
||||||
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 empty holes, this reduce fragmentation
|
|
||||||
uint32_t it = 0;
|
|
||||||
while((it < heap->index.size) && (lookup_ordered_list(it, &heap->index) != (void*)test_header))
|
|
||||||
it++;
|
|
||||||
// If nothing has been found, nothing will be removed
|
|
||||||
if(it < heap->index.size)
|
|
||||||
remove_ordered_list(it, &heap->index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(add_to_free_hole == 1)
|
|
||||||
insert_ordered_list((void*) head, &heap->index);
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
#include "ordered_list.h"
|
|
||||||
#include "kheap.h"
|
|
||||||
#include "../cpu/assert.h"
|
|
||||||
#include "../libc/string.h"
|
|
||||||
|
|
||||||
uint8_t standard_lessthan_predicate(type_t a, type_t b) {
|
|
||||||
if(a < b)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create an ordered list
|
|
||||||
ordered_list_t create_ordered_list(uint32_t max_size, lessthan_predicate_t less_than) {
|
|
||||||
ordered_list_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_then = less_than;
|
|
||||||
return to_ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ordered_list_t place_ordered_list(void *addr, uint32_t max_size, lessthan_predicate_t less_than) {
|
|
||||||
ordered_list_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_then = less_than;
|
|
||||||
return to_ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destroy an ordered list
|
|
||||||
void destroy_ordered_list(ordered_list_t *array) {
|
|
||||||
kfree(array->array);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert item into the array
|
|
||||||
void insert_ordered_list(type_t item, ordered_list_t *array) {
|
|
||||||
ASSERT(array->less_then);
|
|
||||||
uint32_t iterator = 0;
|
|
||||||
while(iterator < array->size && array->less_then(array->array[iterator], item))
|
|
||||||
iterator++;
|
|
||||||
if(iterator == array->size)
|
|
||||||
array->array[array->size++] = item;
|
|
||||||
else {
|
|
||||||
type_t tmp = array->array[iterator];
|
|
||||||
array->array[iterator] = item;
|
|
||||||
while(iterator < array->size) {
|
|
||||||
iterator++;
|
|
||||||
type_t tmp2 = array->array[iterator];
|
|
||||||
array->array[iterator] = tmp;
|
|
||||||
tmp = tmp2;
|
|
||||||
}
|
|
||||||
array->size++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find item at given index
|
|
||||||
type_t lookup_ordered_list(uint32_t i, ordered_list_t *array) {
|
|
||||||
ASSERT(i < array->size);
|
|
||||||
return array->array[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete item from the array
|
|
||||||
void remove_ordered_list(uint32_t i, ordered_list_t *array) {
|
|
||||||
while(i < array->size) {
|
|
||||||
array->array[i] = array->array[i+1];
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
array->size--;
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
/**************************************
|
|
||||||
* iceOS Kernel *
|
|
||||||
* Developed by Marco 'icebit' Cetica *
|
|
||||||
* (c) 2019 *
|
|
||||||
* Released under GPLv3 *
|
|
||||||
* https://github.com/ice-bit/iceOS *
|
|
||||||
***************************************/
|
|
||||||
#ifndef ORDERED_LIST_H
|
|
||||||
#define ORDERED_LIST_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 int8_t (*lessthan_predicate_t)(type_t, type_t);
|
|
||||||
typedef struct {
|
|
||||||
type_t *array;
|
|
||||||
uint32_t size;
|
|
||||||
uint32_t max_size;
|
|
||||||
lessthan_predicate_t less_then;
|
|
||||||
} ordered_list_t;
|
|
||||||
uint8_t standard_lessthan_predicate(type_t a, type_t b);
|
|
||||||
|
|
||||||
// Create an ordered list
|
|
||||||
ordered_list_t create_ordered_list(uint32_t max_size, lessthan_predicate_t less_than);
|
|
||||||
ordered_list_t place_ordered_list(void *addr, uint32_t max_size, lessthan_predicate_t less_than);
|
|
||||||
// Destroy an ordered list
|
|
||||||
void destroy_ordered_list(ordered_list_t *array);
|
|
||||||
// Insert item into the array
|
|
||||||
void insert_ordered_list(type_t item, ordered_list_t *array);
|
|
||||||
// Find item at given index
|
|
||||||
type_t lookup_ordered_list(uint32_t i, ordered_list_t *array);
|
|
||||||
// Delete item from the array
|
|
||||||
void remove_ordered_list(uint32_t i, ordered_list_t *array);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,168 +0,0 @@
|
|||||||
#include "paging.h"
|
|
||||||
#include "kheap.h"
|
|
||||||
#include "../libc/string.h"
|
|
||||||
|
|
||||||
// Macros for bitset algorithms
|
|
||||||
#define INDEX_FROM_BIT(a) (a/(8*4))
|
|
||||||
#define OFFSET_FROM_BIT(a) (a%(8*4))
|
|
||||||
|
|
||||||
// Kernel's page directory
|
|
||||||
page_directory_t *kernel_directory = 0;
|
|
||||||
// Current page directory
|
|
||||||
page_directory_t *current_directory = 0;
|
|
||||||
|
|
||||||
// Bitset of frames, used or free
|
|
||||||
uint32_t *frames;
|
|
||||||
uint32_t nframes;
|
|
||||||
|
|
||||||
// From kheap.c
|
|
||||||
extern uint32_t placement_addr;
|
|
||||||
extern heap_t *kheap;
|
|
||||||
|
|
||||||
// Set a bit in the frame bitset
|
|
||||||
static void set_frame(uint32_t frame_addr) {
|
|
||||||
uint32_t frame = frame_addr / 0x1000;
|
|
||||||
uint32_t idx = INDEX_FROM_BIT(frame);
|
|
||||||
uint32_t off = OFFSET_FROM_BIT(frame);
|
|
||||||
frames[idx] |= (0x1 << off);
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear a bit in the frame bitset
|
|
||||||
static void clear_frame(uint32_t frame_addr) {
|
|
||||||
uint32_t frame = frame_addr / 0x1000;
|
|
||||||
uint32_t idx = INDEX_FROM_BIT(frame);
|
|
||||||
uint32_t off = OFFSET_FROM_BIT(frame);
|
|
||||||
frames[idx] &= ~(0x1 << off);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the first free frames
|
|
||||||
static uint32_t first_frame() {
|
|
||||||
uint32_t nsections = nframes / FRAME_ALLOCATION_SECTION_SIZE;
|
|
||||||
for(uint32_t section = 0; section < INDEX_FROM_BIT(nframes); section++)
|
|
||||||
if(frames[section] != 0xFFFFFFFF) // If nothing is free, exit
|
|
||||||
for(uint32_t idx = 0; idx < FRAME_ALLOCATION_SECTION_SIZE; idx++)
|
|
||||||
if (!(frames[idx] & (0x1 << idx)))
|
|
||||||
return (section * FRAME_ALLOCATION_SECTION_SIZE) + idx;
|
|
||||||
return nsections * FRAME_ALLOCATION_SECTION_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void alloc_frame(page_t *page, int32_t is_supervisored, int32_t is_writeable) {
|
|
||||||
if(page->frame != 0)
|
|
||||||
return; // Frame already allocated
|
|
||||||
else {
|
|
||||||
uint32_t free_frame = first_frame();
|
|
||||||
if(free_frame == (uint32_t)-1) {
|
|
||||||
PANIC("No free frames found!");
|
|
||||||
} else {
|
|
||||||
// Set free frames to page
|
|
||||||
page->present = PAGE_PRESENT;
|
|
||||||
page->rw = (is_writeable) ? PAGE_READ_WRITE : PAGE_READ_ONLY;
|
|
||||||
page->user = (is_supervisored) ? PAGE_SUPERVISOR : PAGE_USER;
|
|
||||||
page->frame = free_frame;
|
|
||||||
|
|
||||||
// Set new frames as used
|
|
||||||
uint32_t physical_address = free_frame * FRAME_SIZE;
|
|
||||||
set_frame(physical_address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_frame(page_t *page) {
|
|
||||||
uint32_t frame;
|
|
||||||
if(!(frame=page->frame))
|
|
||||||
return;
|
|
||||||
else {
|
|
||||||
clear_frame(frame);
|
|
||||||
page->frame = 0x0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void init_paging() {
|
|
||||||
uint32_t nframes = PHYSICAL_MEMORY_SIZE / FRAME_SIZE;
|
|
||||||
frames = (uint32_t*)kmalloc(INDEX_FROM_BIT(nframes));
|
|
||||||
|
|
||||||
// Create a page directory
|
|
||||||
kernel_directory = (page_directory_t*)kmalloc_a(sizeof(page_directory_t));
|
|
||||||
memset(frames, 0, INDEX_FROM_BIT(nframes));
|
|
||||||
current_directory = kernel_directory;
|
|
||||||
|
|
||||||
/* Map pages in the kernel heap area.
|
|
||||||
* We only call get_page and not alloc_frame to create a new page_table_t
|
|
||||||
* only where necessary.*/
|
|
||||||
for(int32_t i = KHEAP_START; i < (int32_t)KHEAP_START+KHEAP_INITIAL_SIZE; i += 0x1000)
|
|
||||||
get_page(i, 1, kernel_directory);
|
|
||||||
|
|
||||||
/* We have eto identify map from 0x0 to the end of the use memory
|
|
||||||
* so we can use this memory region as if paging was not enabled. */
|
|
||||||
int32_t i = 0;
|
|
||||||
while(i < (int32_t)placement_addr+0x1000) {
|
|
||||||
// Kernel code is read only from userspace
|
|
||||||
alloc_frame(get_page(i, 1, kernel_directory), 0, 0);
|
|
||||||
i += 0x1000;
|
|
||||||
}
|
|
||||||
// Perform the real allocation of what we have done so far
|
|
||||||
for(i = KHEAP_START; i < (int32_t)KHEAP_START+KHEAP_INITIAL_SIZE; i += 0x1000)
|
|
||||||
alloc_frame(get_page(i, 1, kernel_directory), 0, 0);
|
|
||||||
|
|
||||||
// Register a new ISR to handle page faults
|
|
||||||
register_interrupt_handler(14, page_fault);
|
|
||||||
|
|
||||||
// Enable paging
|
|
||||||
enable_paging(kernel_directory);
|
|
||||||
|
|
||||||
// Set up kernel heap
|
|
||||||
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_table_physical));
|
|
||||||
uint32_t cr0;
|
|
||||||
asm volatile("mov %%cr0, %0": "=r"(cr0));
|
|
||||||
cr0 |= 0x80000000; // 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) {
|
|
||||||
// Turn address into an index
|
|
||||||
address /= 0x1000;
|
|
||||||
// Find page table that contains this index
|
|
||||||
uint32_t table_idx = address / 1024;
|
|
||||||
if(dir->page_table_virtual[table_idx]) // If current table is already assigned
|
|
||||||
return &dir->page_table_virtual[table_idx]->pages[address%1024];
|
|
||||||
else if(make) {
|
|
||||||
uint32_t tmp;
|
|
||||||
dir->page_table_virtual[table_idx] = (page_table_t*)kmalloc_p(sizeof(page_table_t), &tmp);
|
|
||||||
memset(dir->page_table_virtual[table_idx], 0, 0x1000);
|
|
||||||
dir->page_table_physical[table_idx] = tmp | 0x7;
|
|
||||||
return &dir->page_table_virtual[table_idx]->pages[address%1024];
|
|
||||||
} else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void page_fault(registers_t regs) {
|
|
||||||
// Retrieve faulted address from CR2 register
|
|
||||||
uint32_t fault_addr;
|
|
||||||
asm volatile("mov %%cr2, %0" : "=r"(fault_addr));
|
|
||||||
|
|
||||||
// Retrieve other infos about the error
|
|
||||||
int32_t present = !(regs.err_code & 0x1); // Page not present
|
|
||||||
int32_t rw = regs.err_code & 0x2; // Write operation
|
|
||||||
int32_t us = regs.err_code & 0x4; // CPU mode(kernel or user mode)
|
|
||||||
int32_t reserved = regs.err_code & 0x8;
|
|
||||||
|
|
||||||
// Output of those informations
|
|
||||||
kprint((uint8_t*)"Page fault! ( ");
|
|
||||||
if(present)
|
|
||||||
kprint((uint8_t*)"present ");
|
|
||||||
if(rw)
|
|
||||||
kprint((uint8_t*)"read-only");
|
|
||||||
if(us)
|
|
||||||
kprint((uint8_t*)"user-mode");
|
|
||||||
if(reserved)
|
|
||||||
kprint((uint8_t*)"reserved");
|
|
||||||
kprint((uint8_t*)") at 0x");
|
|
||||||
kprint_hex(fault_addr);
|
|
||||||
kprint((uint8_t*)"\n");
|
|
||||||
PANIC("Page fault");
|
|
||||||
}
|
|
@ -1,68 +0,0 @@
|
|||||||
#ifndef PAGING_H
|
|
||||||
#define PAGING_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "isr.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
|
|
||||||
#define FRAME_ALLOCATION_SECTION_SIZE 32
|
|
||||||
#define USED_FRAME_ALLOCATIONS_SECTION 0xFFFFFFFF
|
|
||||||
#define FREE_FRAME_ALLOCATIONS_SECTION 0x00000000
|
|
||||||
|
|
||||||
// Reserve 16 MiB of physical memory
|
|
||||||
#define PHYSICAL_MEMORY_SIZE 0x10000000
|
|
||||||
|
|
||||||
struct page { // Page structure from Intel's developer manual
|
|
||||||
uint8_t present : 1;
|
|
||||||
uint8_t rw : 1;
|
|
||||||
uint8_t user : 1;
|
|
||||||
uint8_t pwt : 1;
|
|
||||||
uint8_t pcd : 1;
|
|
||||||
uint8_t a : 1;
|
|
||||||
uint8_t d : 1;
|
|
||||||
uint8_t pat : 1;
|
|
||||||
uint8_t g : 1;
|
|
||||||
uint8_t unused : 3;
|
|
||||||
uint32_t frame : 20;
|
|
||||||
} __attribute__((packed));
|
|
||||||
typedef struct page page_t;
|
|
||||||
|
|
||||||
struct page_table {
|
|
||||||
page_t pages[PAGE_TABLE_SIZE];
|
|
||||||
};
|
|
||||||
typedef struct page_table page_table_t;
|
|
||||||
|
|
||||||
/* For each page we hold two arrays:
|
|
||||||
* one is used by the CPU to hold the physical address
|
|
||||||
* the other is used to hold the virtual address to actual read
|
|
||||||
* or write to it. */
|
|
||||||
struct page_directory {
|
|
||||||
page_table_t *page_table_virtual[PAGE_DIRECTORY_SIZE];
|
|
||||||
uint32_t page_table_physical[PAGE_DIRECTORY_SIZE];
|
|
||||||
};
|
|
||||||
typedef struct page_directory page_directory_t;
|
|
||||||
|
|
||||||
// Setup the environment
|
|
||||||
void init_paging();
|
|
||||||
// Load specified page directory into CR3 register
|
|
||||||
void enable_paging(page_directory_t *new);
|
|
||||||
// Retrieve pointer to specified page address
|
|
||||||
page_t *get_page(uint32_t addr, int32_t make, page_directory_t *dir);
|
|
||||||
// Handle page faults
|
|
||||||
void page_fault(registers_t regs);
|
|
||||||
// Allocate a new frame
|
|
||||||
void alloc_frame(page_t *page, int32_t is_supervisored, int32_t is_writeable);
|
|
||||||
// Deallocate frame
|
|
||||||
void free_frame(page_t *page);
|
|
||||||
|
|
||||||
#endif
|
|
@ -10,8 +10,6 @@
|
|||||||
#include "drivers/idt.h"
|
#include "drivers/idt.h"
|
||||||
#include "drivers/timer.h"
|
#include "drivers/timer.h"
|
||||||
#include "drivers/keyboard.h"
|
#include "drivers/keyboard.h"
|
||||||
#include "drivers/paging.h"
|
|
||||||
#include "drivers/kheap.h"
|
|
||||||
#include "shell/shell.h"
|
#include "shell/shell.h"
|
||||||
#include "libc/stdio.h"
|
#include "libc/stdio.h"
|
||||||
|
|
||||||
@ -37,7 +35,7 @@ void kernel_main() {
|
|||||||
printf_color("\n[INFO]", LIGHT_CYAN, BLACK);
|
printf_color("\n[INFO]", LIGHT_CYAN, BLACK);
|
||||||
printf_color(" - Loaded PS/2 driver", WHITE, BLACK);
|
printf_color(" - Loaded PS/2 driver", WHITE, BLACK);
|
||||||
|
|
||||||
printf_color("\n[TEST]", LIGHT_BROWN, BLACK); // Testing heap
|
/* printf_color("\n[TEST]", LIGHT_BROWN, BLACK); // Testing heap
|
||||||
printf_color(" - Allocating heap blocks..\n", LIGHT_BROWN, BLACK);
|
printf_color(" - Allocating heap blocks..\n", LIGHT_BROWN, BLACK);
|
||||||
|
|
||||||
uint32_t x = kmalloc(8), y = kmalloc(16), z = kmalloc(32);
|
uint32_t x = kmalloc(8), y = kmalloc(16), z = kmalloc(32);
|
||||||
@ -48,7 +46,7 @@ void kernel_main() {
|
|||||||
kfree((void*)x), kfree((void*)y), kfree((void*)z);
|
kfree((void*)x), kfree((void*)y), kfree((void*)z);
|
||||||
|
|
||||||
printf_color("\n[STATUS]", LIGHT_GREEN, BLACK);
|
printf_color("\n[STATUS]", LIGHT_GREEN, BLACK);
|
||||||
printf_color(" - Heap worked successfullt!", WHITE, BLACK);
|
printf_color(" - Heap worked successfullt!", WHITE, BLACK); */
|
||||||
|
|
||||||
iceos_ascii_logo();
|
iceos_ascii_logo();
|
||||||
init_prompt(); // Initialize frame buffer
|
init_prompt(); // Initialize frame buffer
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
OBJS = stdio.o string.o
|
OBJS = stdio.o string.o assert.o
|
||||||
|
|
||||||
CC = i686-elf-gcc # cross-compiler
|
CC = i686-elf-gcc # cross-compiler
|
||||||
CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c
|
CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c
|
||||||
|
9
kernel/mem/Makefile
Normal file
9
kernel/mem/Makefile
Normal file
@ -0,0 +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
|
||||||
|
${CC} ${CFLAGS} $< -o $@
|
0
kernel/mem/kheap.c
Normal file
0
kernel/mem/kheap.c
Normal file
@ -10,7 +10,6 @@
|
|||||||
/*** Heap implementation from James Molloy's tutorial:
|
/*** Heap implementation from James Molloy's tutorial:
|
||||||
http://www.jamesmolloy.co.uk/tutorial_html/7.-The%20Heap.html ***/
|
http://www.jamesmolloy.co.uk/tutorial_html/7.-The%20Heap.html ***/
|
||||||
|
|
||||||
|
|
||||||
/* This heap algorithm uses two different data structures: blocks and holes.
|
/* This heap algorithm uses two different data structures: blocks and holes.
|
||||||
* Blocks: Contiguous areas of memory containing user data
|
* Blocks: Contiguous areas of memory containing user data
|
||||||
* Holes: Special kind of blocks that are not in use, this is the result
|
* Holes: Special kind of blocks that are not in use, this is the result
|
||||||
@ -25,48 +24,50 @@
|
|||||||
#ifndef KHEAP_H
|
#ifndef KHEAP_H
|
||||||
#define KHEAP_H
|
#define KHEAP_H
|
||||||
|
|
||||||
#define KHEAP_START 0xC0000000 // starting location can be different
|
#define KHEAP_START 0xC0000000
|
||||||
#define KHEAP_INITIAL_SIZE 0x100000
|
#define KHEAP_INITIAL_SIZE 0x100000
|
||||||
|
|
||||||
#define HEAP_INDEX_SIZE 0x20000
|
#define HEAP_INDEX_SIZE 0x20000
|
||||||
#define HEAP_MAGIC 0x123890AB
|
#define HEAP_MAGIC 0x123890AB
|
||||||
#define HEAP_MIN_SIZE 0x70000
|
#define HEAP_MIN_SIZE 0x70000
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "../cpu/assert.h"
|
#include "ordered_array.h"
|
||||||
#include "ordered_list.h"
|
|
||||||
#include "paging.h"
|
|
||||||
|
|
||||||
// Data structure for single block/hole
|
// Data structure for single hole/block
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t magic; // Magic number for error checking
|
uint32_t magic; // Magic number for error checking
|
||||||
uint8_t is_hole; // 1 if its an hole, 0 for a block
|
uint8_t is_hole; // 1 if it's an hole, 0 for a block
|
||||||
uint32_t size; // Size of the block
|
uint32_t size; // Size of block
|
||||||
} header_t;
|
} header_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t magic;
|
uint32_t magic; // Same as above
|
||||||
header_t *header; // Pointer to the head
|
header_t *header; // Pointer to the header block
|
||||||
} footer_t;
|
} footer_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ordered_list_t index;
|
ordered_array_t index;
|
||||||
uint32_t start_address; // Start of allocated space
|
uint32_t start_address; // Begin of allocated space
|
||||||
uint32_t end_address; // End of allocated space
|
uint32_t end_adddress; // End of allocated space
|
||||||
uint32_t max_address; // Maximum size, heap can be expanded to
|
uint32_t max_address; // Maximum size heap ca be expanded to
|
||||||
uint8_t supervisor;
|
uint8_t supervisor;
|
||||||
uint8_t readonly;
|
uint8_t readonly;
|
||||||
} heap_t;
|
} heap_t;
|
||||||
|
|
||||||
// Heap functions
|
// Create a new heap
|
||||||
heap_t *create_heap(uint32_t start, uint32_t end, uint32_t max, uint8_t supervisor, uint8_t readonly);
|
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);
|
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);
|
void free(void *p, heap_t *heap);
|
||||||
// Public heap functions
|
uint32_t kmalloc_int(uint32_t sz, int align, uint32_t *phys);
|
||||||
uint32_t kmalloc_int(uint32_t sz, int32_t align, uint32_t *phys);
|
|
||||||
void kfree(void *p);
|
|
||||||
uint32_t kmalloc_a(uint32_t sz);
|
uint32_t kmalloc_a(uint32_t sz);
|
||||||
uint32_t kmalloc_p(uint32_t sz, uint32_t *phys);
|
uint32_t kmalloc_p(uint32_t sz, uint32_t *phys);
|
||||||
uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys);
|
uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys);
|
||||||
uint32_t kmalloc(uint32_t sz);
|
uint32_t kmalloc(uint32_t sz);
|
||||||
|
void kfree(void *p);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
66
kernel/mem/ordered_array.c
Normal file
66
kernel/mem/ordered_array.c
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#include "ordered_array.h"
|
||||||
|
#include "kheap.h"
|
||||||
|
#include "../libc/assert.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], it));
|
||||||
|
it++;
|
||||||
|
if(it == array->size)
|
||||||
|
array->array[array->size++] = item;
|
||||||
|
else {
|
||||||
|
type_t tmp = array->array[it];
|
||||||
|
array->array[it] = it;
|
||||||
|
while(it < array->size) {
|
||||||
|
it++;
|
||||||
|
type_t tmp = 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--;
|
||||||
|
}
|
39
kernel/mem/ordered_array.h
Normal file
39
kernel/mem/ordered_array.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/**************************************
|
||||||
|
* iceOS Kernel *
|
||||||
|
* Developed by Marco 'icebit' Cetica *
|
||||||
|
* (c) 2019 *
|
||||||
|
* 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
|
159
kernel/mem/paging.c
Normal file
159
kernel/mem/paging.c
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
#include "paging.h"
|
||||||
|
#include "../libc/string.h"
|
||||||
|
#include "../libc/assert.h"
|
||||||
|
#include "../drivers/tty.h"
|
||||||
|
// #include "kheap.h" FIXME:
|
||||||
|
|
||||||
|
// External definitions from kheap.c
|
||||||
|
extern uint32_t placement_addr;
|
||||||
|
extern heap_t *kheap;
|
||||||
|
|
||||||
|
void map_heap_pages();
|
||||||
|
void setup_frame_allocations();
|
||||||
|
void setup_page_directory();
|
||||||
|
void alloc_heap_pages();
|
||||||
|
|
||||||
|
// 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 = free_frame;
|
||||||
|
// 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_allocations();
|
||||||
|
setup_page_directory();
|
||||||
|
map_heap_pages();
|
||||||
|
identity_map();
|
||||||
|
alloc_heap_pages();
|
||||||
|
|
||||||
|
// 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 map_heap_pages() {
|
||||||
|
for(uint32_t i = KHEAP_START; i < KHEAP_START + KHEAP_INITIAL_SIZE; i != FRAME_SIZE)
|
||||||
|
get_page(i, 1, kernel_directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_frame_allocations() {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void alloc_heap_pages() {
|
||||||
|
for(uint32_t i = KHEAP_START; i < KHEAP_START+KHEAP_INITIAL_SIZE; i += FRAME_SIZE)
|
||||||
|
alloca_frame(get_page(i, 1, kernel_directory), 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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, %d" : "=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_sp(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*)"Page 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");
|
||||||
|
kprint((uint8_t*)") at 0x");
|
||||||
|
kprint_hex(faulting_addr);
|
||||||
|
kprint((uint8_t*)"\n");
|
||||||
|
PANIC("Page fault");
|
||||||
|
}
|
80
kernel/mem/paging.h
Normal file
80
kernel/mem/paging.h
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/**************************************
|
||||||
|
* iceOS Kernel *
|
||||||
|
* Developed by Marco 'icebit' Cetica *
|
||||||
|
* (c) 2019 *
|
||||||
|
* Released under GPLv3 *
|
||||||
|
* https://github.com/ice-bit/iceOS *
|
||||||
|
***************************************/
|
||||||
|
#ifndef PAGING_H
|
||||||
|
#define PAGING_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "../drivers/isr.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
|
Loading…
Reference in New Issue
Block a user