#include #include #include #include #include #include #include extern uint8_t __ld_percpu_start[]; extern uint8_t __ld_percpu_end[]; static _Atomic(size_t) num_cpus = 1; static size_t max_cpus = SIZE_MAX; static void smp_option(uintptr_t value) { max_cpus = value; } CMDLINE_OPTION("smp", "Maximum number of CPUs to use", smp_option); [[__used, __section(".percpu.init")]] struct percpu percpu_bsp = { .self = &percpu_bsp, .id = 0, .online = false, }; struct percpu* percpu_new() { const size_t size = __ld_percpu_end - __ld_percpu_start; const size_t num_pages = ALIGN_UP(size, arch_mem_page_size()) / arch_mem_page_size(); // TODO: Map pages past the end of the kernel. // TODO: Document how allocations work. phys_t mem; if (mem_phys_alloc(num_pages, 0, &mem)) return nullptr; struct percpu* cpu = HHDM_PTR(mem); cpu->self = cpu; cpu->id = atomic_fetch_add_explicit(&num_cpus, 1, memory_order_relaxed); cpu->online = false; return cpu; } size_t percpu_max_cpus() { return max_cpus; } struct percpu* percpu_get() { return arch_percpu_get(); } void percpu_bsp_init() { arch_percpu_bsp_init(); } void percpu_init(struct boot_info*) { arch_percpu_init(); } INIT_TASK(percpu_stage, "core.percpu", percpu_init); INIT_DEPENDS(percpu_stage, mem_stage);