To be exact, I am pushing all the registers in the ISR stub. Then a pointer to that area of the stack is pushed, which can be accessed by C code like a pointer to a structure. Then, after it changes the values in the stack, it returns to the ISR. The ISR then perfoms POPS for all the registers it earlier pushed, only the C code has changed them. That way the pop's actually 'install' the new task. If you wish to see code, you may below. It is actually super simple

.
Also, I would like to add that I tested it on my my working machine. It works perfectly, and ran for minutes without problem. I ended up turning it off, as I could see no trouble. So it appears that either my original *real* testbed is messed up or my new computer is more forgiving.
TaskSwitch.c:
Code: Select all
TaskState NextTask;
TaskState TaskList[2];
int CurrentTask = 0;
void SetTask(int a, TaskState b){
TaskList[a] = b;
}
void TaskSwitcher(RegStateExt* r){
if(CurrentTask == 0)CurrentTask = 1;
else CurrentTask = 0;
memcpy((UCHAR*)r, (UCHAR*)&TaskList[CurrentTask], 64);
}
void StartMultitask(){
IRQ_InstallHandler(0, TaskSwitcher);
}
This is the 'main.c' (really, it's Kernel.c). KernelEntry is where control is passed to it.
Code: Select all
void BeepThis(){
for(;;)PrintString("* TASK1! *");
}
void BeepThat(){
for(;;)PrintString("+ TASK2! +");
}
TaskState BeepThisTask = {
0x10, 0x10, 0x10, 0x10,
0x00, 0x00, 0x00, 0x100000, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
(UINT)BeepThis, 0x08, 0x00,
};
TaskState BeepThatTask = {
0x10, 0x10, 0x10, 0x10,
0x00, 0x00, 0x00, 0x200000, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
(UINT)BeepThat, 0x08, 0x00,
};
void KernelEntry(LoaderInfoBlock* argv){
int i, x;
int NextMsgLine = 0;
char a;
SetSystemMemory(16);
SetSystemBitmap(0x7E0000, 0xFFFE0000);
GDT_Init();
GDT_Install();
IDT_Install();
ISR_Install();
IRQ_Install();
PIT_Install();
Keyboard_Install();
EnableInterrupts();
ClearScreenTo(0x00);
PrintString("--DEMI OS-- (Version 0.0.5b)\n");
PrintString(" + Memory Page Manager\n");
PrintString(" + GDT\n");
PrintString(" + IDT\n");
PrintString(" + ISR\n");
PrintString(" + IRQ\n");
PrintString(" + Default Module: Console(CGA)\n\n");
PrintString("Time it took to get to here: 0x");
PrintHex(PIT_GetTime());
SetTask(0, BeepThisTask);
SetTask(1, BeepThatTask);
StartMultitask();
for(;;);
}
(Note: Some non-pertaining code has been ommited.)
ISR stub:
Code: Select all
;Common stub for all ISRs. Pushes all registers, then pointer to that structure
IsrStub:
pushad ;Push this stuff, in opposite order of memory (stack grows DOWN!)
push ds
push es
push fs
push gs
mov ax, 0x10 ;Kernel Data Segment!
mov ds, ax ;Restore data segment
mov es, ax
mov fs, ax
mov gs, ax
mov eax, esp ;Get stack pointer
push eax ;Push it. Pointer to structure formed in memory above
call _IsrEntry ;Call C handler
pop eax ;Pop back the standard registers
pop gs
pop fs
pop es
pop ds
popad
add esp, 8 ;Clean up pushed error code and ISR number
iret ;Return to interrupted whatever