Some changes in VMM stuff. Mainly a "safe" commit.
This commit is contained in:
parent
2ad677e750
commit
02364038bd
6 changed files with 152 additions and 106 deletions
45
prototypes/base/concepts.txt
Normal file
45
prototypes/base/concepts.txt
Normal 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. |
|
|
@ -6,16 +6,21 @@
|
||||||
|
|
||||||
namespace driver
|
namespace driver
|
||||||
{
|
{
|
||||||
|
using EntryPoint = void (*)();
|
||||||
|
|
||||||
class Task
|
class Task
|
||||||
{
|
{
|
||||||
|
friend class Scheduler;
|
||||||
private:
|
private:
|
||||||
physical_t stackBottom;
|
Task *previous, *next;
|
||||||
CpuState *cpu;
|
CpuState *cpu;
|
||||||
public:
|
physical_t stackBottom;
|
||||||
Task();
|
|
||||||
|
Task(EntryPoint ep);
|
||||||
Task(const Task &) = delete;
|
Task(const Task &) = delete;
|
||||||
Task(Task &&) = delete;
|
Task(Task &&) = delete;
|
||||||
~Task();
|
~Task();
|
||||||
|
public:
|
||||||
};
|
};
|
||||||
|
|
||||||
class Scheduler :
|
class Scheduler :
|
||||||
|
@ -23,12 +28,17 @@ namespace driver
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
static Scheduler *current;
|
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:
|
public:
|
||||||
Scheduler();
|
Scheduler();
|
||||||
|
|
||||||
void install() override;
|
void install() override;
|
||||||
|
|
||||||
|
Task *spawn(EntryPoint ep);
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -43,7 +43,6 @@ public:
|
||||||
* Unmaps a given page from the virtual memory.
|
* Unmaps a given page from the virtual memory.
|
||||||
*/
|
*/
|
||||||
void unmap(virtual_t virt);
|
void unmap(virtual_t virt);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class VMM
|
class VMM
|
||||||
|
|
|
@ -31,9 +31,9 @@ extern dummy kernelEndMarker;
|
||||||
|
|
||||||
driver::Timer timer;
|
driver::Timer timer;
|
||||||
driver::Keyboard keyboardDriver;
|
driver::Keyboard keyboardDriver;
|
||||||
driver::Scheduler scheduler;
|
// driver::Scheduler scheduler;
|
||||||
|
|
||||||
VMMContext *kernelContext;
|
VMMContext * kernelContext;
|
||||||
|
|
||||||
static const uint32_t entryPointAddress = 0x40000000;
|
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)
|
extern "C" void init(Structure const & data)
|
||||||
{
|
{
|
||||||
Console::main
|
Console::main
|
||||||
|
@ -299,11 +218,7 @@ extern "C" void init(Structure const & data)
|
||||||
|
|
||||||
timer.install();
|
timer.install();
|
||||||
keyboardDriver.install();
|
keyboardDriver.install();
|
||||||
scheduler.install();
|
//scheduler.install();
|
||||||
|
|
||||||
IDT::interrupt(0x20) = Interrupt(schedule);
|
|
||||||
|
|
||||||
init_multitasking();
|
|
||||||
|
|
||||||
Console::main << "Drivers installed.\n";
|
Console::main << "Drivers installed.\n";
|
||||||
|
|
||||||
|
@ -311,7 +226,14 @@ extern "C" void init(Structure const & data)
|
||||||
|
|
||||||
Console::main << "Interrupts enabled.\n";
|
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";
|
Console::main << "ELF Modukle:\n";
|
||||||
dump_elf(data.modules[0].start.data<elf::Header>());
|
dump_elf(data.modules[0].start.data<elf::Header>());
|
||||||
|
|
10
prototypes/base/memory.txt
Normal file
10
prototypes/base/memory.txt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[0-1] GB Kernel Space
|
||||||
|
|
||||||
|
[1-4] GB User Space
|
||||||
|
Entry Point: 0x40000000
|
||||||
|
Stack Start: 0xFFFFFFFF
|
|
@ -1,12 +1,21 @@
|
||||||
#include "driver/scheduler.hpp"
|
#include "driver/scheduler.hpp"
|
||||||
#include "bsod.hpp"
|
#include "bsod.hpp"
|
||||||
#include "pmm.hpp"
|
#include "pmm.hpp"
|
||||||
|
#include "vmm.hpp"
|
||||||
|
#include "idt.hpp"
|
||||||
|
#include "console.hpp"
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
extern VMMContext * kernelContext;
|
||||||
|
|
||||||
namespace driver
|
namespace driver
|
||||||
{
|
{
|
||||||
Scheduler * Scheduler::current = nullptr;
|
Scheduler * Scheduler::current = nullptr;
|
||||||
|
|
||||||
Scheduler::Scheduler()
|
Scheduler::Scheduler() :
|
||||||
|
currentTask(nullptr),
|
||||||
|
firstTask(nullptr),
|
||||||
|
lastTask(nullptr)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,29 +27,80 @@ namespace driver
|
||||||
}
|
}
|
||||||
Scheduler::current = this;
|
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) {
|
if(Scheduler::current != nullptr) {
|
||||||
Scheduler::current->next(cpu);
|
cpu = Scheduler::current->next(cpu);
|
||||||
} else {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t memoryPointer = 0x20000000; // start at 512 MB
|
||||||
|
|
||||||
|
static virtual_t alloc()
|
||||||
Task::Task() :
|
|
||||||
stackBottom(PMM::alloc()), cpu(nullptr)
|
|
||||||
{
|
{
|
||||||
|
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()
|
Task::~Task()
|
||||||
|
|
Loading…
Reference in a new issue