mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-02 07:28:21 +00:00
smp: let other processors run threads
This commit is contained in:
@@ -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");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -635,3 +635,7 @@ void vmm_init() {
|
|||||||
|
|
||||||
printspace(&kernelspace);
|
printspace(&kernelspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vmm_apinit() {
|
||||||
|
vmm_switchcontext(&vmm_kernelctx);
|
||||||
|
}
|
||||||
|
|||||||
+49
-19
@@ -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(¤t->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);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user