Some changes in VMM stuff. Mainly a "safe" commit.

This commit is contained in:
Felix Queißner 2016-05-18 10:12:01 +02:00
parent 2ad677e750
commit 02364038bd
6 changed files with 152 additions and 106 deletions

View file

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

View file

@ -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);
};
}

View file

@ -43,7 +43,6 @@ public:
* Unmaps a given page from the virtual memory.
*/
void unmap(virtual_t virt);
};
class VMM

View file

@ -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<uint32_t>(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<elf::Header>());

View file

@ -0,0 +1,10 @@
[0-1] GB Kernel Space
[1-4] GB User Space
Entry Point: 0x40000000
Stack Start: 0xFFFFFFFF

View file

@ -1,12 +1,21 @@
#include "driver/scheduler.hpp"
#include "bsod.hpp"
#include "pmm.hpp"
#include "vmm.hpp"
#include "idt.hpp"
#include "console.hpp"
#include <new>
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<uint32_t>(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()