I have a code based on this http://hosted.cjmovie.net/TutMultitask.htm tutorial. It doesn't cause any errors, but it doesn't work for its purpose, switching tasks.
IRQ0 handler.
Code: Select all
global irq0
irq0:
cli
pusha
push ds
push es
push fs
push gs
mov eax, 0x10 ; Data segment.
mov ds, eax
mov es, eax
mov fs, eax
mov gs, eax
push esp ; Pointer to the stuff we just pushed.
extern switch_task ; multitasking/task.c
call switch_task ; Call C code.
pop eax
mov esp, eax ; Replace the stack with the return value of
; the C function.
; Send End Of Interrupt signal.
mov al, 0x20
out 0x20, al
pop gs
pop fs
pop es
pop ds
popa
iret
Code: Select all
// Basic Operating System.
// Multitasking.
#ifndef TASK_H
#define TASK_H
#include <stdint.h>
// Task descriptor.
typedef struct task_s
{
uint32_t esp0; // Stack for the kernel.
uint32_t esp3; // Stack for the task.
struct task_s *next; // The next task.
} __attribute__ ((packed)) task_t;
/* multitasking/task.c */
task_t *create_task (void *);
uint32_t switch_task (uint32_t);
#endif /* !TASK_H */
Code: Select all
// Basic Operating System.
// Multitasking.
#include <multitasking/task.h>
#include <memory/kmalloc.h>
#include <io/screen.h>
#include <stddef.h>
// Task queue.
task_t *task_queue;
// The current task.
task_t *current_task = NULL;
// Create a task.
task_t *create_task (void (*task_func))
{
uint32_t *stack; // Pointer to the stack of the new task.
// Create a new task.
task_t *new_task = (task_t *) kmalloc (sizeof (task_t));
// Create a stack for the task.
stack = (uint32_t *) kmalloc (4096);
new_task->esp0 = (uint32_t) stack;
// Are there any tasks in the queue?
if (task_queue == NULL)
{
// No. The created task will be the first one.
task_queue = new_task;
}
else
{
// Yes. Make the task `new_task' the last one.
task_t *last = task_queue; // The last task.
while (1)
{
if (last->next != NULL)
last = last->next;
else
break;
}
last->next = new_task;
}
// Fill in the task descriptor.
// Set the registers.
// First, the segment registers.
*--stack = 0x10; // GS
*--stack = 0x10; // FS
*--stack = 0x10; // ES
*--stack = 0x10; // DS
// Next, the registers pushed by `pusha'.
*--stack = 0; // EDI
*--stack = 0; // ESI
*--stack = 0; // EBP
*--stack = 0; // ESP
*--stack = 0; // EBX
*--stack = 0; // EDX
*--stack = 0; // ECX
*--stack = 0; // EAX
// Now these are the registers pushed automatically.
*--stack = (uint32_t) task_func; // EIP
*--stack = 0x08; // CS
*--stack = 0x0202; // EFLAGS
*--stack = 0; // USERESP
*--stack = 0x10; // SS
// Update the stack pointer.
new_task->esp0 = (uint32_t) stack;
new_task->next = NULL;
return new_task;
}
// Switch between tasks.
uint32_t switch_task (uint32_t task_esp)
{
puts ("switch_task()\n");
// Is there the current task?
if (current_task == NULL)
{
// No. Make the first task in the queue the current one.
current_task = task_queue;
}
// Save the stack pointer of the task.
current_task->esp0 = task_esp;
// Switch to the next task.
// Is there the next task?
if (current_task->next == NULL)
{
// No. Switch to the start of the queue.
current_task = task_queue;
}
else
{
// Yes. Switch to it.
current_task = current_task->next;
}
// This is reached, and it's returned well from the function to the ISR.
return current_task->esp0;
}
Code: Select all
// The task №1.
void task_1 (void)
{
halt (); // The kernel will be still running, so the function is not called.
uint8_t *vidmem = (uint8_t *) 0xB8001;
for (;;) *vidmem++;
}
// The task №2.
void task_2 (void)
{
uint8_t *vidmem = (uint8_t *) 0xB8003;
for (;;) *vidmem++;
}
Code: Select all
// The C kernel main.
void kernel_main (mb_info_t *mb_info, uint32_t kernel_end)
{
init_screen ();
clear_screen ();
setup_idt ();
init_keyboard_handler ();
init_timer_handler ();
asm volatile ("cli"); // Disable interrupts due to multitasking.
<...>
puts ("[kernel_main] Creating the task #1.\n");
task_t *task1 = create_task (task_1);
puts ("[kernel_main] Creating the task #2.\n");
task_t *task2 = create_task (task_2);
puts ("[kernel_main] Enabling interrupts.\n");
asm volatile ("sti");
puts ("[kernel_main] End of the function.\n");
}
`switch_task()' string is displayed on the screen each short (<1 sec.) period of time, but the tasks functions are not get called.
P.S. Are there spoilers on the forum?