Hacks(git add .git add .) multithreading.
This commit is contained in:
parent
585cb33680
commit
2ad677e750
8 changed files with 122 additions and 12 deletions
|
@ -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.");
|
|
@ -9,7 +9,7 @@ namespace driver
|
|||
public Driver
|
||||
{
|
||||
private:
|
||||
static void dispatchIRQ(CpuState *cpu);
|
||||
static void dispatchIRQ(CpuState *&cpu);
|
||||
public:
|
||||
Keyboard();
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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! ";
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace driver
|
|||
|
||||
void Timer::install()
|
||||
{
|
||||
IDT::interrupt(0x20) = Interrupt([](auto *) { counter++; });
|
||||
IDT::interrupt(0x20) = Interrupt([](auto *&) { counter++; });
|
||||
}
|
||||
|
||||
void Timer::reset()
|
||||
|
|
Loading…
Reference in a new issue