📄 smpboot.c
字号:
set_processor_id(cpu); set_current(idle_vcpu[cpu]); this_cpu(curr_vcpu) = idle_vcpu[cpu]; if ( cpu_has_efer ) rdmsrl(MSR_EFER, this_cpu(efer)); asm volatile ( "mov %%cr4,%0" : "=r" (this_cpu(cr4)) ); percpu_traps_init(); cpu_init(); /*preempt_disable();*/ smp_callin(); while (!cpu_isset(smp_processor_id(), smp_commenced_mask)) rep_nop(); /* * At this point, boot CPU has fully initialised the IDT. It is * now safe to make ourselves a private copy. */ construct_percpu_idt(cpu); setup_secondary_APIC_clock(); enable_APIC_timer(); /* * low-memory mappings have been cleared, flush them from * the local TLBs too. */ flush_tlb_local(); /* This must be done before setting cpu_online_map */ set_cpu_sibling_map(raw_smp_processor_id()); wmb(); cpu_set(smp_processor_id(), cpu_online_map); per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE; init_percpu_time(); /* We can take interrupts now: we're officially "up". */ local_irq_enable(); wmb(); startup_cpu_idle_loop();}extern struct { void * esp; unsigned short ss;} stack_start;u32 cpu_2_logical_apicid[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };static void map_cpu_to_logical_apicid(void){ int cpu = smp_processor_id(); int apicid = logical_smp_processor_id(); cpu_2_logical_apicid[cpu] = apicid;}static void unmap_cpu_to_logical_apicid(int cpu){ cpu_2_logical_apicid[cpu] = BAD_APICID;}#if APIC_DEBUGstatic inline void __inquire_remote_apic(int apicid){ int i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 }; char *names[] = { "ID", "VERSION", "SPIV" }; int timeout, status; printk("Inquiring remote APIC #%d...\n", apicid); for (i = 0; i < ARRAY_SIZE(regs); i++) { printk("... APIC #%d %s: ", apicid, names[i]); /* * Wait for idle. */ apic_wait_icr_idle(); apic_icr_write(APIC_DM_REMRD | regs[i], apicid); timeout = 0; do { udelay(100); status = apic_read(APIC_ICR) & APIC_ICR_RR_MASK; } while (status == APIC_ICR_RR_INPROG && timeout++ < 1000); switch (status) { case APIC_ICR_RR_VALID: status = apic_read(APIC_RRR); printk("%08x\n", status); break; default: printk("failed\n"); } }}#endif#ifdef WAKE_SECONDARY_VIA_NMIstatic int logical_apicid_to_cpu(int logical_apicid){ int i; for ( i = 0; i < sizeof(cpu_2_logical_apicid); i++ ) if ( cpu_2_logical_apicid[i] == logical_apicid ) break; if ( i == sizeof(cpu_2_logical_apicid) ); i = -1; /* not found */ return i;}/* * Poke the other CPU in the eye via NMI to wake it up. Remember that the normal * INIT, INIT, STARTUP sequence will reset the chip hard for us, and this * won't ... remember to clear down the APIC, etc later. */static int __devinitwakeup_secondary_cpu(int logical_apicid, unsigned long start_eip){ unsigned long send_status = 0, accept_status = 0; int timeout, maxlvt; int dest_cpu; u32 dest; dest_cpu = logical_apicid_to_cpu(logical_apicid); BUG_ON(dest_cpu == -1); dest = cpu_physical_id(dest_cpu); /* Boot on the stack */ apic_icr_write(APIC_DM_NMI | APIC_DEST_PHYSICAL, dest_cpu); Dprintk("Waiting for send to finish...\n"); timeout = 0; do { Dprintk("+"); udelay(100); if ( !x2apic_enabled ) send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; else send_status = 0; /* We go out of the loop directly. */ } while (send_status && (timeout++ < 1000)); /* * Give the other CPU some time to accept the IPI. */ udelay(200); /* * Due to the Pentium erratum 3AP. */ maxlvt = get_maxlvt(); if (maxlvt > 3) { apic_read_around(APIC_SPIV); apic_write(APIC_ESR, 0); } accept_status = (apic_read(APIC_ESR) & 0xEF); Dprintk("NMI sent.\n"); if (send_status) printk("APIC never delivered???\n"); if (accept_status) printk("APIC delivery error (%lx).\n", accept_status); return (send_status | accept_status);}#endif /* WAKE_SECONDARY_VIA_NMI */#ifdef WAKE_SECONDARY_VIA_INITstatic int __devinitwakeup_secondary_cpu(int phys_apicid, unsigned long start_eip){ unsigned long send_status = 0, accept_status = 0; int maxlvt, timeout, num_starts, j; /* * Be paranoid about clearing APIC errors. */ if (APIC_INTEGRATED(apic_version[phys_apicid])) { apic_read_around(APIC_SPIV); apic_write(APIC_ESR, 0); apic_read(APIC_ESR); } Dprintk("Asserting INIT.\n"); /* * Turn INIT on target chip via IPI */ apic_icr_write(APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT, phys_apicid); Dprintk("Waiting for send to finish...\n"); timeout = 0; do { Dprintk("+"); udelay(100); if ( !x2apic_enabled ) send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; else send_status = 0; /* We go out of the loop dirctly. */ } while (send_status && (timeout++ < 1000)); mdelay(10); Dprintk("Deasserting INIT.\n"); apic_icr_write(APIC_INT_LEVELTRIG | APIC_DM_INIT, phys_apicid); Dprintk("Waiting for send to finish...\n"); timeout = 0; do { Dprintk("+"); udelay(100); if ( !x2apic_enabled ) send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; else send_status = 0; /* We go out of the loop dirctly. */ } while (send_status && (timeout++ < 1000)); atomic_set(&init_deasserted, 1); /* * Should we send STARTUP IPIs ? * * Determine this based on the APIC version. * If we don't have an integrated APIC, don't send the STARTUP IPIs. */ if (APIC_INTEGRATED(apic_version[phys_apicid])) num_starts = 2; else num_starts = 0; /* * Run STARTUP IPI loop. */ Dprintk("#startup loops: %d.\n", num_starts); maxlvt = get_maxlvt(); for (j = 1; j <= num_starts; j++) { Dprintk("Sending STARTUP #%d.\n",j); apic_read_around(APIC_SPIV); apic_write(APIC_ESR, 0); apic_read(APIC_ESR); Dprintk("After apic_write.\n"); /* * STARTUP IPI * Boot on the stack */ apic_icr_write(APIC_DM_STARTUP | (start_eip >> 12), phys_apicid); /* * Give the other CPU some time to accept the IPI. */ udelay(300); Dprintk("Startup point 1.\n"); Dprintk("Waiting for send to finish...\n"); timeout = 0; do { Dprintk("+"); udelay(100); if ( !x2apic_enabled ) send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; else send_status = 0; /* We go out of the loop dirctly. */ } while (send_status && (timeout++ < 1000)); /* * Give the other CPU some time to accept the IPI. */ udelay(200); /* * Due to the Pentium erratum 3AP. */ if (maxlvt > 3) { apic_read_around(APIC_SPIV); apic_write(APIC_ESR, 0); } accept_status = (apic_read(APIC_ESR) & 0xEF); if (send_status || accept_status) break; } Dprintk("After Startup.\n"); if (send_status) printk("APIC never delivered???\n"); if (accept_status) printk("APIC delivery error (%lx).\n", accept_status); return (send_status | accept_status);}#endif /* WAKE_SECONDARY_VIA_INIT */extern cpumask_t cpu_initialized;static inline int alloc_cpu_id(void){ cpumask_t tmp_map; int cpu; cpus_complement(tmp_map, cpu_present_map); cpu = first_cpu(tmp_map); if (cpu >= NR_CPUS) return -ENODEV; return cpu;}static struct vcpu *prepare_idle_vcpu(unsigned int cpu){ if (idle_vcpu[cpu]) return idle_vcpu[cpu]; return alloc_idle_vcpu(cpu);}static void *prepare_idle_stack(unsigned int cpu){ if (!stack_base[cpu]) stack_base[cpu] = alloc_xenheap_pages(STACK_ORDER); return stack_base[cpu];}static int __devinit do_boot_cpu(int apicid, int cpu)/* * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad * (ie clustered apic addressing mode), this is a LOGICAL apic ID. * Returns zero if CPU booted OK, else error code from wakeup_secondary_cpu. */{ unsigned long boot_error; int timeout; unsigned long start_eip; unsigned short nmi_high = 0, nmi_low = 0; struct vcpu *v; /* * Save current MTRR state in case it was changed since early boot * (e.g. by the ACPI SMI) to initialize new CPUs with MTRRs in sync: */ mtrr_save_state(); ++cpucount; booting_cpu = cpu; v = prepare_idle_vcpu(cpu); BUG_ON(v == NULL); /* start_eip had better be page-aligned! */ start_eip = setup_trampoline(); /* So we see what's up */ printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip); stack_start.esp = prepare_idle_stack(cpu); /* Debug build: detect stack overflow by setting up a guard page. */ memguard_guard_stack(stack_start.esp); /* * This grunge runs the startup process for * the targeted processor. */ atomic_set(&init_deasserted, 0); Dprintk("Setting warm reset code and vector.\n"); store_NMI_vector(&nmi_high, &nmi_low); smpboot_setup_warm_reset_vector(start_eip); /* * Starting actual IPI sequence... */ boot_error = wakeup_secondary_cpu(apicid, start_eip); if (!boot_error) { /* * allow APs to start initializing. */ Dprintk("Before Callout %d.\n", cpu); cpu_set(cpu, cpu_callout_map); Dprintk("After Callout %d.\n", cpu); /* * Wait 5s total for a response */ for (timeout = 0; timeout < 50000; timeout++) { if (cpu_isset(cpu, cpu_callin_map)) break; /* It has booted */ udelay(100); } if (cpu_isset(cpu, cpu_callin_map)) { /* number CPUs logically, starting from 1 (BSP is 0) */ Dprintk("OK.\n"); printk("CPU%d: ", cpu); print_cpu_info(&cpu_data[cpu]); Dprintk("CPU has booted.\n"); } else { boot_error = 1; mb(); if (bootsym(trampoline_cpu_started) == 0xA5) /* trampoline started but...? */ printk("Stuck ??\n"); else /* trampoline code not run */ printk("Not responding.\n"); inquire_remote_apic(apicid); } } if (boot_error) { /* Try to put things back the way they were before ... */ unmap_cpu_to_logical_apicid(cpu); cpu_clear(cpu, cpu_callout_map); /* was set here (do_boot_cpu()) */ cpu_clear(cpu, cpu_initialized); /* was set by cpu_init() */ cpucount--; } else { x86_cpu_to_apicid[cpu] = apicid; cpu_set(cpu, cpu_present_map); } /* mark "stuck" area as not stuck */ bootsym(trampoline_cpu_started) = 0; mb(); return boot_error;}#ifdef CONFIG_HOTPLUG_CPUstatic void idle_task_exit(void){ /* Give up lazy state borrowed by this idle vcpu */ __sync_lazy_execstate();}void cpu_exit_clear(void){ int cpu = raw_smp_processor_id(); idle_task_exit(); cpucount --; cpu_uninit(); cpu_clear(cpu, cpu_callout_map); cpu_clear(cpu, cpu_callin_map); cpu_clear(cpu, smp_commenced_mask); unmap_cpu_to_logical_apicid(cpu);}static int __cpuinit __smp_prepare_cpu(int cpu){ int apicid, ret; apicid = x86_cpu_to_apicid[cpu]; if (apicid == BAD_APICID) { ret = -ENODEV; goto exit; } tsc_sync_disabled = 1; do_boot_cpu(apicid, cpu); tsc_sync_disabled = 0; ret = 0;exit: return ret;}#endif/* * Cycle through the processors sending APIC IPIs to boot each. *//* Where the IO area was mapped on multiquad, always 0 otherwise */void *xquad_portio;#ifdef CONFIG_X86_NUMAQEXPORT_SYMBOL(xquad_portio);#endifstatic void __init smp_boot_cpus(unsigned int max_cpus){ int apicid, cpu, bit, kicked;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -