wip: better way of handling thread switch (iret in the switch)

This commit is contained in:
0x35c
2025-11-11 11:13:35 +01:00
parent bf993baa59
commit 9059901f70
7 changed files with 64 additions and 66 deletions

View File

@ -1,3 +1,5 @@
#pragma once #pragma once
void scheduler(void); #include <stdint.h>
void scheduler(uint32_t *esp);

View File

@ -24,4 +24,4 @@ struct tcb {
struct tcb *create_thread(struct pcb *process, void (*entry)(void)); struct tcb *create_thread(struct pcb *process, void (*entry)(void));
void delete_thread(struct tcb *thread); void delete_thread(struct tcb *thread);
void switch_thread(struct tcb *thread_to_switch); void switch_thread(uint32_t *esp);

View File

@ -40,7 +40,7 @@ static void clock_handler(struct registers *regs)
{ {
(void)regs; (void)regs;
if (scheduler_counter % 10 == 0) if (scheduler_counter % 10 == 0)
scheduler(); scheduler((uint32_t *)regs->esp);
scheduler_counter++; scheduler_counter++;
sleep_counter--; sleep_counter--;
} }

View File

@ -6,31 +6,6 @@
#include "string.h" #include "string.h"
// int8_t create_kernel_process(void)
// {
// struct pcb *new_pcb = vmalloc(sizeof(struct pcb));
// if (!new_pcb)
// return -1;
// new_pcb->pid = 0;
// new_pcb->uid = 0;
// new_pcb->heap = kernel_pd;
// new_pcb->cr3 = (uint32_t *)((uint32_t)kernel_pd - HEAP_END);
// new_pcb->next = new_pcb;
// new_pcb->prev = new_pcb;
// struct tcb *kern_thread = vmalloc(sizeof(struct tcb));
// if (!kern_thread) {
// vfree(new_pcb);
// return -1;
// }
// kern_thread->esp = ;
// kern_thread->next = NULL;
// kern_thread->process = new_pcb;
// kern_thread->state = RUNNING;
// kern_thread->tid = 1;
// return 0;
// }
struct pcb *create_process(uint8_t uid) struct pcb *create_process(uint8_t uid)
{ {
static uint32_t pid = 1; static uint32_t pid = 1;
@ -47,14 +22,16 @@ struct pcb *create_process(uint8_t uid)
} }
memcpy(new_pcb->heap, current_pcb->heap, 4096); memcpy(new_pcb->heap, current_pcb->heap, 4096);
new_pcb->next = new_pcb;
new_pcb->prev = new_pcb;
if (current_pcb) { if (current_pcb) {
new_pcb->next = current_pcb->next; new_pcb->next = current_pcb->next;
new_pcb->prev = current_pcb; new_pcb->prev = current_pcb;
current_pcb->next = new_pcb; current_pcb->next = new_pcb;
if (current_pcb->prev == current_pcb) if (current_pcb->prev == current_pcb)
current_pcb->prev = new_pcb; current_pcb->prev = new_pcb;
} } else {
else {
current_pcb = new_pcb; current_pcb = new_pcb;
} }
new_pcb->signals.pending = SIG_IGN; new_pcb->signals.pending = SIG_IGN;

View File

@ -11,19 +11,32 @@
struct pcb *current_pcb; struct pcb *current_pcb;
struct tcb *current_tcb; struct tcb *current_tcb;
void scheduler(void) static struct tcb *get_thread_to_switch(void)
{ {
struct tcb *thread_to_switch; struct pcb *it_p;
if (!current_tcb) { struct tcb *it_t;
thread_to_switch = current_pcb->thread_list;
} else { it_p = current_pcb;
if (!current_tcb->next) { it_t = current_tcb == NULL ? NULL : current_tcb->next;
current_pcb = current_pcb->next; while (it_p) {
// TODO switch context while (it_t != NULL) {
thread_to_switch = current_pcb->thread_list; if (it_t != NULL && it_t->state != WAITING)
} else { return it_t;
thread_to_switch = current_tcb->next; it_t = it_t->next;
} }
it_p = it_p->next;
it_t = it_p->thread_list;
} }
switch_thread(thread_to_switch); return NULL;
}
void scheduler(uint32_t *esp)
{
struct tcb *thread_to_switch = get_thread_to_switch();
if (!thread_to_switch)
kpanic("No existing threads \n");
if (current_tcb)
current_tcb->esp = esp;
current_tcb = thread_to_switch;
switch_thread(thread_to_switch->esp);
} }

View File

@ -1,27 +1,21 @@
.intel_syntax noprefix .intel_syntax noprefix
.set CLEAR_ERRNO_INTNO, 0x08
.section .text .section .text
.global switch_thread .global switch_thread
switch_thread: switch_thread:
mov edx, DWORD PTR [esp]
cmp DWORD PTR [current_tcb], 0
je .LABEL1
mov eax, [current_tcb]
// save the current stack pointer to the old stack
mov [eax+0], esp
// stack pointer + the 4 regs pushed
// and + 1 to get the argument (next thread)
.LABEL1:
mov esi, [esp+4]
mov [current_tcb], esi
mov eax, [current_tcb]
mov esp, [eax+0] // get esp
push edx
ret mov eax, [esp + 4]
mov esp, eax
pop eax
mov ds, eax
popa
call pic_send_eoi
add esp, CLEAR_ERRNO_INTNO
iret

View File

@ -19,15 +19,27 @@ struct tcb *create_thread(struct pcb *process, void (*entry)(void))
vfree(new_tcb); vfree(new_tcb);
return NULL; return NULL;
} }
// set esp to "skip" the 4 GPRs and eip later to be used as the context uint32_t *stack = (uint32_t *)((uint8_t *)new_tcb->esp0 + STACK_SIZE);
// of the thread uint32_t *esp = stack;
uint32_t *stack =
(uint32_t *)((uint8_t *)new_tcb->esp0 + STACK_SIZE - 5 * 4);
// testing out some stuff // testing out some stuff
*(--stack) = 0x202; // EFLAGS *(--stack) = 0x202; // EFLAGS
*(--stack) = 0x08; // CS = kernel code segment *(--stack) = 0x08; // CS = kernel code segment
*(--stack) = (uint32_t)entry; *(--stack) = (uint32_t)entry;
// Error code and interrupt number (skipped by add $8, %esp)
*(--stack) = 0; // err_code
*(--stack) = 0; // int_no
// General purpose registers (for popa)
*(--stack) = 0; // EAX
*(--stack) = 0; // ECX
*(--stack) = 0; // EDX
*(--stack) = 0; // EBX
*(--stack) = (uint32_t)esp; // ESP (original - points to exit_process)
*(--stack) = 0; // EBP
*(--stack) = 0; // ESI
*(--stack) = 0; // EDI
*(--stack) = 0x10; // kernel DS
new_tcb->esp = stack; new_tcb->esp = stack;
new_tcb->process = process; new_tcb->process = process;
new_tcb->next = NULL; new_tcb->next = NULL;