summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Moffett <ian@osmora.org>2025-09-17 15:06:35 -0400
committerIan Moffett <ian@osmora.org>2025-09-17 15:08:32 -0400
commitbb840ef326ab3570d201e045e894710fd6db18f2 (patch)
tree89133e8bfed5ead413648ad0f2ef331ec40ba031
parent9ed326263929d215887dd9bab18d292d6632ed34 (diff)
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 <ian@osmora.org>
-rw-r--r--src/sys/arch/amd64/cpu/trap.S4
-rw-r--r--src/sys/arch/amd64/os/os_proc.c81
-rw-r--r--src/sys/include/os/sched.h8
-rw-r--r--src/sys/include/sys/proc.h14
4 files changed, 100 insertions, 7 deletions
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 <machine/pcb.h>
#include <machine/gdt.h>
#include <machine/frame.h>
+#include <machine/lapic.h>
#include <string.h>
/*
@@ -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();
}
/*
@@ -122,6 +129,21 @@ md_proc_init(struct proc *procp, int flags)
}
/*
+ * 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
*/
int
@@ -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 <sys/proc.h>
#include <os/spinlock.h>
+#define SCHED_QUANTUM 10000
#define SCHED_NQUEUES 4
/*
@@ -50,6 +51,13 @@ struct sched_queue {
};
/*
+ * Context switch to another process
+ *
+ * @tf: Current CPU context frame
+ */
+void md_sched_switch(struct trapframe *tf);
+
+/*
* Enqueue a new process to a queue
*
* @q: Queue to target
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 <sys/types.h>
+#include <sys/cdefs.h>
#include <sys/queue.h>
#include <machine/pcb.h> /* 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_ */