Page 2 of 2

Re: How do I switch between kernel threads?

Posted: Fri Feb 28, 2020 12:37 pm
by peachsmith
Ok, I think I managed to get it working now.
I took the Ghost OS approach of passing the esp of the current task to my task switcher and cast it as a pointer to a struct that holds CPU state.
I also now start new tasks by constructing a default ISR stack.
In new threads, I set the eip to the address of the starting function, I set cs to be the offset of my kernel's code segment, and I set the IF bit in eflags and leave all other eflags bits as 0.

Here's my updated flow:

Code: Select all

#
# IRQ0 entry point
#
irq_0:
	pushal             # push GPRs
	pushl %esp         # push esp
	call irq_0_handler # handle PIT and task logic
	movl %eax, %esp    # update esp
	popal              # pop GPRs
	iret               # pop ISR stack

Code: Select all

/**
 * IRQ0 handler
 */
uint32_t irq_0_handler(uint32_t esp)
{
	// This is currently only used to determine if it's time to switch tasks.
	// We'll need some synchronization primitives before threads can share the PIT.
	main_ticks++;

	// Send the EOI.
	k_outb(0x20, 0x20);

	// Select the next task.
	uint32_t next_esp = k_switch_task(main_ticks, esp);

	return next_esp;
}

Code: Select all

/**
 * task switching
 */
uint32_t k_switch_task(uint32_t main_ticks, uint32_t esp)
{

    // If there is no current task,
    // then tasking has not yet been initialized.
    if (current_task == NULL || initialized == 0)
    {
        fprintf(stddbg, "tasking has not yet been initialized\n");
        return 0;
    }

    // Update the stored CPU state of the current task.
    current_task->cpu_state = (k_regs*)esp;

    // We currently switch tasks approximately every 2 seconds.
    // This logic is just for developing the task switch functionality.
    if (main_ticks % 2000 != 0)
        return (uint32_t)(current_task->cpu_state);

    // Alternate between tasks.
    switch (current_task->id)
    {
        case 1:
            current_task = &task_a;
            break;

        case 2:
            current_task = &task_b;
            break;

        case 3:
            current_task = &main_task;
            break;

        default:
            break;
    }

    return (uint32_t)(current_task->cpu_state);
}