From 02364038bd02b1030d980d6583a44053a9fbf3fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Quei=C3=9Fner?= Date: Wed, 18 May 2016 10:12:01 +0200 Subject: [PATCH] Some changes in VMM stuff. Mainly a "safe" commit. --- prototypes/base/concepts.txt | 45 +++++++++ prototypes/base/include/driver/scheduler.hpp | 20 +++- prototypes/base/include/vmm.hpp | 1 - prototypes/base/init.cpp | 100 ++----------------- prototypes/base/memory.txt | 10 ++ prototypes/base/src/scheduler.cpp | 82 +++++++++++++-- 6 files changed, 152 insertions(+), 106 deletions(-) create mode 100644 prototypes/base/concepts.txt create mode 100644 prototypes/base/memory.txt diff --git a/prototypes/base/concepts.txt b/prototypes/base/concepts.txt new file mode 100644 index 0000000..581eac0 --- /dev/null +++ b/prototypes/base/concepts.txt @@ -0,0 +1,45 @@ + +# DasOS Concepts + +## Memory Layout + +| Start | Length | Length -h | Description | +|------------|------------|-----------|--------------------------------------------------------------------------| +| 0x00000000 | 0x40000000 | 1 GB | Kernel Space. This is where the kernel and its functionality is located. | +| 0x00100000 | ??? | ??? | Kernel entry point and load target. Here the kernel will be loaded. | +| 0x20000000 | 0x20000000 | 512 MB | Kernel Heap. This memory is used for dynamic allocations in the kernel. | +| 0x40000000 | 0xC0000000 | 3 GB | User Space. This is where Artifacts are loaded and executed. | + +### Kernel Heap + +A simple storage allocator. + +Storage of: +- Task Descriptions +- Memory Mapping Information +- Location of loaded artifacts +- ... + +## Starting a Task + +### Requirements + +- allocate task structure +- allocate mapping directory +- fill mapping directory with + - Lower End: Copy kernel mappings + - Upper End: Copy artifact data +- allocate task stack + +## Executables, Libraries and Stuff + +Artifact = Executable + Library + Shared Memory + +### Artifact Types + +| Type | Entry Point | Description | +|------------|-------------|--------------------------------------------------------------------------------------------------------------------------------------| +| Program | _main | A program targeted at user or system administrator. Can be executed with command line arguments. Uses stdin, stdout, stderr. | +| Library | _libmain | Can be loaded by other artifacts and allows utilization of a shared set of functions. | +| Service | _svcmain | A service is a background worker that won't be terminated when its main function returns. Can be 'woken up' by an external artifact. | +| Driver | _drvinit | A driver is loaded at system start and is allowed to request and dispatch interrupts. Can be used to create a flexible OS. | diff --git a/prototypes/base/include/driver/scheduler.hpp b/prototypes/base/include/driver/scheduler.hpp index 5e538f3..a1b14d4 100644 --- a/prototypes/base/include/driver/scheduler.hpp +++ b/prototypes/base/include/driver/scheduler.hpp @@ -6,16 +6,21 @@ namespace driver { + using EntryPoint = void (*)(); + class Task { + friend class Scheduler; private: - physical_t stackBottom; + Task *previous, *next; CpuState *cpu; - public: - Task(); + physical_t stackBottom; + + Task(EntryPoint ep); Task(const Task &) = delete; Task(Task &&) = delete; ~Task(); + public: }; class Scheduler : @@ -23,12 +28,17 @@ namespace driver { private: static Scheduler *current; - static void dispatch(CpuState *cpu); + static void dispatch(CpuState *& cpu); - void next(CpuState *cpu); + Task *currentTask; + Task *firstTask; + Task *lastTask; + CpuState * next(CpuState *cpu); public: Scheduler(); void install() override; + + Task *spawn(EntryPoint ep); }; } \ No newline at end of file diff --git a/prototypes/base/include/vmm.hpp b/prototypes/base/include/vmm.hpp index dc18277..d01d288 100644 --- a/prototypes/base/include/vmm.hpp +++ b/prototypes/base/include/vmm.hpp @@ -43,7 +43,6 @@ public: * Unmaps a given page from the virtual memory. */ void unmap(virtual_t virt); - }; class VMM diff --git a/prototypes/base/init.cpp b/prototypes/base/init.cpp index 8300e2d..856e2ac 100644 --- a/prototypes/base/init.cpp +++ b/prototypes/base/init.cpp @@ -31,9 +31,9 @@ extern dummy kernelEndMarker; driver::Timer timer; driver::Keyboard keyboardDriver; -driver::Scheduler scheduler; +// driver::Scheduler scheduler; -VMMContext *kernelContext; +VMMContext * kernelContext; static const uint32_t entryPointAddress = 0x40000000; @@ -126,87 +126,6 @@ void task_b(void) } } -static uint8_t stack_a[4096]; -static uint8_t stack_b[4096]; - -/* - * Jeder Task braucht seinen eigenen Stack, auf dem er beliebig arbeiten kann, - * ohne dass ihm andere Tasks Dinge ueberschreiben. Ausserdem braucht ein Task - * einen Einsprungspunkt. - */ -CpuState* init_task(uint8_t* stack, void (*entry)()) -{ - /* - * CPU-Zustand fuer den neuen Task festlegen - */ - CpuState new_state; - { - new_state.eax = 0; - new_state.ebx = 0; - new_state.ecx = 0; - new_state.edx = 0; - new_state.esi = 0; - new_state.edi = 0; - new_state.ebp = 0; - //new_state..esp = unbenutzt (kein Ring-Wechsel) - new_state.eip = reinterpret_cast(entry); - - /* Ring-0-Segmentregister */ - new_state.cs = 0x08; - //new_state..ss = unbenutzt (kein Ring-Wechsel) - - /* IRQs einschalten (IF = 1) */ - new_state.eflags = 0x202; - } - - /* - * Den angelegten CPU-Zustand auf den Stack des Tasks kopieren, damit es am - * Ende so aussieht als waere der Task durch einen Interrupt unterbrochen - * worden. So kann man dem Interrupthandler den neuen Task unterschieben - * und er stellt einfach den neuen Prozessorzustand "wieder her". - */ - CpuState* state = (CpuState*) (stack + 4096 - sizeof(new_state)); - *state = new_state; - - return state; -} - -static int current_task = -1; -static int num_tasks = 2; -static CpuState* task_states[2]; - -void init_multitasking(void) -{ - task_states[0] = init_task(stack_a, task_a); - task_states[1] = init_task(stack_b, task_b); -} - -/* - * Gibt den Prozessorzustand des naechsten Tasks zurueck. Der aktuelle - * Prozessorzustand wird als Parameter uebergeben und gespeichert, damit er - * beim naechsten Aufruf des Tasks wiederhergestellt werden kann - */ -void schedule(CpuState *& cpu) -{ - /* - * Wenn schon ein Task laeuft, Zustand sichern. Wenn nicht, springen wir - * gerade zum ersten Mal in einen Task. Diesen Prozessorzustand brauchen - * wir spaeter nicht wieder. - */ - if (current_task >= 0) { - task_states[current_task] = cpu; - } - - /* - * Naechsten Task auswaehlen. Wenn alle durch sind, geht es von vorne los - */ - current_task++; - current_task %= num_tasks; - - /* Prozessorzustand des neuen Tasks aktivieren */ - cpu = task_states[current_task]; -} - extern "C" void init(Structure const & data) { Console::main @@ -299,11 +218,7 @@ extern "C" void init(Structure const & data) timer.install(); keyboardDriver.install(); - scheduler.install(); - - IDT::interrupt(0x20) = Interrupt(schedule); - - init_multitasking(); + //scheduler.install(); Console::main << "Drivers installed.\n"; @@ -311,7 +226,14 @@ extern "C" void init(Structure const & data) Console::main << "Interrupts enabled.\n"; - if(data.modules.length > 0) + //driver::Task *taskB = scheduler.spawn(task_b); + //driver::Task *taskA = scheduler.spawn(task_a); + // + //Console::main + //<< "Task A: " << taskA << "\n" + //<< "Task B: " << taskB << "\n"; + + if(data.modules.length > 0 && false) { Console::main << "ELF Modukle:\n"; dump_elf(data.modules[0].start.data()); diff --git a/prototypes/base/memory.txt b/prototypes/base/memory.txt new file mode 100644 index 0000000..50daa6a --- /dev/null +++ b/prototypes/base/memory.txt @@ -0,0 +1,10 @@ + + + + + +[0-1] GB Kernel Space + +[1-4] GB User Space + Entry Point: 0x40000000 + Stack Start: 0xFFFFFFFF diff --git a/prototypes/base/src/scheduler.cpp b/prototypes/base/src/scheduler.cpp index 8fcdbf9..636fcf6 100644 --- a/prototypes/base/src/scheduler.cpp +++ b/prototypes/base/src/scheduler.cpp @@ -1,12 +1,21 @@ #include "driver/scheduler.hpp" #include "bsod.hpp" #include "pmm.hpp" +#include "vmm.hpp" +#include "idt.hpp" +#include "console.hpp" +#include + +extern VMMContext * kernelContext; namespace driver { Scheduler * Scheduler::current = nullptr; - Scheduler::Scheduler() + Scheduler::Scheduler() : + currentTask(nullptr), + firstTask(nullptr), + lastTask(nullptr) { } @@ -18,29 +27,80 @@ namespace driver } Scheduler::current = this; - + IDT::interrupt(0x20) = Interrupt(Scheduler::dispatch); } - void Scheduler::next(CpuState *cpu) + CpuState * Scheduler::next(CpuState *cpu) { - + if (this->currentTask != nullptr) { + this->currentTask->cpu = cpu; + } + + this->currentTask = this->currentTask->next; + + /* Prozessorzustand des neuen Tasks aktivieren */ + return this->currentTask->cpu; } - void Scheduler::dispatch(CpuState *cpu) + void Scheduler::dispatch(CpuState *& cpu) { if(Scheduler::current != nullptr) { - Scheduler::current->next(cpu); - } else { - + cpu = Scheduler::current->next(cpu); } } + static uint32_t memoryPointer = 0x20000000; // start at 512 MB - - Task::Task() : - stackBottom(PMM::alloc()), cpu(nullptr) + static virtual_t alloc() { + virtual_t ptr(memoryPointer); + kernelContext->provide(ptr, VMMFlags::Writable); + memoryPointer += 0x1000; + Console::main << "Providing " << ptr << "\n"; + return ptr; + } + + Task *Scheduler::spawn(EntryPoint ep) + { + void *memory = alloc().data(); + Task *task = new (memory) Task(ep); + asm volatile("cli"); + if(this->firstTask != nullptr) { + task->next = this->firstTask; + this->lastTask->next = task; + this->firstTask = task; + } else { + this->lastTask = task; + this->firstTask = task; + task->next = task; + } + asm volatile("sti"); + return task; + } + + Task::Task(EntryPoint ep) : + previous(nullptr), next(nullptr), + cpu(nullptr), + stackBottom(alloc().data()) + { + this->cpu = (CpuState*)(this->stackBottom.numeric() + 4096 - sizeof(CpuState)); + this->cpu->eax = 0; + this->cpu->ebx = 0; + this->cpu->ecx = 0; + this->cpu->edx = 0; + this->cpu->esi = 0; + this->cpu->edi = 0; + this->cpu->ebp = 0; + //this->cpu->.esp = unbenutzt (kein Ring-Wechsel) + this->cpu->eip = reinterpret_cast(ep); + + /* Ring-0-Segmentregister */ + this->cpu->cs = 0x08; + //this->cpu->.ss = unbenutzt (kein Ring-Wechsel) + + /* IRQs einschalten (IF = 1) */ + this->cpu->eflags = 0x202; } Task::~Task()