diff --git a/kernel-src/arch/x86-64/main.c b/kernel-src/arch/x86-64/main.c index 39f95f62..158b012c 100644 --- a/kernel-src/arch/x86-64/main.c +++ b/kernel-src/arch/x86-64/main.c @@ -58,6 +58,7 @@ void kernel_entry() { timekeeper_init(arch_hpet_ticks, u); arch_apic_timerinit(); sched_init(); + arch_smp_wakeup(); vfs_init(); tmpfs_init(); devfs_init(); diff --git a/kernel-src/arch/x86-64/mmu.c b/kernel-src/arch/x86-64/mmu.c index 004cebb8..a1e7a6e6 100644 --- a/kernel-src/arch/x86-64/mmu.c +++ b/kernel-src/arch/x86-64/mmu.c @@ -177,7 +177,7 @@ void arch_mmu_switch(pagetableptr_t table) { asm volatile("mov %%rax, %%cr3" : : "a"(table)); } -// hhdm pointer to template to be used for new mappings +// hhdm pointer to template to be used for new mappings and smp bootup static pagetableptr_t template; pagetableptr_t arch_mmu_newtable() { @@ -276,6 +276,10 @@ void arch_mmu_init() { } } + arch_mmu_apswitch(); +} + +void arch_mmu_apswitch() { arch_mmu_switch(FROM_HHDM(template)); interrupt_register(14, pfisr, NULL, IPL_IGNORE); } diff --git a/kernel-src/arch/x86-64/smp.c b/kernel-src/arch/x86-64/smp.c new file mode 100644 index 00000000..4f7c82e4 --- /dev/null +++ b/kernel-src/arch/x86-64/smp.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include +#include +#include + +static volatile struct limine_smp_request smprequest = { + .id = LIMINE_SMP_REQUEST +}; + +// set to 1 because of the bsp +size_t cpusawake = 1; + +static void cpuwakeup(struct limine_smp_info *info) { + cpu_set((cpu_t *)info->extra_argument); + + arch_gdt_reload(); + arch_idt_reload(); + dpc_init(); + arch_mmu_apswitch(); + + cpu_initstate(); + arch_apic_timerinit(); + + __atomic_add_fetch(&cpusawake, 1, __ATOMIC_SEQ_CST); + // TODO let other processors run threads and applications + for (;;) CPU_HALT(); +} + +// if the nosmp argument is given to the kernel, this is what the APs will jump to +static void cpuwakeuphalt(struct limine_smp_info *info) { + for (;;) CPU_HALT(); +} + +void arch_smp_wakeup() { + struct limine_smp_response *response = smprequest.response; + if (response == NULL) { + // TODO try to detect the other processors manually + printf("smp: limine smp request response not present\n"); + return; + } + + printf("smp: %d processor%s\n", response->cpu_count, response->cpu_count > 1 ? "s" : ""); + + // use physical pages so the other cpus have it on the hhdm + cpu_t *apcpu = pmm_alloc(ROUND_UP(sizeof(cpu_t) * response->cpu_count, PAGE_SIZE) / PAGE_SIZE, PMM_SECTION_DEFAULT); + __assert(apcpu); + apcpu = MAKE_HHDM(apcpu); + + void (*wakeupfn)(struct limine_smp_info *) = cmdline_get("nosmp") ? cpuwakeuphalt : cpuwakeup; + + // make the other processors jump to cpuwakeup() + for (int i = 0; i < response->cpu_count; ++i) { + // skip the bootstrap processor + if (response->cpus[i]->lapic_id == response->bsp_lapic_id) + continue; + + response->cpus[i]->extra_argument = (uint64_t)&apcpu[i]; + + __atomic_store_n(&response->cpus[i]->goto_address, wakeupfn, __ATOMIC_SEQ_CST); + } + + // wait for other cpus to boot up + if (wakeupfn == cpuwakeup) + while (__atomic_load_n(&cpusawake, __ATOMIC_SEQ_CST) != response->cpu_count) asm("pause"); + + printf("smp: awoke other processors\n"); +} diff --git a/kernel-src/include/x86-64/arch/mmu.h b/kernel-src/include/x86-64/arch/mmu.h index 730416a0..8daf5055 100644 --- a/kernel-src/include/x86-64/arch/mmu.h +++ b/kernel-src/include/x86-64/arch/mmu.h @@ -34,5 +34,6 @@ bool arch_mmu_ispresent(pagetableptr_t table, void *vaddr); bool arch_mmu_iswritable(pagetableptr_t table, void *vaddr); pagetableptr_t arch_mmu_newtable(); void arch_mmu_init(); +void arch_mmu_apswitch(); #endif diff --git a/kernel-src/include/x86-64/arch/smp.h b/kernel-src/include/x86-64/arch/smp.h new file mode 100644 index 00000000..8b75b9c5 --- /dev/null +++ b/kernel-src/include/x86-64/arch/smp.h @@ -0,0 +1,6 @@ +#ifndef _SMP_H +#define _SMP_H + +void arch_smp_wakeup(); + +#endif