Trying to fix kheap...
This commit is contained in:
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
73
kernel/mem/kheap.h
Normal file
73
kernel/mem/kheap.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/**************************************
|
||||
* iceOS Kernel *
|
||||
* Developed by Marco 'icebit' Cetica *
|
||||
* (c) 2019 *
|
||||
* 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_adddress; // End of allocated space
|
||||
uint32_t max_address; // Maximum size heap ca 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, int 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
|
||||
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
|
||||
Reference in New Issue
Block a user