From 0afba27e412787368ecc1f0c9d519e98914ca27f Mon Sep 17 00:00:00 2001 From: Baptiste Wicht Date: Sun, 19 Jan 2014 17:57:37 +0100 Subject: [PATCH] Try for user mode --- Makefile | 4 +- kernel/include/gdt.hpp | 4 +- kernel/include/paging.hpp | 18 ++++++--- kernel/src/acpi.cpp | 2 +- kernel/src/boot/boot_16.cpp | 10 +++-- kernel/src/memory.cpp | 2 +- kernel/src/paging.cpp | 30 +++++++-------- kernel/src/shell.cpp | 74 ++++++++++++++++++++++++++++++++++--- kernel/src/vesa.cpp | 2 +- 9 files changed, 109 insertions(+), 37 deletions(-) diff --git a/Makefile b/Makefile index 5e6b4215..654c995f 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,9 @@ qemu: default qemu-kvm -cpu host -vga std -hda hdd.img bochs: default - bochs -qf bochsrc.txt + echo "c" > commands + bochs -qf bochsrc.txt -rc commands + rm commands debug: default echo "c" > commands diff --git a/kernel/include/gdt.hpp b/kernel/include/gdt.hpp index 6a3cbd9a..f80a5cc9 100644 --- a/kernel/include/gdt.hpp +++ b/kernel/include/gdt.hpp @@ -17,8 +17,8 @@ namespace gdt { constexpr const uint16_t CODE_SELECTOR = 0x08; constexpr const uint16_t DATA_SELECTOR = 0x10; constexpr const uint16_t LONG_SELECTOR = 0x18; -constexpr const uint16_t USER_DATA_SELECTOR = 0x20; -constexpr const uint16_t USER_CODE_SELECTOR = 0x28; +constexpr const uint16_t USER_CODE_SELECTOR = 0x20; +constexpr const uint16_t USER_DATA_SELECTOR = 0x28; constexpr const uint16_t TSS_SELECTOR = 0x30; //Selector types diff --git a/kernel/include/paging.hpp b/kernel/include/paging.hpp index b42315cc..8f0763b1 100644 --- a/kernel/include/paging.hpp +++ b/kernel/include/paging.hpp @@ -14,6 +14,14 @@ namespace paging { constexpr const int PAGE_SIZE = 4096; +//Flags +constexpr const uint8_t PRESENT = 0x1; +constexpr const uint8_t WRITE = 0x2; +constexpr const uint8_t USER = 0x4; +constexpr const uint8_t WRITE_THROUGH = 0x8; +constexpr const uint8_t CACHE_DISABLED = 0x10; +constexpr const uint8_t ACCESSED= 0x20; + template constexpr bool page_aligned(T* addr){ return !(reinterpret_cast(addr) & (paging::PAGE_SIZE - 1)); @@ -28,14 +36,14 @@ void* physical_address(void* virt); bool page_present(void* virt); bool page_free_or_set(void* virt, void* physical); -bool identity_map(void* virt); -bool identity_map(void* virt, size_t pages); +bool identity_map(void* virt, uint8_t flags = PRESENT | WRITE); +bool identity_map_pages(void* virt, size_t pages, uint8_t flags = PRESENT | WRITE); -bool map(void* virt, void* physical); -bool map(void* virt, void* physical, size_t pages); +bool map(void* virt, void* physical, uint8_t flags = PRESENT | WRITE); +bool map_pages(void* virt, void* physical, size_t pages, uint8_t flags = PRESENT | WRITE); bool unmap(void* virt); -bool unmap(void* virt, size_t pages); +bool unmap_pages(void* virt, size_t pages); } //end of namespace paging diff --git a/kernel/src/acpi.cpp b/kernel/src/acpi.cpp index cc35ba97..4da43120 100644 --- a/kernel/src/acpi.cpp +++ b/kernel/src/acpi.cpp @@ -188,7 +188,7 @@ int init_acpi(){ aligned_ptr = reinterpret_cast(reinterpret_cast(ptr) & ~(paging::PAGE_SIZE - 1)); } - if(!paging::identity_map(aligned_ptr, 2)){ + if(!paging::identity_map_pages(aligned_ptr, 2)){ k_print_line("Impossible to identity map the ACPI tables"); return -1; diff --git a/kernel/src/boot/boot_16.cpp b/kernel/src/boot/boot_16.cpp index fa388f7a..e90afe54 100644 --- a/kernel/src/boot/boot_16.cpp +++ b/kernel/src/boot/boot_16.cpp @@ -141,6 +141,10 @@ void setup_vesa(){ vesa::vbe_info_block.signature[2] = 'E'; vesa::vbe_info_block.signature[3] = '2'; + vesa::vesa_enabled = false; + + return; + uint16_t return_code; asm volatile ("int 0x10" : "=a"(return_code) @@ -336,7 +340,7 @@ gdt::gdt_descriptor_t user_data_descriptor(){ descriptor.limit_low = 0xFFFF; descriptor.limit_high = 0xF; descriptor.always_1 = 1; - descriptor.dpl = 0; + descriptor.dpl = 3; descriptor.present = 1; descriptor.avl = 0; descriptor.big = 0; @@ -360,8 +364,8 @@ void setup_gdt(){ gdt[1] = code_32_descriptor(); gdt[2] = data_descriptor(); gdt[3] = code_64_descriptor(); - gdt[4] = user_data_descriptor(); - gdt[5] = user_code_64_descriptor(); + gdt[4] = user_code_64_descriptor(); + gdt[5] = user_data_descriptor(); //2. Init TSS Descriptor diff --git a/kernel/src/memory.cpp b/kernel/src/memory.cpp index 987fbd16..e59e37b1 100644 --- a/kernel/src/memory.cpp +++ b/kernel/src/memory.cpp @@ -126,7 +126,7 @@ uint64_t* allocate_block(uint64_t blocks){ auto block = reinterpret_cast(current_mmap_entry_position); - paging::identity_map(block, blocks); + paging::identity_map_pages(block, blocks); current_mmap_entry_position += blocks * BLOCK_SIZE; diff --git a/kernel/src/paging.cpp b/kernel/src/paging.cpp index 78d0ca4b..1ef6b479 100644 --- a/kernel/src/paging.cpp +++ b/kernel/src/paging.cpp @@ -18,10 +18,6 @@ typedef pt_t* pdt_t; typedef pdt_t* pdpt_t; typedef pdpt_t* pml4t_t; -constexpr const uint8_t PRESENT = 0x1; -constexpr const uint8_t WRITEABLE = 0x2; -constexpr const uint8_t USER = 0x4; - //Memory from 0x70000 can be used for pages uintptr_t last_page = 0x73000; @@ -101,7 +97,7 @@ bool paging::page_free_or_set(void* virt, void* physical){ return false; } -bool paging::map(void* virt, void* physical){ +bool paging::map(void* virt, void* physical, uint8_t flags){ //The address must be page-aligned if(!page_aligned(virt)){ return false; @@ -117,21 +113,21 @@ bool paging::map(void* virt, void* physical){ //Init new page if necessary if(!(reinterpret_cast(pml4t[pml4]) & PRESENT)){ - pml4t[pml4] = reinterpret_cast(init_new_page() | (PRESENT | WRITEABLE)); + pml4t[pml4] = reinterpret_cast(init_new_page() | flags); } auto pdpt = reinterpret_cast(reinterpret_cast(pml4t[pml4]) & ~0xFFF); //Init new page if necessary if(!(reinterpret_cast(pdpt[directory_ptr]) & PRESENT)){ - pdpt[directory_ptr] = reinterpret_cast(init_new_page() | (PRESENT | WRITEABLE)); + pdpt[directory_ptr] = reinterpret_cast(init_new_page() | flags); } auto pdt = reinterpret_cast(reinterpret_cast(pdpt[directory_ptr]) & ~0xFFF); //Init new page if necessary if(!(reinterpret_cast(pdt[directory]) & PRESENT)){ - pdt[directory] = reinterpret_cast(init_new_page() | (PRESENT | WRITEABLE)); + pdt[directory] = reinterpret_cast(init_new_page() | flags); } auto pt = reinterpret_cast(reinterpret_cast(pdt[directory]) & ~0xFFF); @@ -140,11 +136,11 @@ bool paging::map(void* virt, void* physical){ if(reinterpret_cast(pt[table]) & PRESENT){ //If the page is already set to the correct value, return true //If the page is set to another value, return false - return reinterpret_cast(pt[table]) == (reinterpret_cast(physical) | (PRESENT | WRITEABLE)); + return reinterpret_cast(pt[table]) == (reinterpret_cast(physical) | flags); } //Map to the physical address - pt[table] = reinterpret_cast(reinterpret_cast(physical) | (PRESENT | WRITEABLE)); + pt[table] = reinterpret_cast(reinterpret_cast(physical) | flags); //Flush TLB flush_tlb(virt); @@ -152,7 +148,7 @@ bool paging::map(void* virt, void* physical){ return true; } -bool paging::map(void* virt, void* physical, size_t pages){ +bool paging::map_pages(void* virt, void* physical, size_t pages, uint8_t flags){ //The address must be page-aligned if(!page_aligned(virt)){ return false; @@ -174,7 +170,7 @@ bool paging::map(void* virt, void* physical, size_t pages){ auto virt_addr = reinterpret_cast(reinterpret_cast(virt) + page * PAGE_SIZE); auto phys_addr = reinterpret_cast(reinterpret_cast(physical) + page * PAGE_SIZE); - if(!map(virt_addr, phys_addr)){ + if(!map(virt_addr, phys_addr, flags)){ return false; } } @@ -226,7 +222,7 @@ bool paging::unmap(void* virt){ return true; } -bool paging::unmap(void* virt, size_t pages){ +bool paging::unmap_pages(void* virt, size_t pages){ //The address must be page-aligned if(!page_aligned(virt)){ return false; @@ -244,10 +240,10 @@ bool paging::unmap(void* virt, size_t pages){ return true; } -bool paging::identity_map(void* virt){ - return map(virt, virt); +bool paging::identity_map(void* virt, uint8_t flags){ + return map(virt, virt, flags); } -bool paging::identity_map(void* virt, size_t pages){ - return map(virt, virt, pages); +bool paging::identity_map_pages(void* virt, size_t pages, uint8_t flags){ + return map_pages(virt, virt, pages, flags); } diff --git a/kernel/src/shell.cpp b/kernel/src/shell.cpp index 5dcccf60..30be8c56 100644 --- a/kernel/src/shell.cpp +++ b/kernel/src/shell.cpp @@ -17,6 +17,7 @@ #include "rtc.hpp" #include "elf.hpp" #include "paging.hpp" +#include "gdt.hpp" #include "vesa.hpp" //Commands @@ -743,7 +744,7 @@ std::optional read_elf_file(const std::string& file, const std::str return {std::move(content)}; } -bool allocate_segments(char* buffer, void** allocated_segments){ +bool allocate_segments(char* buffer, void** allocated_segments, uint8_t flags){ auto header = reinterpret_cast(buffer); auto program_header_table = reinterpret_cast(buffer + header->e_phoff); @@ -793,7 +794,7 @@ bool allocate_segments(char* buffer, void** allocated_segments){ //4. Map physical allocated memory to the necessary virtual memory - if(!paging::map(reinterpret_cast(first_page), aligned_memory, pages)){ + if(!paging::map_pages(reinterpret_cast(first_page), aligned_memory, pages, flags)){ k_print_line("Mapping the pages failed"); failed = true; break; @@ -810,6 +811,51 @@ bool allocate_segments(char* buffer, void** allocated_segments){ return failed; } +void* allocate_user_stack(size_t stack_address, size_t stack_size, uint8_t flags){ + //0. Calculate some stuff + auto address = stack_address; + auto first_page = reinterpret_cast(paging::page_align(reinterpret_cast(address))); + auto left_padding = address - first_page; + auto bytes = left_padding + paging::PAGE_SIZE + stack_size; + auto pages = (bytes / paging::PAGE_SIZE) + 1; + + //1. Verify that all the necessary pages are free + for(size_t i = 0; i < pages; ++i){ + if(paging::page_present(reinterpret_cast(first_page + i * paging::PAGE_SIZE))){ + k_print_line("Some pages are already mapped"); + return nullptr; + } + } + + //2. Get enough physical memory + auto memory = k_malloc(bytes); + + if(!memory){ + k_print_line("Cannot allocate memory, probably out of memory"); + return nullptr; + } + + //3. Find a start of a page inside the physical memory + + auto aligned_memory = paging::page_aligned(memory) ? memory : + reinterpret_cast((reinterpret_cast(memory) / paging::PAGE_SIZE + 1) * paging::PAGE_SIZE); + + //4. Map physical allocated memory to the necessary virtual memory + + if(!paging::map_pages(reinterpret_cast(first_page), aligned_memory, pages, flags)){ + k_print_line("Mapping the pages failed"); + return nullptr; + } + + //5. Zero-out memory + + auto memory_start = reinterpret_cast(aligned_memory) + left_padding; + + std::fill_n(reinterpret_cast(memory_start), stack_size, 0); + + return memory; +} + void release_segments(char* buffer, void** allocated_segments){ auto header = reinterpret_cast(buffer); auto program_header_table = reinterpret_cast(buffer + header->e_phoff); @@ -828,7 +874,7 @@ void release_segments(char* buffer, void** allocated_segments){ auto bytes = left_padding + paging::PAGE_SIZE + p_header.p_memsz; auto pages = (bytes / paging::PAGE_SIZE) + 1; - if(!paging::unmap(reinterpret_cast(first_page), pages)){ + if(!paging::unmap_pages(reinterpret_cast(first_page), pages)){ k_print_line("Unmap failed, memory could be in invalid state"); } } @@ -859,10 +905,26 @@ void exec_command(const std::vector& params){ std::unique_heap_array allocated_segments(header->e_phnum); - auto failed = allocate_segments(buffer, allocated_segments.get()); + auto failed = allocate_segments(buffer, allocated_segments.get(), paging::PRESENT | paging::WRITE | paging::USER); if(!failed){ - //TODO + auto stack_physical = allocate_user_stack(0x500000, paging::PAGE_SIZE * 2, paging::PRESENT | paging::WRITE | paging::USER); + + if(stack_physical){ + asm volatile("mov ax, %0; mov ds, ax; mov es, ax; mov fs, ax; mov gs, ax;" + : //No outputs + : "i" (gdt::USER_DATA_SELECTOR + 3) + : "rax"); + + asm volatile("push %0; push %1; pushfq; push %2; push %3; iretq" + : //No outputs + : "i" (gdt::USER_DATA_SELECTOR + 3), "i" (0x500000 + paging::PAGE_SIZE * 2 - 64), "i" (gdt::USER_CODE_SELECTOR + 3), "r" (header->e_entry) + : "rax"); + + //TODO Release stack + } else { + k_print_line("Unable to allocate a stack for the program"); + } } else { k_print_line("execin: Unable to execute the program"); } @@ -894,7 +956,7 @@ void execin_command(const std::vector& params){ std::unique_heap_array allocated_segments(header->e_phnum); - auto failed = allocate_segments(buffer, allocated_segments.get()); + auto failed = allocate_segments(buffer, allocated_segments.get(), paging::PRESENT | paging::WRITE); if(!failed){ auto main_function = reinterpret_cast(header->e_entry); diff --git a/kernel/src/vesa.cpp b/kernel/src/vesa.cpp index 036f18e1..a048b34c 100644 --- a/kernel/src/vesa.cpp +++ b/kernel/src/vesa.cpp @@ -69,7 +69,7 @@ void vesa::init(){ auto bytes = left_padding + paging::PAGE_SIZE + total_size; auto pages = (bytes / paging::PAGE_SIZE) + 1; - paging::identity_map(reinterpret_cast(first_page), pages); + paging::identity_map_pages(reinterpret_cast(first_page), pages); init_font(); }