#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /// The CPUs static struct cpu cpus[CPUS_MAX]; static atomic_int last_cpu_index = 0; static atomic_int cpu_counter; static atomic_int cpu_id_counter = 0; /// Allocate a CPU structure struct cpu* cpu_make (uint64_t lapic_id, uint64_t acpi_id) { int id = atomic_fetch_add (&cpu_id_counter, 1); struct cpu* cpu = &cpus[id]; memset (cpu, 0, sizeof (*cpu)); cpu->lock = SPIN_LOCK_INIT; cpu->id = id; cpu->acpi_id = acpi_id; cpu->lapic_id = lapic_id; amd64_wrmsr (MSR_GS_BASE, (uint64_t)cpu); return cpu; } struct cpu* cpu_get (void) { struct cpu* ptr = (struct cpu*)amd64_rdmsr (MSR_GS_BASE); return ptr; } void cpu_request_sched (struct cpu* cpu) { if (cpu == thiscpu) { proc_sched (); return; } amd64_lapic_ipi (cpu->lapic_id, CPU_REQUEST_SCHED); } struct cpu* cpu_find_lightest (void) { struct limine_mp_response* mp = limine_mp_request.response; int start = atomic_fetch_add (&last_cpu_index, 1) % mp->cpu_count; struct cpu* best_cpu = &cpus[start]; int best_load = atomic_load (&best_cpu->proc_run_q_count); for (int i = 1; i < (int)mp->cpu_count; i++) { int idx = (start + i) % mp->cpu_count; struct cpu* cpu = &cpus[idx]; int l = atomic_load (&cpu->proc_run_q_count); if (l < best_load) { best_load = l; best_cpu = cpu; } } return best_cpu; } /// Bootstrap code for non-BSP CPUs static void amd64_smp_bootstrap (struct limine_mp_info* mp_info) { amd64_load_kernel_cr3 (); struct cpu* cpu = cpu_make (mp_info->lapic_id, mp_info->processor_id); amd64_init (cpu, true); /* gdt + idt */ syscall_init (); amd64_lapic_init (1000); DEBUG ("CPU %u is online!\n", thiscpu->id); atomic_fetch_sub (&cpu_counter, 1); struct proc* spin_proc = proc_spawn_rd ("spin.exe"); struct cpu* spin_cpu = thiscpu; proc_register (spin_proc, &spin_cpu); spin_lock_ctx_t ctxcpu; spin_lock (&spin_proc->cpu->lock, &ctxcpu); do_sched (spin_proc, &spin_proc->cpu->lock, &ctxcpu); } /// Initialize SMP subsystem for AMD64. Start AP CPUs void smp_init (void) { amd64_lapic_init (1000); struct limine_mp_response* mp = limine_mp_request.response; cpu_counter = mp->cpu_count - 1; for (size_t i = 0; i < mp->cpu_count; i++) { if (mp->cpus[i]->processor_id != thiscpu->acpi_id) { mp->cpus[i]->goto_address = &amd64_smp_bootstrap; } } DEBUG ("Waiting for other CPUs:\n"); while (atomic_load (&cpu_counter) > 0) debugprintf (".\n"); DEBUG ("All CPUs are up!\n"); }