aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlex Auvolat <alex.auvolat@ens.fr>2015-02-14 22:37:35 +0100
committerAlex Auvolat <alex.auvolat@ens.fr>2015-02-14 22:37:35 +0100
commit73cf3eddd480f2bd7e987c58da82c243861a5314 (patch)
treeb6cf499e261cd2e4d87bd08b499ebdf1b97adf90 /src
parentfcc321d0ef1771edff61a986df62d2cda2d7485e (diff)
downloadkogata-73cf3eddd480f2bd7e987c58da82c243861a5314.tar.gz
kogata-73cf3eddd480f2bd7e987c58da82c243861a5314.zip
Many things :
- fix context switching (it actually worked only because of optimizations!) - complete mchmap implementation - adjust elf parser to load binaries correctly even without FM_MMAP
Diffstat (limited to 'src')
-rw-r--r--src/kernel/core/context_switch.s35
-rw-r--r--src/kernel/core/dbglog.c7
-rw-r--r--src/kernel/core/kmain.c6
-rw-r--r--src/kernel/core/paging.c36
-rw-r--r--src/kernel/core/thread.c6
-rw-r--r--src/kernel/include/paging.h12
-rw-r--r--src/kernel/user/elf.c21
-rw-r--r--src/kernel/user/process.c43
-rw-r--r--src/rules.make4
9 files changed, 101 insertions, 69 deletions
diff --git a/src/kernel/core/context_switch.s b/src/kernel/core/context_switch.s
index 6738a03..b8f6bb8 100644
--- a/src/kernel/core/context_switch.s
+++ b/src/kernel/core/context_switch.s
@@ -4,11 +4,10 @@
[GLOBAL save_context_and_enter_scheduler]
; void save_context_and_enter_scheduler(struct saved_context *ctx);
save_context_and_enter_scheduler:
- pushf
+ pushf ; push flags
cli
- pusha ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
-
- mov eax, cr3
+ pusha ; push general registers
+ mov eax, cr3 ; push CR3
push eax
mov eax, [esp+44] ; get address of saved_context structure
@@ -19,32 +18,10 @@ save_context_and_enter_scheduler:
jmp run_scheduler
resume_saved_context:
- pop eax
- mov cr3, eax
-
- popa
- popf
- ret
-
-[GLOBAL irq0_save_context_and_enter_scheduler]
-; meant to be called on IRQ0
-; general registers already saved by IRQ handler stub
-; flags already saved by interruption and interruptions disabled
-; only saves CR3
-irq0_save_context_and_enter_scheduler:
- mov eax, cr3
- push eax
-
- mov eax, [esp+8] ; get address of saved_context structure
- mov [eax], esp ; save esp
- mov dword [eax+4], resume_saved_irq0_context ; save eip
-
- mov esp, kernel_stack_top
- jmp run_scheduler
-
-resume_saved_irq0_context:
- pop eax
+ pop eax ; restore CR3
mov cr3, eax
+ popa ; restore general registers
+ popf ; restore flags
ret
diff --git a/src/kernel/core/dbglog.c b/src/kernel/core/dbglog.c
index e042625..54d396c 100644
--- a/src/kernel/core/dbglog.c
+++ b/src/kernel/core/dbglog.c
@@ -14,9 +14,9 @@
static const size_t VGA_WIDTH = 80;
static const size_t VGA_HEIGHT = 25;
-static uint8_t vga_color = 7;
-static uint16_t* vga_buffer = 0;
-static uint16_t vga_row = 0, vga_column = 0;
+static uint8_t vga_color;
+static uint16_t* vga_buffer;
+static uint16_t vga_row, vga_column;
static uint16_t make_vgaentry(char c, uint8_t color) {
uint16_t c16 = c;
@@ -41,6 +41,7 @@ static void vga_init() {
vga_row = 0;
vga_column = 0;
vga_buffer = (uint16_t*) (K_HIGHHALF_ADDR + 0xB8000);
+ vga_color = 7;
for (size_t y = 0; y < VGA_HEIGHT; y++) {
for (size_t x = 0; x < VGA_WIDTH; x++) {
diff --git a/src/kernel/core/kmain.c b/src/kernel/core/kmain.c
index f5d2ace..9b9a050 100644
--- a/src/kernel/core/kmain.c
+++ b/src/kernel/core/kmain.c
@@ -95,13 +95,15 @@ void kmain(multiboot_info_t *mbd, int32_t mb_magic) {
dbg_printf("Paging seems to be working!\n");
region_allocator_init(kernel_data_end);
-
+ dbg_printf("Region allocator initialized.\n");
TEST_PLACEHOLDER_AFTER_REGION;
kmalloc_setup();
+ dbg_printf("Kernel malloc setup ok.\n");
TEST_PLACEHOLDER_AFTER_KMALLOC;
setup_syscalls();
+ dbg_printf("System calls setup ok.\n");
// enter multi-threading mode
// interrupts are enabled at this moment, so all
@@ -111,6 +113,8 @@ void kmain(multiboot_info_t *mbd, int32_t mb_magic) {
}
void kernel_init_stage2(void* data) {
+ dbg_printf("Threading setup ok.\n");
+
multiboot_info_t *mbd = (multiboot_info_t*)data;
dbg_print_region_info();
diff --git a/src/kernel/core/paging.c b/src/kernel/core/paging.c
index 5a58c8c..69fb98f 100644
--- a/src/kernel/core/paging.c
+++ b/src/kernel/core/paging.c
@@ -10,17 +10,6 @@
#define PAGE_OF_ADDR(x) (((size_t)x >> PAGE_SHIFT) % N_PAGES_IN_PT)
#define PT_OF_ADDR(x) ((size_t)x >> (PAGE_SHIFT + PT_SHIFT))
-#define PTE_PRESENT (1<<0)
-#define PTE_RW (1<<1)
-#define PTE_USER (1<<2)
-#define PTE_WRITE_THROUGH (1<<3)
-#define PTE_DISABLE_CACHE (1<<4)
-#define PTE_ACCESSED (1<<5)
-#define PTE_DIRTY (1<<6) // only PTE
-#define PTE_SIZE_4M (1<<7) // only PDE
-#define PTE_GLOBAL (1<<8) // only PTE
-#define PTE_FRAME_SHIFT 12
-
typedef struct page_table {
uint32_t page[1024];
} pagetable_t;
@@ -107,7 +96,7 @@ void page_fault_handler(registers_t *regs) {
if ((size_t)vaddr >= PD_MIRROR_ADDR) {
dbg_printf("Fault on access to mirrorred PD at 0x%p\n", vaddr);
- dbg_print_region_info();
+ dbg_dump_registers(regs);
PANIC("Unhandled kernel space page fault");
}
@@ -164,10 +153,11 @@ void paging_setup(void* kernel_data_end) {
// paging already enabled in loader, nothing to do.
- // disable 4M pages (remove PSE bit in CR4)
+
uint32_t cr4;
asm volatile("movl %%cr4, %0": "=r"(cr4));
- cr4 &= ~0x00000010;
+ cr4 &= ~(1<<4); // disable 4M pages (remove PSE bit in CR4)
+ cr4 |= (1<<7); // enable global PTE/PDE
asm volatile("movl %0, %%cr4":: "r"(cr4));
idt_set_ex_handler(EX_PAGE_FAULT, page_fault_handler);
@@ -191,15 +181,19 @@ void switch_pagedir(pagedir_t *pd) {
// Mapping and unmapping of pages //
// ============================== //
-uint32_t pd_get_frame(void* vaddr) {
+uint32_t pd_get_entry(void* vaddr) {
uint32_t pt = PT_OF_ADDR(vaddr);
uint32_t page = PAGE_OF_ADDR(vaddr);
pagetable_t *pd = ((size_t)vaddr >= K_HIGHHALF_ADDR ? &kernel_pd : current_pd);
- if (!pd->page[pt] & PTE_PRESENT) return 0;
- if (!current_pt[pt].page[page] & PTE_PRESENT) return 0;
- return current_pt[pt].page[page] >> PTE_FRAME_SHIFT;
+ if (!(pd->page[pt] & PTE_PRESENT)) return 0;
+ if (!(current_pt[pt].page[page] & PTE_PRESENT)) return 0;
+ return current_pt[pt].page[page];
+}
+
+uint32_t pd_get_frame(void* vaddr) {
+ return pd_get_entry(vaddr) >> PTE_FRAME_SHIFT;
}
bool pd_map_page(void* vaddr, uint32_t frame_id, bool rw) {
@@ -213,7 +207,7 @@ bool pd_map_page(void* vaddr, uint32_t frame_id, bool rw) {
pagetable_t *pd = ((size_t)vaddr >= K_HIGHHALF_ADDR ? &kernel_pd : current_pd);
mutex_lock(&pdd->mutex);
- if (!pd->page[pt] & PTE_PRESENT) {
+ if (!(pd->page[pt] & PTE_PRESENT)) {
uint32_t new_pt_frame = frame_alloc(1);
if (new_pt_frame == 0) {
mutex_unlock(&pdd->mutex);
@@ -243,8 +237,8 @@ void pd_unmap_page(void* vaddr) {
pagetable_t *pd = ((size_t)vaddr >= K_HIGHHALF_ADDR ? &kernel_pd : current_pd);
// no need to lock the PD's mutex
- if (!pd->page[pt] & PTE_PRESENT) return;
- if (!current_pt[pt].page[page] & PTE_PRESENT) return;
+ if (!(pd->page[pt] & PTE_PRESENT)) return;
+ if (!(current_pt[pt].page[page] & PTE_PRESENT)) return;
current_pt[pt].page[page] = 0;
invlpg(vaddr);
diff --git a/src/kernel/core/thread.c b/src/kernel/core/thread.c
index cc39eb2..e62b5a8 100644
--- a/src/kernel/core/thread.c
+++ b/src/kernel/core/thread.c
@@ -8,7 +8,6 @@
#include <paging.h>
void save_context_and_enter_scheduler(saved_context_t *ctx);
-void irq0_save_context_and_enter_scheduler(saved_context_t *ctx);
void resume_context(saved_context_t *ctx);
thread_t *current_thread = 0;
@@ -156,8 +155,9 @@ thread_t *new_thread(entry_t entry, void* data) {
// ========== //
static void irq0_handler(registers_t *regs) {
- if (current_thread != 0)
- irq0_save_context_and_enter_scheduler(&current_thread->ctx);
+ if (current_thread != 0) {
+ save_context_and_enter_scheduler(&current_thread->ctx);
+ }
}
void threading_setup(entry_t cont, void* arg) {
set_pit_frequency(TASK_SWITCH_FREQUENCY);
diff --git a/src/kernel/include/paging.h b/src/kernel/include/paging.h
index 67f9fef..702391e 100644
--- a/src/kernel/include/paging.h
+++ b/src/kernel/include/paging.h
@@ -11,6 +11,17 @@
#define PF_RSVD_WRITE_BIT (1<<3)
#define PF_OPFETCH_BIT (1<<4)
+#define PTE_PRESENT (1<<0)
+#define PTE_RW (1<<1)
+#define PTE_USER (1<<2)
+#define PTE_WRITE_THROUGH (1<<3)
+#define PTE_DISABLE_CACHE (1<<4)
+#define PTE_ACCESSED (1<<5)
+#define PTE_DIRTY (1<<6) // only PTE
+#define PTE_SIZE_4M (1<<7) // only PDE
+#define PTE_GLOBAL (1<<8) // only PTE
+#define PTE_FRAME_SHIFT 12
+
struct page_directory;
typedef struct page_directory pagedir_t;
@@ -25,6 +36,7 @@ void switch_pagedir(pagedir_t *pd);
// these functions are always relative to the currently mapped page directory
uint32_t pd_get_frame(void* vaddr); // get physical frame for virtual address
+uint32_t pd_get_entry(void* vaddr); // same as pd_get_frame but returns whole entry with flags
bool pd_map_page(void* vaddr, uint32_t frame_id, bool rw); // returns true on success, false on failure
void pd_unmap_page(void* vaddr); // does nothing if page not mapped
diff --git a/src/kernel/user/elf.c b/src/kernel/user/elf.c
index 00b3c54..a3dada7 100644
--- a/src/kernel/user/elf.c
+++ b/src/kernel/user/elf.c
@@ -34,9 +34,10 @@ proc_entry_t elf_load(fs_handle_t *f, process_t* process) {
if (read_phdr_r != sizeof(elf_phdr_t)) goto error;
if (phdr.p_type == PT_LOAD) {
- if (phdr.p_flags & PF_W) {
- mmap(process, (void*)phdr.p_vaddr, phdr.p_memsz,
+ if ((phdr.p_flags & PF_W) || !(file_get_mode(f) & FM_MMAP)) {
+ bool mmap_ok = mmap(process, (void*)phdr.p_vaddr, phdr.p_memsz,
((phdr.p_flags & PF_R) ? MM_READ : 0) | MM_WRITE);
+ if (!mmap_ok) goto error;
size_t read_r = file_read(f, phdr.p_offset, phdr.p_filesz, (char*)phdr.p_vaddr);
if (read_r != phdr.p_filesz) goto error;
@@ -44,16 +45,22 @@ proc_entry_t elf_load(fs_handle_t *f, process_t* process) {
if (phdr.p_memsz > phdr.p_filesz) {
memset((char*)phdr.p_vaddr + phdr.p_filesz, 0, phdr.p_memsz - phdr.p_filesz);
}
+
+ if (!(phdr.p_flags & PF_W)) {
+ bool mchmap_ok = mchmap(process, (void*)phdr.p_vaddr,
+ ((phdr.p_flags & PF_R) ? MM_READ : 0));
+ if (!mchmap_ok) goto error;
+ }
} else {
if (phdr.p_filesz != phdr.p_memsz) {
dbg_printf("Strange ELF file...\n");
- goto error;
}
- mmap_file(process,
- f, phdr.p_offset,
- (void*)phdr.p_vaddr, phdr.p_memsz,
- ((phdr.p_flags & PF_R) ? MM_READ : 0) | ((phdr.p_flags & PF_X) ? MM_EXEC : 0));
+ bool mmap_ok = mmap_file(process,
+ f, phdr.p_offset,
+ (void*)phdr.p_vaddr, phdr.p_memsz,
+ ((phdr.p_flags & PF_R) ? MM_READ : 0) | ((phdr.p_flags & PF_X) ? MM_EXEC : 0));
+ if (!mmap_ok) goto error;
}
}
}
diff --git a/src/kernel/user/process.c b/src/kernel/user/process.c
index a4383f7..72042d9 100644
--- a/src/kernel/user/process.c
+++ b/src/kernel/user/process.c
@@ -177,6 +177,10 @@ bool mmap_file(process_t *proc, fs_handle_t *h, size_t offset, void* addr, size_
if ((uint32_t)addr & (~PAGE_MASK)) return false;
+ int fmode = file_get_mode(h);
+ if (!(fmode & FM_MMAP) || !(fmode & FM_READ)) return false;
+ if ((mode & MM_WRITE) && !(fmode & FM_WRITE)) return false;
+
user_region_t *r = (user_region_t*)malloc(sizeof(user_region_t));
if (r == 0) return false;
@@ -212,6 +216,24 @@ bool mchmap(process_t *proc, void* addr, int mode) {
if (r == 0) return false;
r->mode = mode;
+
+ // change mode on already mapped pages
+ pagedir_t *save_pd = get_current_pagedir();
+ switch_pagedir(proc->pd);
+ for (void* it = r->addr; it < r->addr + r->size; r += PAGE_SIZE) {
+ uint32_t ent = pd_get_entry(it);
+ uint32_t frame = pd_get_frame(it);
+
+ if (ent & PTE_PRESENT) {
+ bool can_w = (ent & PTE_RW) != 0;
+ bool should_w = (mode & MM_WRITE) != 0;
+ if (can_w != should_w) {
+ pd_map_page(it, frame, should_w);
+ }
+ }
+ }
+ switch_pagedir(save_pd);
+
return true;
}
@@ -230,12 +252,27 @@ bool munmap(process_t *proc, void* addr) {
}
}
- // TODO : write modified pages back to file!
- // TODO : unmap mapped page for region...
+ btree_remove_v(proc->regions_idx, r->addr, r);
+
+ // Unmap that stuff
+ pagedir_t *save_pd = get_current_pagedir();
+ switch_pagedir(proc->pd);
+ for (void* it = r->addr; it < r->addr + r->size; r += PAGE_SIZE) {
+ uint32_t ent = pd_get_entry(it);
+ uint32_t frame = pd_get_frame(it);
+
+ if (ent & PTE_PRESENT) {
+ if ((ent & PTE_DIRTY) && (r->mode & MM_WRITE) && r->file != 0) {
+ file_write(r->file, it - r->addr + r->file_offset, PAGE_SIZE, it);
+ }
+ pd_unmap_page(it);
+ frame_free(frame, 1);
+ }
+ }
+ switch_pagedir(save_pd);
if (r->file != 0) unref_file(r->file);
- btree_remove_v(proc->regions_idx, r->addr, r);
free(r);
return true;
diff --git a/src/rules.make b/src/rules.make
index 9f4e8ce..14dfe0a 100644
--- a/src/rules.make
+++ b/src/rules.make
@@ -4,11 +4,11 @@ AS = nasm
ASFLAGS = -felf -g
CC = i586-elf-gcc
-CFLAGS += -ffreestanding -O2 -std=gnu99 -Wall -Wextra -Werror -I . -I ./include -g -Wno-unused-parameter
+CFLAGS += -ffreestanding -std=gnu99 -Wall -Wextra -Werror -Wno-unused-parameter -I . -I ./include -g
# CXX = i586-elf-g++
# CXFLAGS = -ffreestanding -O3 -Wall -Wextra -I . -I ./include -fno-exceptions -fno-rtti
LD = i586-elf-gcc
-LDFLAGS += -ffreestanding -O2 -nostdlib -lgcc
+LDFLAGS += -ffreestanding -nostdlib -lgcc
all: $(OUT)