smp: let other processors run threads

This commit is contained in:
Matheus
2023-11-30 17:54:32 -03:00
parent 1b7e671a6d
commit 57c94ebf15
7 changed files with 82 additions and 25 deletions
+10 -5
View File
@@ -11,7 +11,7 @@ static volatile struct limine_smp_request smprequest = {
}; };
// set to 1 because of the bsp // set to 1 because of the bsp
size_t cpusawake = 1; size_t arch_smp_cpusawake = 1;
static void cpuwakeup(struct limine_smp_info *info) { static void cpuwakeup(struct limine_smp_info *info) {
cpu_set((cpu_t *)info->extra_argument); cpu_set((cpu_t *)info->extra_argument);
@@ -20,13 +20,14 @@ static void cpuwakeup(struct limine_smp_info *info) {
arch_idt_reload(); arch_idt_reload();
dpc_init(); dpc_init();
arch_mmu_apswitch(); arch_mmu_apswitch();
vmm_apinit();
cpu_initstate(); cpu_initstate();
arch_apic_timerinit(); arch_apic_timerinit();
__atomic_add_fetch(&cpusawake, 1, __ATOMIC_SEQ_CST); __atomic_add_fetch(&arch_smp_cpusawake, 1, __ATOMIC_SEQ_CST);
// TODO let other processors run threads and applications
for (;;) CPU_HALT(); sched_apentry();
} }
// if the nosmp argument is given to the kernel, this is what the APs will jump to // if the nosmp argument is given to the kernel, this is what the APs will jump to
@@ -34,6 +35,10 @@ static void cpuwakeuphalt(struct limine_smp_info *info) {
for (;;) CPU_HALT(); for (;;) CPU_HALT();
} }
void arch_smp_sendipi(cpu_t *targcpu, isr_t *isr, int target) {
arch_apic_sendipi(targcpu ? targcpu->id : 0, INTERRUPT_IDTOVECTOR(isr->id), target, 0, 1);
}
void arch_smp_wakeup() { void arch_smp_wakeup() {
struct limine_smp_response *response = smprequest.response; struct limine_smp_response *response = smprequest.response;
if (response == NULL) { if (response == NULL) {
@@ -64,7 +69,7 @@ void arch_smp_wakeup() {
// wait for other cpus to boot up // wait for other cpus to boot up
if (wakeupfn == cpuwakeup) if (wakeupfn == cpuwakeup)
while (__atomic_load_n(&cpusawake, __ATOMIC_SEQ_CST) != response->cpu_count) asm("pause"); while (__atomic_load_n(&arch_smp_cpusawake, __ATOMIC_SEQ_CST) != response->cpu_count) asm("pause");
printf("smp: awoke other processors\n"); printf("smp: awoke other processors\n");
} }
+8
View File
@@ -0,0 +1,8 @@
#ifndef _PGCACHE_H
#define _PGCACHE_H
void pgcache_init();
int pgcache_getpage(vnode_t *node, uintmax_t offset, void **ret);
int pgcache_setdirty(void *addr);
#endif
+2
View File
@@ -11,6 +11,7 @@
#define SCHED_THREAD_FLAGS_RUNNING 2 #define SCHED_THREAD_FLAGS_RUNNING 2
#define SCHED_THREAD_FLAGS_SLEEP 4 #define SCHED_THREAD_FLAGS_SLEEP 4
#define SCHED_THREAD_FLAGS_INTERRUPTIBLE 8 #define SCHED_THREAD_FLAGS_INTERRUPTIBLE 8
#define SCHED_THREAD_FLAGS_PREEMPTED 16
#define SCHED_PROC_STATE_NORMAL 0 #define SCHED_PROC_STATE_NORMAL 0
#define SCHED_PROC_STATE_ZOMBIE 1 #define SCHED_PROC_STATE_ZOMBIE 1
@@ -91,5 +92,6 @@ void sched_destroyproc(proc_t *);
void sched_destroythread(thread_t *); void sched_destroythread(thread_t *);
void sched_targetcpu(struct cpu_t *cpu); void sched_targetcpu(struct cpu_t *cpu);
void sched_sleepus(size_t us); void sched_sleepus(size_t us);
void sched_apentry();
#endif #endif
+8
View File
@@ -1,6 +1,14 @@
#ifndef _SMP_H #ifndef _SMP_H
#define _SMP_H #define _SMP_H
#define ARCH_SMP_IPI_TARGET 0
#define ARCH_SMP_IPI_SELF 1
#define ARCH_SMP_IPI_ALL 2
#define ARCH_SMP_IPI_OTHERCPUS 3
extern size_t arch_smp_cpusawake;
void arch_smp_wakeup(); void arch_smp_wakeup();
void arch_smp_sendipi(cpu_t *targcpu, isr_t *isr, int target);
#endif #endif
+1 -1
View File
@@ -4,7 +4,7 @@
#include <kernel/interrupt.h> #include <kernel/interrupt.h>
__attribute__((noreturn)) void _panic(char *msg, context_t *ctx) { __attribute__((noreturn)) void _panic(char *msg, context_t *ctx) {
printf("Oops.\n"); printf("cpu%lu: Oops.\n", _cpu()->id);
if (msg) if (msg)
printf("%s\n", msg); printf("%s\n", msg);
+4
View File
@@ -635,3 +635,7 @@ void vmm_init() {
printspace(&kernelspace); printspace(&kernelspace);
} }
void vmm_apinit() {
vmm_switchcontext(&vmm_kernelctx);
}
+49 -19
View File
@@ -12,7 +12,7 @@
#include <kernel/devfs.h> #include <kernel/devfs.h>
#define QUANTUM_US 100000 #define QUANTUM_US 100000
#define SCHEDULER_STACK_SIZE 4096 #define SCHEDULER_STACK_SIZE PAGE_SIZE
static scache_t *threadcache; static scache_t *threadcache;
static scache_t *processcache; static scache_t *processcache;
@@ -151,7 +151,6 @@ static thread_t *runqueuenext(int minprio) {
runqueuebitmap &= ~((uint64_t)1 << i); runqueuebitmap &= ~((uint64_t)1 << i);
} }
if (thread) if (thread)
thread->flags &= ~SCHED_THREAD_FLAGS_QUEUED; thread->flags &= ~SCHED_THREAD_FLAGS_QUEUED;
@@ -173,6 +172,14 @@ static __attribute__((noreturn)) void switchthread(thread_t *thread) {
thread->cpu = _cpu(); thread->cpu = _cpu();
if (current) if (current)
current->flags &= ~SCHED_THREAD_FLAGS_RUNNING; current->flags &= ~SCHED_THREAD_FLAGS_RUNNING;
__assert((thread->flags & SCHED_THREAD_FLAGS_RUNNING) == 0);
if (current && current->flags & SCHED_THREAD_FLAGS_SLEEP)
spinlock_release(&current->sleeplock);
thread->flags |= SCHED_THREAD_FLAGS_RUNNING;
ARCH_CONTEXT_SWITCHTHREAD(thread); ARCH_CONTEXT_SWITCHTHREAD(thread);
__builtin_unreachable(); __builtin_unreachable();
} }
@@ -258,9 +265,7 @@ static void yield(context_t *context) {
if (next || sleeping) { if (next || sleeping) {
ARCH_CONTEXT_THREADSAVE(thread, context); ARCH_CONTEXT_THREADSAVE(thread, context);
if (sleeping) if (sleeping == false)
spinlock_release(&thread->sleeplock);
else
runqueueinsert(thread); runqueueinsert(thread);
if (next == NULL) if (next == NULL)
@@ -348,32 +353,44 @@ void sched_setroot(vnode_t *new) {
setnodeslock(&proc->root, new); setnodeslock(&proc->root, new);
} }
static void timerhook(context_t *context, dpcarg_t arg) { // once a scheduler dpc gets run, the return context is set to this function using the scheduler stack
thread_t* current = _cpu()->thread; static void dopreempt() {
// interrupts are disabled, the thread context is already saved
interrupt_set(false);
spinlock_acquire(&runqueuelock); spinlock_acquire(&runqueuelock);
thread_t *current = _cpu()->thread;
thread_t *next = runqueuenext(current->priority); thread_t *next = runqueuenext(current->priority);
current->flags &= ~SCHED_THREAD_FLAGS_PREEMPTED;
if (next) { if (next) {
current->flags &= ~SCHED_THREAD_FLAGS_RUNNING; current->flags &= ~SCHED_THREAD_FLAGS_RUNNING;
ARCH_CONTEXT_THREADSAVE(current, context);
runqueueinsert(current); runqueueinsert(current);
} else {
ARCH_CONTEXT_THREADLOAD(next, context); next = current;
_cpu()->thread = next;
next->flags |= SCHED_THREAD_FLAGS_RUNNING;
next->cpu = _cpu();
if (next->vmmctx != current->vmmctx)
vmm_switchcontext(next->vmmctx);
} }
spinlock_release(&runqueuelock); spinlock_release(&runqueuelock);
switchthread(next);
}
static void timerhook(context_t *context, dpcarg_t arg) {
thread_t* current = _cpu()->thread;
interrupt_set(false);
// no need to preempt it again
if (current->flags & SCHED_THREAD_FLAGS_PREEMPTED)
return;
current->flags |= SCHED_THREAD_FLAGS_PREEMPTED;
ARCH_CONTEXT_THREADSAVE(current, context);
CTX_INIT(context, false);
CTX_SP(context) = (uintptr_t)_cpu()->schedulerstack;
CTX_IP(context) = (uintptr_t)dopreempt;
} }
static void cpuidlethread() { static void cpuidlethread() {
sched_targetcpu(_cpu());
interrupt_set(true); interrupt_set(true);
while (1) { while (1) {
CPU_HALT(); CPU_HALT();
@@ -400,13 +417,26 @@ void sched_sleepus(size_t us) {
sched_yield(); sched_yield();
} }
void sched_apentry() {
_cpu()->schedulerstack = vmm_map(NULL, SCHEDULER_STACK_SIZE, VMM_FLAGS_ALLOCATE, ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC, NULL);
__assert(_cpu()->schedulerstack);
_cpu()->schedulerstack = (void *)((uintptr_t)_cpu()->schedulerstack + SCHEDULER_STACK_SIZE);
_cpu()->idlethread = sched_newthread(cpuidlethread, PAGE_SIZE * 4, 3, NULL, NULL);
__assert(_cpu()->idlethread);
timer_insert(_cpu()->timer, &_cpu()->schedtimerentry, timerhook, NULL, QUANTUM_US, true);
timer_resume(_cpu()->timer);
sched_stopcurrentthread();
}
void sched_init() { void sched_init() {
threadcache = slab_newcache(sizeof(thread_t), 0, NULL, NULL); threadcache = slab_newcache(sizeof(thread_t), 0, NULL, NULL);
__assert(threadcache); __assert(threadcache);
processcache = slab_newcache(sizeof(proc_t), 0, NULL, NULL); processcache = slab_newcache(sizeof(proc_t), 0, NULL, NULL);
__assert(processcache); __assert(processcache);
_cpu()->schedulerstack = alloc(SCHEDULER_STACK_SIZE); _cpu()->schedulerstack = vmm_map(NULL, SCHEDULER_STACK_SIZE, VMM_FLAGS_ALLOCATE, ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC, NULL);
__assert(_cpu()->schedulerstack); __assert(_cpu()->schedulerstack);
_cpu()->schedulerstack = (void *)((uintptr_t)_cpu()->schedulerstack + SCHEDULER_STACK_SIZE); _cpu()->schedulerstack = (void *)((uintptr_t)_cpu()->schedulerstack + SCHEDULER_STACK_SIZE);