Hacks(git add .git add .) multithreading.

This commit is contained in:
Felix Queißner 2016-05-07 21:49:54 +02:00
parent 585cb33680
commit 2ad677e750
8 changed files with 122 additions and 12 deletions

View file

@ -20,6 +20,6 @@ struct CpuState
uint32_t eflags;
uint32_t esp;
uint32_t ss;
};
} __attribute__((packed));
static_assert(sizeof(CpuState) == 56, "CpuState must be 56 bytes large.");

View file

@ -9,7 +9,7 @@ namespace driver
public Driver
{
private:
static void dispatchIRQ(CpuState *cpu);
static void dispatchIRQ(CpuState *&cpu);
public:
Keyboard();

View file

@ -48,7 +48,7 @@ static_assert(sizeof(InterruptDescriptor) == 8, "InterruptDescriptor must be 8 b
class Interrupt
{
friend class IDT;
using Handler = void (*)(CpuState *cpu);
using Handler = void (*)(CpuState * & cpu);
private:
bool isEnabled;
Handler handler;
@ -70,7 +70,7 @@ private:
static InterruptDescriptor descriptors[length];
IDT() = delete;
static void dispatch(CpuState *cpu);
static CpuState * dispatch(CpuState *cpu);
static void setupPIC();
public:

View file

@ -105,6 +105,108 @@ static void dump_elf(elf::Header *header)
}
}
void delay()
{
for(volatile uint32_t i = 0; i < 0x1000000; i++);
}
void task_a(void)
{
while (1) {
Console::main.put('A');
delay();
}
}
void task_b(void)
{
while (1) {
Console::main.put('B');
delay();
}
}
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
@ -198,14 +300,17 @@ extern "C" void init(Structure const & data)
timer.install();
keyboardDriver.install();
scheduler.install();
Console::main << "Drivers installed.\n";
IDT::interrupt(0x20) = Interrupt(schedule);
init_multitasking();
Console::main << "Drivers installed.\n";
asm volatile("sti");
Console::main << "Interrupts enabled.\n";
if(data.modules.length > 0)
{
Console::main << "ELF Modukle:\n";

View file

@ -39,7 +39,9 @@ isr_handler:
// Calls interrupt handler with CPU state as argument
push %esp
call IDT_DISPATCH
add $4, %esp
// add $4, %esp
mov %eax, %esp
// Restore CPU State
pop %eax

View file

@ -63,8 +63,10 @@ void IDT::setupPIC()
slavePIC.maskInterrupts(0x00);
}
void IDT::dispatch(CpuState *cpu)
CpuState * IDT::dispatch(CpuState *cpu)
{
bool ackMaster = cpu->interrupt >= 0x20 && cpu->interrupt <= 0x2F;
bool ackSlave = cpu->interrupt >= 0x28;
Interrupt &intr = IDT::interrupts[cpu->interrupt];
if(intr.isEnabled) {
(*intr.handler)(cpu);
@ -73,12 +75,13 @@ void IDT::dispatch(CpuState *cpu)
}
// ACK interrupts
if (cpu->interrupt >= 0x20 && cpu->interrupt <= 0x2F) {
if(cpu->interrupt >= 0x28) {
if (ackMaster) {
if(ackSlave) {
slavePIC.sendEndOfInterrupt();
}
masterPIC.sendEndOfInterrupt();
}
return cpu;
}

View file

@ -14,7 +14,7 @@ namespace driver
IDT::interrupt(0x21) = Interrupt(Keyboard::dispatchIRQ);
}
void Keyboard::dispatchIRQ(CpuState *cpu)
void Keyboard::dispatchIRQ(CpuState *&cpu)
{
Console::main << "keyboard! ";
}

View file

@ -12,7 +12,7 @@ namespace driver
void Timer::install()
{
IDT::interrupt(0x20) = Interrupt([](auto *) { counter++; });
IDT::interrupt(0x20) = Interrupt([](auto *&) { counter++; });
}
void Timer::reset()