summaryrefslogtreecommitdiff
path: root/src/kernel/mem
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/mem')
-rw-r--r--src/kernel/mem/gdt.c18
-rw-r--r--src/kernel/mem/gdt.h9
-rw-r--r--src/kernel/mem/heap.c7
-rw-r--r--src/kernel/mem/heap.h5
-rw-r--r--src/kernel/mem/mem.c4
-rw-r--r--src/kernel/mem/mem.h3
-rw-r--r--src/kernel/mem/paging.c27
-rw-r--r--src/kernel/mem/seg.c20
-rw-r--r--src/kernel/mem/seg.h13
9 files changed, 92 insertions, 14 deletions
diff --git a/src/kernel/mem/gdt.c b/src/kernel/mem/gdt.c
index e9a1be5..8ee403a 100644
--- a/src/kernel/mem/gdt.c
+++ b/src/kernel/mem/gdt.c
@@ -2,19 +2,23 @@
#include <stdlib.h>
#include <core/monitor.h>
-extern void gdt_flush(uint32_t); //ASM (idt_.asm)
+extern void gdt_flush(uint32_t); //ASM (imported from idt_.asm)
extern void tss_flush();
-#define GDT_ENTRIES 6
+#define GDT_ENTRIES 6 // The contents of each entry is defined in gdt_init.
static struct tss_entry tss_entry;
static struct gdt_entry gdt_entries[GDT_ENTRIES];
static struct gdt_ptr gdt_ptr;
+/* This function is called by the task_switch function on each context switch.
+ It updates the TSS so that an interrupt will be handled on the correct kernel stack
+ (one kernel stack is allocated to each thread). */
void gdt_setKernelStack(uint32_t esp0) {
tss_entry.esp0 = esp0;
}
+/* For internal use only. Writes one entry of the GDT with given parameters. */
static void gdt_setGate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) {
gdt_entries[num].base_low = (base & 0xFFFF);
gdt_entries[num].base_middle = (base >> 16) & 0xFF;
@@ -26,6 +30,7 @@ static void gdt_setGate(int num, uint32_t base, uint32_t limit, uint8_t access,
gdt_entries[num].access = access;
}
+/* For internal use only. Writes one entry of the GDT, that entry being a pointer to the TSS. */
static void gdt_writeTss(int num, uint32_t ss0, uint32_t esp0) {
uint32_t base = (uint32_t)&tss_entry;
uint32_t limit = base + sizeof(struct tss_entry);
@@ -40,15 +45,16 @@ static void gdt_writeTss(int num, uint32_t ss0, uint32_t esp0) {
tss_entry.ss = tss_entry.ds = tss_entry.es = tss_entry.fs = tss_entry.gs = 0x13;
}
+/* Write data to the GDT and enable it. */
void gdt_init() {
gdt_ptr.limit = (sizeof(struct gdt_entry) * GDT_ENTRIES) - 1;
gdt_ptr.base = (uint32_t)&gdt_entries;
gdt_setGate(0, 0, 0, 0, 0); //Null segment
- gdt_setGate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); //Kernel code segment
- gdt_setGate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); //Kernel data segment
- gdt_setGate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); //User code segment
- gdt_setGate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); //User data segment
+ gdt_setGate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); //Kernel code segment 0x08
+ gdt_setGate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); //Kernel data segment 0x10
+ gdt_setGate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); //User code segment 0x18
+ gdt_setGate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); //User data segment 0x20
gdt_writeTss(5, 0x10, 0);
gdt_flush((uint32_t)&gdt_ptr);
diff --git a/src/kernel/mem/gdt.h b/src/kernel/mem/gdt.h
index 485002b..1b33dac 100644
--- a/src/kernel/mem/gdt.h
+++ b/src/kernel/mem/gdt.h
@@ -3,6 +3,11 @@
#include <types.h>
+/* The GDT is one of the x86's descriptor tables. It is used for memory segmentation.
+ Here, we don't use segmentation to separate processes from one another (this is done with paging).
+ We only use segmentation to make the difference between kernel mode (ring 3) and user mode (ring 0) */
+
+/* One entry of the table */
struct gdt_entry {
uint16_t limit_low;
uint16_t base_low;
@@ -12,11 +17,15 @@ struct gdt_entry {
uint8_t base_high;
} __attribute__((packed));
+/* Structure defining the whole table : address and size (in bytes). */
struct gdt_ptr {
uint16_t limit;
uint32_t base;
} __attribute__((packed));
+/* The TSS is used for hardware multitasking.
+ We don't use that, but we still need a TSS so that user mode process exceptions
+ can be handled correctly by the kernel. */
struct tss_entry {
uint32_t prev_tss; // The previous TSS - if we used hardware task switching this would form a linked list.
uint32_t esp0; // The stack pointer to load when we change to kernel mode.
diff --git a/src/kernel/mem/heap.c b/src/kernel/mem/heap.c
index b6d2cd4..b7f6c97 100644
--- a/src/kernel/mem/heap.c
+++ b/src/kernel/mem/heap.c
@@ -6,6 +6,7 @@
/* ******************* HEADER ****************** */
+/* For internal use only. Inserts a hole in the heap's hole index at the correct position. */
static void heapIdx_insert(struct heap *heap, struct heap_header *e) {
if ((heap->idxused + sizeof(struct heap_header*) + (size_t)heap->idx) >= heap->start_addr) return;
@@ -28,6 +29,7 @@ static void heapIdx_insert(struct heap *heap, struct heap_header *e) {
}
}
+/* For internal use only. Removes a hole from the heap's hole index. */
static void heapIdx_remove(struct heap *heap, struct heap_header *e) {
uint32_t iterator;
for (iterator = 0; iterator < heap->idxused; iterator++) {
@@ -43,6 +45,7 @@ static void heapIdx_remove(struct heap *heap, struct heap_header *e) {
/* ******************** CONTENTS ********************* */
+/* Initializes the heap, creates the correct data structures. */
void heap_create(struct heap *heap, size_t start, size_t idxsize, size_t datasize, size_t maxdatasize) {
uint32_t i;
@@ -71,6 +74,7 @@ void heap_create(struct heap *heap, size_t start, size_t idxsize, size_t datasiz
heapIdx_insert(heap, hole);
}
+/* For internal use only. Called by heap_alloc when necessary. Expands the heap to take more space. */
static uint32_t heap_expand(struct heap *heap, size_t quantity) {
uint32_t i;
@@ -116,6 +120,7 @@ static uint32_t heap_expand(struct heap *heap, size_t quantity) {
return 1;
}
+/* For internal use only. Called by heap_free when necessary. Reduces the heap's size. */
static void heap_contract(struct heap *heap) {
struct heap_footer *last_footer = (struct heap_footer*)(heap->end_addr - sizeof(struct heap_footer));
struct heap_header *last_header = last_footer->header;
@@ -142,6 +147,7 @@ static void heap_contract(struct heap *heap) {
}
}
+/* Alocate some bytes on the heap. */
void* heap_alloc(struct heap *heap, size_t sz) {
size_t newsize = sz + sizeof(struct heap_header) + sizeof(struct heap_footer);
uint32_t iterator = 0;
@@ -185,6 +191,7 @@ void* heap_alloc(struct heap *heap, size_t sz) {
return (void*)((size_t)loc + sizeof(struct heap_header));
}
+/* Frees a block previously allocated on the heap. */
void heap_free(struct heap *heap, void* ptr) {
if (ptr == 0) return;
if ((size_t)ptr < heap->start_addr || (size_t)ptr > heap->end_addr) return;
diff --git a/src/kernel/mem/heap.h b/src/kernel/mem/heap.h
index 39ba37e..8f8cdcf 100644
--- a/src/kernel/mem/heap.h
+++ b/src/kernel/mem/heap.h
@@ -1,6 +1,11 @@
#ifndef DEF_HEAP_H
#define DEF_HEAP_H
+/* The heap is the data structure that permits allocating and freeing memory easily.
+ The functions in this file are only used by mem.c, which provides kmalloc and kfree.
+ The heap algorithm used is the one described here :
+ http://www.jamesmolloy.co.uk/tutorial_html/7.-The%20Heap.html */
+
#include "types.h"
struct heap_header {
diff --git a/src/kernel/mem/mem.c b/src/kernel/mem/mem.c
index 06242a5..47a03dc 100644
--- a/src/kernel/mem/mem.c
+++ b/src/kernel/mem/mem.c
@@ -22,6 +22,7 @@ static struct freepage {
} freepages[FREEPAGESTOKEEP];
uint32_t freepagecount = 0;
+/* For internal use only. Populates the cache of pages that can be given to requesters. */
static void get_free_pages() {
static uint32_t locked = 0;
uint32_t i;
@@ -49,6 +50,7 @@ static void get_free_pages() {
locked = 0;
}
+/* Gives one page from the cache to someone requesting it. */
void* kmalloc_page(size_t *phys) {
cli();
get_free_pages();
@@ -72,12 +74,14 @@ void kfree_page(void* ptr) {
static struct heap kheap;
+/* Called on kernel start. Creates the kernel heap. */
void kheap_init() {
heap_create(&kheap, (mem_placementAddr & 0xFFFFF000) + 0x1000, KHEAP_IDXSIZE, KHEAP_INITSIZE, KHEAP_MAXSIZE);
kheap_working = 1;
monitor_write("[KHeap] ");
}
+/* Allocates on the heap if possible. If not possible, allocates just after the kernel code. */
void* kmalloc(size_t size) {
if (kheap_working) {
return heap_alloc(&kheap, size);
diff --git a/src/kernel/mem/mem.h b/src/kernel/mem/mem.h
index 5417d5f..b372fae 100644
--- a/src/kernel/mem/mem.h
+++ b/src/kernel/mem/mem.h
@@ -1,6 +1,9 @@
#ifndef DEF_MEM_H
#define DEF_MEM_H
+/* mem.c provides the kernel's allocation and freeing functions.
+ kmalloc_page and kfree_page are used mostly for paging. */
+
#include <types.h>
void* kmalloc_page(size_t *phys);
diff --git a/src/kernel/mem/paging.c b/src/kernel/mem/paging.c
index 4992d5e..f8f69f1 100644
--- a/src/kernel/mem/paging.c
+++ b/src/kernel/mem/paging.c
@@ -11,7 +11,9 @@ static struct bitset frames;
struct page_directory *kernel_pagedir, *current_pagedir;
-/* ACCESSOR FUNCTIONS FOR STATIC BITSET */
+/************************** PHYSICAL MEMORY ALLOCATION ************************/
+
+/* Allocates a page of physical memory. */
uint32_t frame_alloc() {
uint32_t free = bitset_firstFree(&frames);
bitset_set(&frames, free);
@@ -22,6 +24,13 @@ void frame_free(uint32_t id) {
bitset_clear(&frames, id);
}
+/************************* PAGING INITIALIZATION *****************************/
+
+/* This function creates the kernel page directory. It must be called before the GDT is loaded.
+ It maps 0xE0000000+ to the corresponding physical kernel code, but it also maps
+ 0x00000000+ to that code because with the false GDT we set up in loader_.asm,
+ the code will be looked for at the beginning of the memory. Only when the real GDT is loaded
+ we can de-allocate pages at 0x00000000 ; this is done by paging_cleanup. */
void paging_init(size_t totalRam) {
uint32_t i;
@@ -50,6 +59,7 @@ void paging_init(size_t totalRam) {
monitor_write("} [Paging] ");
}
+/* De-allocates pages at 0x00000000 where kernel code was read from with the GDT from loader_.asm. */
void paging_cleanup() {
uint32_t i;
for (i = 0; i < (mem_placementAddr - 0xE0000000) / 0x100000; i++) {
@@ -59,6 +69,10 @@ void paging_cleanup() {
monitor_write("[PD Cleanup] ");
}
+/************************* PAGING EVERYDAY USE *****************************/
+
+/* Switch to a page directory. Can be done if we are sure not to be interrupted by a task switch.
+ Example use for cross-memory space writing in linker/elf.c */
void pagedir_switch(struct page_directory *pd) {
current_pagedir = pd;
asm volatile("mov %0, %%cr3" : : "r"(pd->physicalAddr));
@@ -68,6 +82,7 @@ void pagedir_switch(struct page_directory *pd) {
asm volatile("mov %0, %%cr0" : : "r"(cr0));
}
+/* Creates a new page directory for a process, and maps the kernel page tables on it. */
struct page_directory *pagedir_new() {
uint32_t i;
@@ -87,6 +102,7 @@ struct page_directory *pagedir_new() {
return pd;
}
+/* Deletes a page directory, cleaning it up. */
void pagedir_delete(struct page_directory *pd) {
uint32_t i;
//Unmap segments
@@ -99,6 +115,9 @@ void pagedir_delete(struct page_directory *pd) {
kfree(pd);
}
+/* Handle a paging fault. First, looks for the corresponding segment.
+ If the segment was found and it handles the fault, return normally.
+ Else, display informatinos and return an error. */
uint32_t paging_fault(struct registers *regs) {
size_t addr;
struct segment_map *seg = 0;
@@ -127,6 +146,9 @@ uint32_t paging_fault(struct registers *regs) {
return 0;
}
+/* Gets the corresponding page in a page directory for a given address.
+ If make is set, the necessary page table can be created.
+ Can return 0 if make is not set. */
struct page *pagedir_getPage(struct page_directory *pd, uint32_t address, int make) {
address /= 0x1000;
uint32_t table_idx = address / 1024;
@@ -145,6 +167,7 @@ struct page *pagedir_getPage(struct page_directory *pd, uint32_t address, int ma
}
}
+/* Modifies a page structure so that it is mapped to a frame. */
void page_map(struct page *page, uint32_t frame, uint32_t user, uint32_t rw) {
if (page != 0 && page->frame == 0 && page->present == 0) {
page->present = 1;
@@ -154,6 +177,7 @@ void page_map(struct page *page, uint32_t frame, uint32_t user, uint32_t rw) {
}
}
+/* Modifies a page structure so that it is no longer mapped to a frame. */
void page_unmap(struct page *page) {
if (page != 0) {
page->frame = 0;
@@ -161,6 +185,7 @@ void page_unmap(struct page *page) {
}
}
+/* Same as above but also frees the frame. */
void page_unmapFree(struct page *page) {
if (page != 0) {
if (page->frame != 0) frame_free(page->frame);
diff --git a/src/kernel/mem/seg.c b/src/kernel/mem/seg.c
index e3eca67..4a33db3 100644
--- a/src/kernel/mem/seg.c
+++ b/src/kernel/mem/seg.c
@@ -2,6 +2,8 @@
#include "mem.h"
#include <core/sys.h>
+/* Call this function when mapping a segment to a page directory.
+ Calls the appropriate map method and updates the segment's and pagedir's information. */
struct segment_map *seg_map(struct segment* seg, struct page_directory *pagedir, size_t offset) {
struct segment_map *sm = seg->map(seg, pagedir, offset);
if (sm == 0) return 0;
@@ -13,6 +15,9 @@ struct segment_map *seg_map(struct segment* seg, struct page_directory *pagedir,
return sm;
}
+/* Call this function when unmapping a segment from a page directory.
+ The segment will automatically be deleted if it is not mapped.
+ Calls the appropriate unmap method and updates the segment's and pagedir's information. */
void seg_unmap(struct segment_map *map) {
map->seg->unmap(map);
if (map->pagedir->mappedSegs == map) {
@@ -32,7 +37,14 @@ void seg_unmap(struct segment_map *map) {
}
// ************************************ SIMPLESEG stuff *************
+
+static struct segment_map* simpleseg_map(struct segment* seg, struct page_directory* pagedir, size_t offset);
+static void simpleseg_unmap(struct segment_map*);
+static void simpleseg_delete(struct segment *seg);
+static int simpleseg_handleFault(struct segment_map* map, size_t addr, int write);
+/* Call this when creating a simpleseg.
+ Creates the simpleseg structure and the segment structure and fills them up. */
struct segment* simpleseg_make(size_t start, size_t len, int writable) {
struct simpleseg *ss = kmalloc(sizeof(struct simpleseg));
struct segment *se = kmalloc(sizeof(struct segment));
@@ -46,6 +58,7 @@ struct segment* simpleseg_make(size_t start, size_t len, int writable) {
return se;
}
+/* For internal use only. Called when a simpleseg is mapped to a pagedirectory. */
struct segment_map* simpleseg_map(struct segment* seg, struct page_directory* pagedir, size_t offset) {
struct segment_map *sm = kmalloc(sizeof(struct segment_map));
sm->start = ((struct simpleseg*)(seg->seg_data))->start;
@@ -53,6 +66,8 @@ struct segment_map* simpleseg_map(struct segment* seg, struct page_directory* pa
return sm;
}
+/* For internal use only. Called when a simpleseg is unmapped.
+ Frees all the allocated pages. */
void simpleseg_unmap(struct segment_map* sm) {
size_t i;
for (i = sm->start; i < sm->start + sm->len; i += 0x1000) {
@@ -60,6 +75,7 @@ void simpleseg_unmap(struct segment_map* sm) {
}
}
+/* For internal use only. Handles a page fault. Can allocate and map a frame if necessary. */
int simpleseg_handleFault(struct segment_map* sm, size_t addr, int write) {
struct simpleseg *ss = sm->seg->seg_data;
if (write && !ss->writable) return 1;
@@ -70,14 +86,16 @@ int simpleseg_handleFault(struct segment_map* sm, size_t addr, int write) {
return 0;
}
+/* For internal use only. Called when the simpleseg is deleted. Does nothing. */
void simpleseg_delete(struct segment* seg) {
}
+/* Call this to resize a simpleseg. Ajusts the size and frees pages if the new size is smaller.*/
int simpleseg_resize(struct segment_map *map, size_t len) {
size_t i;
if (map == 0) return -1;
- if (map->seg->delete != simpleseg_delete) return -2;
+ if (map->seg->delete != simpleseg_delete) return -2; //check segment is a simpleseg
struct simpleseg *s = (struct simpleseg*)map->seg->seg_data;
if (len & 0xFFF) len = (len & 0xFFFFF000) + 0x1000;
diff --git a/src/kernel/mem/seg.h b/src/kernel/mem/seg.h
index 26664dc..d37ba59 100644
--- a/src/kernel/mem/seg.h
+++ b/src/kernel/mem/seg.h
@@ -1,6 +1,9 @@
#ifndef DEF_SEG_H
#define DEF_SEG_H
+/* Segments are pieces of usable memory in a process' address space.
+ They have nothing to do with GDT segments, they are created over paging. */
+
#include "paging.h"
struct segment_map;
@@ -8,6 +11,7 @@ struct segment {
void* seg_data;
int mappings;
+ // these 4 functions must not be used directly by anyone
struct segment_map* (*map)(struct segment* seg, struct page_directory* pagedir, size_t offset);
void (*unmap)(struct segment_map*);
void (*delete)(struct segment* seg);
@@ -21,8 +25,9 @@ struct segment_map {
struct segment_map *next;
};
-//parameter offset in seg_map needs not be used
+//parameter offset in seg_map doesn't need to be used
struct segment_map *seg_map(struct segment* seg, struct page_directory* pagedir, size_t offset);
+/* When unmapping a segment, the segment is deleted if it is not mapped anywhere anymore. */
void seg_unmap(struct segment_map* map);
/// ************************************* SIMPLESEG stuff *****************
@@ -32,11 +37,7 @@ struct simpleseg {
size_t start, len;
};
-struct segment* simpleseg_make(size_t start, size_t len, int writable);
-struct segment_map* simpleseg_map(struct segment* seg, struct page_directory* pagedir, size_t offset);
-void simpleseg_unmap(struct segment_map*);
-void simpleseg_delete(struct segment *seg);
-int simpleseg_handleFault(struct segment_map* map, size_t addr, int write);
+struct segment* simpleseg_make(size_t start, size_t len, int writable);
int simpleseg_resize(struct segment_map *map, size_t len);
#endif