Is my multitasking code here correct?
Posted: Tue Oct 10, 2017 9:46 pm
Hello, I have been implementing multitasking system and I am confused why the output on the screen is not like what I expect.
If I test my multitasking system by outputting to Text Mode screen memory (0xB8000), the output is like what I expect.
For example: when I output "Hello, world" to the screen, than what appear on screen is "Hello, world".
But when I test it by drawing pixels in Graphics Mode, the screen gone weird.
What I expect:
I draw a rectangle that moving from left to right (from X position 0, to X position 800)
The result:
The rectangle is lagging while moving, and stops moving at X position 400.
What do I do wrong? Am I missing something? Or I lose my contents on some registers?
I guess there are some registers that I do not save.
multitask.cpp:
multitask.h:
multitask_asm.asm:
If I test my multitasking system by outputting to Text Mode screen memory (0xB8000), the output is like what I expect.
For example: when I output "Hello, world" to the screen, than what appear on screen is "Hello, world".
But when I test it by drawing pixels in Graphics Mode, the screen gone weird.
What I expect:
I draw a rectangle that moving from left to right (from X position 0, to X position 800)
The result:
The rectangle is lagging while moving, and stops moving at X position 400.
What do I do wrong? Am I missing something? Or I lose my contents on some registers?
I guess there are some registers that I do not save.
multitask.cpp:
Code: Select all
#include <system.h>
Multitask multitask1;
Multitask multitask2;
Multitask multitask3;
Multitask* currentTask;
extern "C" void _switch_task(Registers* regs1, Registers* regs2);
extern "C" void switchTask(Registers* regs1, Registers* regs2);
extern "C" void _test_assembly(uint32_t param1, uint32_t param2);
void switch_task(Multitask* task1, Multitask* task2) {
switchTask(&task1->regs, &task2->regs);
}
extern "C" void __pit_handler();
extern "C" Multitask* getLastTask() {
return &multitask2;
}
extern "C" Multitask* getNextTask() {
return &multitask2;
//flush();
Multitask* last = currentTask;
currentTask = currentTask->next;
/*if (currentTask == &multitask1) {
ps("Task1");
} else if (currentTask == &multitask2) {
ps("Task2");
} else if (currentTask == &multitask3) {
ps("Task3");
} else {
ps("Unknown task");
}*/
if (currentTask == &multitask1) {
currentTask = currentTask->next;
}
return currentTask;
}
void create_task(Multitask* task, void (*main)(), uint32_t flags, uint32_t* pagedir, uint32_t cs, uint32_t ss) {
task->regs.eax = 0;
task->regs.ebx = 0;
task->regs.ecx = 0;
task->regs.edx = 0;
task->regs.esi = 0;
task->regs.edi = 0;
task->regs.eflags = flags;
task->regs.eip = (uint32_t)main;
task->regs.cr3 = (uint32_t)pagedir;
task->regs.esp = (uint32_t)malloc_align(4096, 4096)+0x1000;
task->regs.ss = ss;
task->regs.cs = cs;
task->next = 0;
}
void yield() {
Multitask* last = currentTask;
currentTask = currentTask->next;
if (currentTask == &multitask1) {
currentTask = currentTask->next;
}
_switch_task(&last->regs, ¤tTask->regs);
}
extern "C" void main1() {
while (1) {
fill_rect(0, 0, get_width(), get_height(), 0xFFFFFF);
//flush();
//printf("Task 1, ");
//yield();
}
stop();
}
extern "C" void main2() {
int x = 0;
while (1) {
fill_rect(x, 0, 100, 100, 0xFF0000);
flush();
//printf("Task 2, ");
//yield();
x++;
}
stop();
}
void main3() {
int x = 700;
while (1) {
//fill_rect(x, 100, 100, 100, 0x0000FF);
printf("Task 3, ");
//x--;
//yield();
}
stop();
}
void test_multitasking() {
uint32_t cr3 = read_cr(3);
uint32_t eflags;
uint32_t cs, ss;
asm volatile("pushf; mov eax, [esp]; mov %0, eax; popf;":"=m"(eflags)::"eax");
asm volatile("mov eax, cs; mov %0, eax;":"=m"(cs)::"eax");
asm volatile("mov eax, ss; mov %0, eax;":"=m"(ss)::"eax");
create_task((Multitask*)&multitask1, main1, eflags, cr3, cs, ss);
create_task((Multitask*)&multitask2, main2, eflags, cr3, cs, ss);
create_task((Multitask*)&multitask3, main3, eflags, cr3, cs, ss);
multitask1.regs.esp = malloc_align(4096, 4096)+4096;
multitask1.next = &multitask2;
multitask2.regs.esp = malloc_align(4096, 4096)+4096;
multitask2.next = &multitask3;
multitask3.regs.esp = malloc_align(4096, 4096)+4096;
multitask3.next = &multitask1;
//multitask1 = 0x86E060
currentTask = (Multitask*)&multitask1;
idt_set_gate(32, (unsigned)__pit_handler, 0x08, 0x8E);
//irq_set_handler(0, _pit_handler);
//yield();
//switchTask(&multitask1.regs, &multitask2.regs);
}
void init_multitasking() {
//_test_assembly('A', 'B');
test_multitasking();
}
Code: Select all
#ifndef MULTITASK_H
#define MULTITASK_H
typedef struct {
uint32_t eax, ebx, ecx, edx, esi, edi, esp, ebp, eip, eflags, cr3, cs, ss;
} Registers;
typedef struct Multitask {
Registers regs;
struct Multitask *next;
} Multitask;
void init_multitasking();
extern "C" void yield();
#endif
Code: Select all
global __pit_handler
__pit_handler:
extern pnh
extern getLastTask
extern getNextTask
extern main1
extern main2
pushad
call getLastTask
mov [last_task], eax
call getNextTask
mov [next_task], eax
popad
push esp
call pnh
add esp, 4
push eax
push esp
push ebp
mov eax, [last_task]
mov [eax+4], ebx
mov [eax+8], ecx
mov [eax+12], edx
mov [eax+16], esi
mov [eax+20], edi
mov ebx, [esp+8] ;EAX
mov ecx, [esp+12] ;EIP
mov edx, [esp+4] ;ESP
add edx, 4
mov esi, [esp] ;EBP
mov edi, [esp+20] ;EFLAGS
mov [eax], ebx
mov [eax+24], edx
mov [eax+28], esi
mov [eax+32], ecx
mov [eax+36], edi
pop dword [.tmp]
pop dword [.tmp]
pop dword [.tmp]
mov eax, [next_task]
mov ebx, [eax+4]
mov ecx, [eax+8]
mov edx, [eax+12]
mov esi, [eax+16]
mov edi, [eax+20]
push eax
mov eax, [eax+24]
push eax
call pnh
add esp, 4
pop eax
mov ebp, [eax+28]
mov esp, [eax+24]
push eax
mov eax, [eax+44] ;CS
mov [esp+8], eax
pop eax
push eax
mov eax, [eax+48] ;SS
mov [esp+20], eax
pop eax
push eax
mov eax, [eax+36] ;EFLAGS
mov [esp+12], eax
push eax
popfd
pop eax
push eax
mov eax, [eax+32] ;EIP
mov eax, main2
mov [esp+4], eax
xchg eax, [esp]
pop dword [.tmp]
mov eax, [eax]
; Send End Of Interrupt
push eax
mov al, 0x20
out 0x20, al
mov eax, cr0
or eax, (1<<3)
mov cr0, eax
pop eax
iret
.eflags dd 0
.esp dd 0
.ss dd 0
.tmp dd 0
last_task dq 0
next_task dq 0