Try for user mode

This commit is contained in:
Baptiste Wicht 2014-01-19 17:57:37 +01:00
parent 6054bf8a06
commit 0afba27e41
9 changed files with 109 additions and 37 deletions

View File

@ -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

View File

@ -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

View File

@ -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<typename T>
constexpr bool page_aligned(T* addr){
return !(reinterpret_cast<uintptr_t>(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

View File

@ -188,7 +188,7 @@ int init_acpi(){
aligned_ptr = reinterpret_cast<unsigned int*>(reinterpret_cast<uintptr_t>(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;

View File

@ -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

View File

@ -126,7 +126,7 @@ uint64_t* allocate_block(uint64_t blocks){
auto block = reinterpret_cast<uint64_t*>(current_mmap_entry_position);
paging::identity_map(block, blocks);
paging::identity_map_pages(block, blocks);
current_mmap_entry_position += blocks * BLOCK_SIZE;

View File

@ -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<uintptr_t>(pml4t[pml4]) & PRESENT)){
pml4t[pml4] = reinterpret_cast<pdpt_t>(init_new_page() | (PRESENT | WRITEABLE));
pml4t[pml4] = reinterpret_cast<pdpt_t>(init_new_page() | flags);
}
auto pdpt = reinterpret_cast<pdpt_t>(reinterpret_cast<uintptr_t>(pml4t[pml4]) & ~0xFFF);
//Init new page if necessary
if(!(reinterpret_cast<uintptr_t>(pdpt[directory_ptr]) & PRESENT)){
pdpt[directory_ptr] = reinterpret_cast<pdt_t>(init_new_page() | (PRESENT | WRITEABLE));
pdpt[directory_ptr] = reinterpret_cast<pdt_t>(init_new_page() | flags);
}
auto pdt = reinterpret_cast<pdt_t>(reinterpret_cast<uintptr_t>(pdpt[directory_ptr]) & ~0xFFF);
//Init new page if necessary
if(!(reinterpret_cast<uintptr_t>(pdt[directory]) & PRESENT)){
pdt[directory] = reinterpret_cast<pt_t>(init_new_page() | (PRESENT | WRITEABLE));
pdt[directory] = reinterpret_cast<pt_t>(init_new_page() | flags);
}
auto pt = reinterpret_cast<pt_t>(reinterpret_cast<uintptr_t>(pdt[directory]) & ~0xFFF);
@ -140,11 +136,11 @@ bool paging::map(void* virt, void* physical){
if(reinterpret_cast<uintptr_t>(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<uintptr_t>(pt[table]) == (reinterpret_cast<uintptr_t>(physical) | (PRESENT | WRITEABLE));
return reinterpret_cast<uintptr_t>(pt[table]) == (reinterpret_cast<uintptr_t>(physical) | flags);
}
//Map to the physical address
pt[table] = reinterpret_cast<page_entry>(reinterpret_cast<uintptr_t>(physical) | (PRESENT | WRITEABLE));
pt[table] = reinterpret_cast<page_entry>(reinterpret_cast<uintptr_t>(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<void*>(reinterpret_cast<uintptr_t>(virt) + page * PAGE_SIZE);
auto phys_addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(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);
}

View File

@ -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<std::string> 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<elf::elf_header*>(buffer);
auto program_header_table = reinterpret_cast<elf::program_header*>(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<void*>(first_page), aligned_memory, pages)){
if(!paging::map_pages(reinterpret_cast<void*>(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<uintptr_t>(paging::page_align(reinterpret_cast<void*>(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<void*>(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<void*>((reinterpret_cast<uintptr_t>(memory) / paging::PAGE_SIZE + 1) * paging::PAGE_SIZE);
//4. Map physical allocated memory to the necessary virtual memory
if(!paging::map_pages(reinterpret_cast<void*>(first_page), aligned_memory, pages, flags)){
k_print_line("Mapping the pages failed");
return nullptr;
}
//5. Zero-out memory
auto memory_start = reinterpret_cast<uintptr_t>(aligned_memory) + left_padding;
std::fill_n(reinterpret_cast<char*>(memory_start), stack_size, 0);
return memory;
}
void release_segments(char* buffer, void** allocated_segments){
auto header = reinterpret_cast<elf::elf_header*>(buffer);
auto program_header_table = reinterpret_cast<elf::program_header*>(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<void*>(first_page), pages)){
if(!paging::unmap_pages(reinterpret_cast<void*>(first_page), pages)){
k_print_line("Unmap failed, memory could be in invalid state");
}
}
@ -859,10 +905,26 @@ void exec_command(const std::vector<std::string>& params){
std::unique_heap_array<void*> 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<std::string>& params){
std::unique_heap_array<void*> 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<int(*)()>(header->e_entry);

View File

@ -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<void*>(first_page), pages);
paging::identity_map_pages(reinterpret_cast<void*>(first_page), pages);
init_font();
}