static void bootothers(void) { extern uchar _binary____boot_x86_bootother_start[], _binary____boot_x86_bootother_size[]; uchar *code; struct cpu *c; char *stack; // Write bootstrap code to unused memory at 0x7000. code = (uchar*)0x7000; memmove(code, _binary____boot_x86_bootother_start, (uint)_binary____boot_x86_bootother_size); for(c = cpus; c < cpus+ncpu; c++) { if(c == cpus+cpu()) // We've started already. continue; cprintf("Try to start cup:%d\n", c->apicid); // Fill in %esp, %eip and start code on cpu. stack = kalloc(KSTACKSIZE); *(void**)(code-4) = stack + KSTACKSIZE; *(void**)(code-8) = mpmain; lapic_startap(c->apicid, (uint)code); // Wait for cpu to get through bootstrap. while(c->booted == 0) ; } }
// Start the non-boot (AP) processors. static void boot_aps(void) { extern unsigned char mpentry_start[], mpentry_end[]; void *code; struct CpuInfo *c; // Write entry code to unused memory at MPENTRY_PADDR code = KADDR(MPENTRY_PADDR); memmove(code, mpentry_start, mpentry_end - mpentry_start); // Boot each AP one at a time for (c = cpus; c < cpus + ncpu; c++) { if (c == cpus + cpunum()) // We've started already. continue; // Tell mpentry.S what stack to use mpentry_kstack = percpu_kstacks[c - cpus] + KSTKSIZE; // Start the CPU at mpentry_start lapic_startap(c->cpu_id, PADDR(code)); // Wait for the CPU to finish some basic setup in mp_main() while(c->cpu_status != CPU_STARTED) ; } }
static void start_smp() { int n; void *stack; for (n = 0; n < mpinfo.ncpu; n++) { if (cpuset[n].flag_bsp) { printk("CPU(BSP) #%d is up ...\n", cpuset[n].proc_id); continue; } // because each AP will initially begin with 16-bits real mode // we need to move these code under 1M address, but kernel // is usually loaded above 1M with this 16-bits code embedded // use 'apinit_start' and 'apinit_end' to locate 16-bits in // linker script and move them to target address (<1M) memmove((void *)ADDR_AP_REAL, apinit_start, (addr_t) apinit_end - (addr_t) apinit_start); // AFTER APs enter protected mode, 32bit code need jump back to // kernel text section, put this address before ADDR_AP_REAL so // AP boot section can simply get the address value *(void **)(ADDR_AP_REAL - 4) = (void *)&__main; // same as comments above, we allocate temporary stack space // for other processors, remember to free it when init task is // setup to run stack = get_free_page(); if (stack == NULL) PANIC("No memory for AP stack"); *(void **)(ADDR_AP_REAL - 8) = (void *)stack; // each processor should maintain its own per-cpu struct *(void **)(ADDR_AP_REAL - 12) = (void *)&cpuset[n]; // startup ! startup !! startup !!! lapic_startap(cpuset[n].proc_id, ADDR_AP_REAL); printk("CPU(AP) #%d is up ...\n", cpuset[n].proc_id); } }