diff options
author | Alex Auvolat <alex.auvolat@ens.fr> | 2015-02-14 22:37:35 +0100 |
---|---|---|
committer | Alex Auvolat <alex.auvolat@ens.fr> | 2015-02-14 22:37:35 +0100 |
commit | 73cf3eddd480f2bd7e987c58da82c243861a5314 (patch) | |
tree | b6cf499e261cd2e4d87bd08b499ebdf1b97adf90 /src | |
parent | fcc321d0ef1771edff61a986df62d2cda2d7485e (diff) | |
download | kogata-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.s | 35 | ||||
-rw-r--r-- | src/kernel/core/dbglog.c | 7 | ||||
-rw-r--r-- | src/kernel/core/kmain.c | 6 | ||||
-rw-r--r-- | src/kernel/core/paging.c | 36 | ||||
-rw-r--r-- | src/kernel/core/thread.c | 6 | ||||
-rw-r--r-- | src/kernel/include/paging.h | 12 | ||||
-rw-r--r-- | src/kernel/user/elf.c | 21 | ||||
-rw-r--r-- | src/kernel/user/process.c | 43 | ||||
-rw-r--r-- | src/rules.make | 4 |
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(¤t_thread->ctx); + if (current_thread != 0) { + save_context_and_enter_scheduler(¤t_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) |