diff options
author | Alexis211 <alexis211@gmail.com> | 2010-08-10 20:39:57 +0200 |
---|---|---|
committer | Alexis211 <alexis211@gmail.com> | 2010-08-10 20:39:57 +0200 |
commit | f81bf65484fa8c81a1886f456c71f1e6eebe84e9 (patch) | |
tree | 146f304d8de8828003edd548df22cca581044017 /src/kernel/mem | |
parent | 0ec0ca40a4fedfe97c49903a329b2a9ad2e22d03 (diff) | |
download | TCE-f81bf65484fa8c81a1886f456c71f1e6eebe84e9.tar.gz TCE-f81bf65484fa8c81a1886f456c71f1e6eebe84e9.zip |
Added a lot of comments in kernel code. A bit of cleaning too.
Diffstat (limited to 'src/kernel/mem')
-rw-r--r-- | src/kernel/mem/gdt.c | 18 | ||||
-rw-r--r-- | src/kernel/mem/gdt.h | 9 | ||||
-rw-r--r-- | src/kernel/mem/heap.c | 7 | ||||
-rw-r--r-- | src/kernel/mem/heap.h | 5 | ||||
-rw-r--r-- | src/kernel/mem/mem.c | 4 | ||||
-rw-r--r-- | src/kernel/mem/mem.h | 3 | ||||
-rw-r--r-- | src/kernel/mem/paging.c | 27 | ||||
-rw-r--r-- | src/kernel/mem/seg.c | 20 | ||||
-rw-r--r-- | src/kernel/mem/seg.h | 13 |
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 |