From bb840ef326ab3570d201e045e894710fd6db18f2 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Wed, 17 Sep 2025 15:06:35 -0400 Subject: kern/amd64: proc: Add initial context switch logic This commit introduces new functions that will be useful for having multiple processes run on the system. - Add md_proc_yield() - Add md_proc_kick() - Add md_sched_switch() Signed-off-by: Ian Moffett --- src/sys/arch/amd64/cpu/trap.S | 4 +- src/sys/arch/amd64/os/os_proc.c | 81 +++++++++++++++++++++++++++++++++++++++-- src/sys/include/os/sched.h | 8 ++++ src/sys/include/sys/proc.h | 14 +++++++ 4 files changed, 100 insertions(+), 7 deletions(-) (limited to 'src/sys') diff --git a/src/sys/arch/amd64/cpu/trap.S b/src/sys/arch/amd64/cpu/trap.S index fba15ce..ef5c14f 100644 --- a/src/sys/arch/amd64/cpu/trap.S +++ b/src/sys/arch/amd64/cpu/trap.S @@ -104,8 +104,6 @@ TRAP_EXIT_EC(ss_fault) .globl lapic_tmr_isr INTR_ENTRY(lapic_tmr_isr) - // TODO mov %rsp, %rdi - cli - hlt + call md_sched_switch INTR_EXIT(lapic_tmr_isr) diff --git a/src/sys/arch/amd64/os/os_proc.c b/src/sys/arch/amd64/os/os_proc.c index 61ef51e..8c7b6f3 100644 --- a/src/sys/arch/amd64/os/os_proc.c +++ b/src/sys/arch/amd64/os/os_proc.c @@ -36,6 +36,7 @@ #include #include #include +#include #include /* @@ -43,12 +44,16 @@ * run. The catch is that we have never been in userland * from this context so we'll have to fake an IRET frame * to force the processor to have a CPL of 3. - * - * @tfp: Trapframe of context to enter */ -static inline void -__proc_kick(struct trapframe *tfp) +__dead void +md_proc_kick(struct proc *procp) { + struct md_pcb *pcbp = &procp->pcb; + struct trapframe *tfp = &pcbp->tf; + + mmu_write_vas(&pcbp->vas); + lapic_timer_oneshot_us(SCHED_QUANTUM); + __ASMV( "sti\n" "mov %0, %%rax\n" @@ -67,6 +72,8 @@ __proc_kick(struct trapframe *tfp) "m" (tfp->rflags), "r" (tfp->rip) ); + + __builtin_unreachable(); } /* @@ -121,6 +128,21 @@ md_proc_init(struct proc *procp, int flags) return 0; } +/* + * Process idle loop + */ +__dead void +md_proc_yield(void) +{ + /* Clear pending interrupts and oneshot */ + lapic_eoi(); + lapic_timer_oneshot_us(9000); + + for (;;) { + __ASMV("sti; hlt"); + } +} + /* * Set process instruction pointer */ @@ -139,3 +161,54 @@ md_set_ip(struct proc *procp, uintptr_t ip) tfp->rip = ip; return 0; } + +void +md_sched_switch(struct trapframe *tf) +{ + struct proc *self, *proc = NULL; + struct md_pcb *pcbp; + struct pcore *core; + int error; + + if ((core = this_core()) == NULL) { + printf("sched_switch: could not get core\n"); + goto done; + } + + /* Don't switch if no self */ + if ((self = core->curproc) == NULL) { + md_proc_yield(); + } + + error = sched_enq(&core->scq, self); + if (error < 0) { + goto done; + } + + /* + * Save the current trapframe to our process control + * block as we'll want it later when we're back. + */ + pcbp = &self->pcb; + memcpy(&pcbp->tf, tf, sizeof(*tf)); + + /* + * Grab the next process. If we cannot find any, assume + * we are the only one and continue on... + */ + error = sched_deq(&core->scq, &proc); + if (error < 0) { + goto done; + } + + /* Load the next trapframe into the live one */ + pcbp = &proc->pcb; + memcpy(tf, &pcbp->tf, sizeof(*tf)); + core->curproc = proc; + + /* Switch the address space and hope for the best */ + mmu_write_vas(&pcbp->vas); +done: + lapic_eoi(); + lapic_timer_oneshot_us(SCHED_QUANTUM); +} diff --git a/src/sys/include/os/sched.h b/src/sys/include/os/sched.h index b393395..1850366 100644 --- a/src/sys/include/os/sched.h +++ b/src/sys/include/os/sched.h @@ -35,6 +35,7 @@ #include #include +#define SCHED_QUANTUM 10000 #define SCHED_NQUEUES 4 /* @@ -49,6 +50,13 @@ struct sched_queue { size_t nproc; }; +/* + * Context switch to another process + * + * @tf: Current CPU context frame + */ +void md_sched_switch(struct trapframe *tf); + /* * Enqueue a new process to a queue * diff --git a/src/sys/include/sys/proc.h b/src/sys/include/sys/proc.h index d09e459..59d47ec 100644 --- a/src/sys/include/sys/proc.h +++ b/src/sys/include/sys/proc.h @@ -31,6 +31,7 @@ #define _SYS_PROC_H_ #include +#include #include #include /* standard */ @@ -87,4 +88,17 @@ int md_proc_init(struct proc *procp, int flags); */ int md_set_ip(struct proc *procp, uintptr_t ip); +/* + * Put the current process into a halt loop + * until the next one runs. + */ +__dead void md_proc_yield(void); + +/* + * Kick a process into a user context + * + * @procp: Process pointer + */ +__dead void md_proc_kick(struct proc *procp); + #endif /* !_SYS_PROC_H_ */ -- cgit v1.2.3