void initialize_cpus(struct bus *cpu_bus) { struct device_path cpu_path; struct cpu_info *info; /* Find the info struct for this CPU */ info = cpu_info(); if (need_lapic_init()) { /* Ensure the local APIC is enabled */ enable_lapic(); /* Get the device path of the boot CPU */ cpu_path.type = DEVICE_PATH_APIC; cpu_path.apic.apic_id = lapicid(); } else { /* Get the device path of the boot CPU */ cpu_path.type = DEVICE_PATH_CPU; cpu_path.cpu.id = 0; } /* Find the device structure for the boot CPU */ info->cpu = alloc_find_dev(cpu_bus, &cpu_path); // why here? In case some day we can start core1 in amd_sibling_init if (is_smp_boot()) copy_secondary_start_to_lowest_1M(); if (!IS_ENABLED(CONFIG_SERIALIZED_SMM_INITIALIZATION)) smm_init(); /* start all aps at first, so we can init ECC all together */ if (is_smp_boot() && IS_ENABLED(CONFIG_PARALLEL_CPU_INIT)) start_other_cpus(cpu_bus, info->cpu); /* Initialize the bootstrap processor */ cpu_initialize(0); if (is_smp_boot() && !IS_ENABLED(CONFIG_PARALLEL_CPU_INIT)) { start_other_cpus(cpu_bus, info->cpu); /* Now wait the rest of the cpus stop*/ wait_other_cpus_stop(cpu_bus); } if (IS_ENABLED(CONFIG_SERIALIZED_SMM_INITIALIZATION)) { /* At this point, all APs are sleeping: * smm_init() will queue a pending SMI on all cpus * and smm_other_cpus() will start them one by one */ smm_init(); if (is_smp_boot()) { last_cpu_index = 0; smm_other_cpus(cpu_bus, info->cpu); } } smm_init_completion(); if (is_smp_boot()) recover_lowest_1M(); }
/* * Now running in a thread. Create the rest of the kernel threads * and the bootstrap task. */ void start_kernel_threads(void) { register int i; /* * Create the idle threads and the other * service threads. */ for (i = 0; i < NCPUS; i++) { if (machine_slot[i].is_cpu) { thread_t th; spl_t s; processor_t processor = cpu_to_processor(i); (void) thread_create_at(kernel_task, &th, idle_thread); s=splsched(); thread_lock(th); thread_bind_locked(th, processor); processor->idle_thread = th; /*(void) thread_resume(th->top_act);*/ th->state |= TH_RUN; thread_setrun( th, TRUE, TAIL_Q); thread_unlock( th ); splx(s); } } (void) kernel_thread(kernel_task, reaper_thread, (char *) 0); #if THREAD_SWAPPER (void) kernel_thread(kernel_task, swapin_thread, (char *) 0); (void) kernel_thread(kernel_task, swapout_thread, (char *) 0); #endif /* THREAD_SWAPPER */ #if TASK_SWAPPER if (task_swap_on) { (void) kernel_thread(kernel_task, task_swapper, (char *) 0); (void) kernel_thread(kernel_task, task_swap_swapout_thread, (char *) 0); } #endif /* TASK_SWAPPER */ (void) kernel_thread(kernel_task, sched_thread, (char *) 0); (void) kernel_thread(kernel_task, timeout_thread, (char *) 0); #if NORMA_VM (void) kernel_thread(kernel_task, vm_object_thread, (char *) 0); #endif /* NORMA_VM */ /* * Create the clock service. */ clock_service_create(); /* * Create the device service. */ device_service_create(); /* * Initialize distributed services, starting * with distributed IPC and progressing to any * services layered on top of that. * * This stub exists even in non-NORMA systems. */ norma_bootstrap(); /* * Initialize any testing services blocking the main kernel * thread so that the in-kernel tests run without interference * from other boot time activities. We will resume this thread * in kernel_test_thread(). */ #if KERNEL_TEST /* * Initialize the lock that will be used to guard * variables that will be used in the test synchronization * scheme. */ simple_lock_init(&kernel_test_lock, ETAP_MISC_KERNEL_TEST); #if PARAGON860 { char *s; unsigned int firstnode; /* * Only start up loopback tests on boot node. */ if ((s = (char *) getbootenv("BOOT_FIRST_NODE")) == 0) panic("startup"); firstnode = atoi(s); (void) kernel_thread(kernel_task, kernel_test_thread, (char * )(dipc_node_self() == (node_name) firstnode)); } #else /* PARAGON860 */ (void) kernel_thread(kernel_task, kernel_test_thread, (char *) 0); #endif /* PARAGON860 */ { /* * The synchronization scheme uses a simple lock, two * booleans and the wakeup event. The wakeup event will * be posted by kernel_test_thread(). */ spl_t s; s = splsched(); simple_lock(&kernel_test_lock); while(!kernel_test_thread_sync_done){ assert_wait((event_t) &start_kernel_threads, FALSE); start_kernel_threads_blocked = TRUE; simple_unlock(&kernel_test_lock); splx(s); thread_block((void (*)(void)) 0); s = splsched(); simple_lock(&kernel_test_lock); start_kernel_threads_blocked = FALSE; } kernel_test_thread_sync_done = FALSE; /* Reset for next use */ simple_unlock(&kernel_test_lock); splx(s); } #endif /* KERNEL_TEST */ /* * Start the user bootstrap. */ bootstrap_create(); #if XPR_DEBUG xprinit(); /* XXX */ #endif /* XPR_DEBUG */ #if NCPUS > 1 /* * Create the shutdown thread. */ (void) kernel_thread(kernel_task, action_thread, (char *) 0); /* * Allow other CPUs to run. * * (this must be last, to allow bootstrap_create to fiddle with * its child thread before some cpu tries to run it) */ start_other_cpus(); #endif /* NCPUS > 1 */ /* * Become the pageout daemon. */ (void) spllo(); vm_pageout(); /*NOTREACHED*/ }
void main(void) { proc_t *p = ttoproc(curthread); /* &p0 */ int (**initptr)(); extern void sched(); extern void fsflush(); extern int (*init_tbl[])(); extern int (*mp_init_tbl[])(); extern id_t syscid, defaultcid; extern int swaploaded; extern int netboot; extern ib_boot_prop_t *iscsiboot_prop; extern void vm_init(void); extern void cbe_init_pre(void); extern void cbe_init(void); extern void clock_tick_init_pre(void); extern void clock_tick_init_post(void); extern void clock_init(void); extern void physio_bufs_init(void); extern void pm_cfb_setup_intr(void); extern int pm_adjust_timestamps(dev_info_t *, void *); extern void start_other_cpus(int); extern void sysevent_evc_thrinit(); extern kmutex_t ualock; #if defined(__x86) extern void fastboot_post_startup(void); extern void progressbar_start(void); #endif /* * In the horrible world of x86 in-lines, you can't get symbolic * structure offsets a la genassym. This assertion is here so * that the next poor slob who innocently changes the offset of * cpu_thread doesn't waste as much time as I just did finding * out that it's hard-coded in i86/ml/i86.il. Similarly for * curcpup. You're welcome. */ ASSERT(CPU == CPU->cpu_self); ASSERT(curthread == CPU->cpu_thread); ASSERT_STACK_ALIGNED(); /* * We take the ualock until we have completed the startup * to prevent kadmin() from disrupting this work. In particular, * we don't want kadmin() to bring the system down while we are * trying to start it up. */ mutex_enter(&ualock); /* * Setup root lgroup and leaf lgroup for CPU 0 */ lgrp_init(LGRP_INIT_STAGE2); /* * Once 'startup()' completes, the thread_reaper() daemon would be * created(in thread_init()). After that, it is safe to create threads * that could exit. These exited threads will get reaped. */ startup(); segkmem_gc(); callb_init(); cbe_init_pre(); /* x86 must initialize gethrtimef before timer_init */ ddi_periodic_init(); cbe_init(); callout_init(); /* callout table MUST be init'd after cyclics */ clock_tick_init_pre(); clock_init(); #if defined(__x86) /* * The progressbar thread uses cv_reltimedwait() and hence needs to be * started after the callout mechanism has been initialized. */ progressbar_start(); #endif /* * On some platforms, clkinitf() changes the timing source that * gethrtime_unscaled() uses to generate timestamps. cbe_init() calls * clkinitf(), so re-initialize the microstate counters after the * timesource has been chosen. */ init_mstate(&t0, LMS_SYSTEM); init_cpu_mstate(CPU, CMS_SYSTEM); /* * May need to probe to determine latencies from CPU 0 after * gethrtime() comes alive in cbe_init() and before enabling interrupts * and copy and release any temporary memory allocated with BOP_ALLOC() * before release_bootstrap() frees boot memory */ lgrp_init(LGRP_INIT_STAGE3); /* * Call all system initialization functions. */ for (initptr = &init_tbl[0]; *initptr; initptr++) (**initptr)(); /* * Load iSCSI boot properties */ ld_ib_prop(); /* * initialize vm related stuff. */ vm_init(); /* * initialize buffer pool for raw I/O requests */ physio_bufs_init(); ttolwp(curthread)->lwp_error = 0; /* XXX kludge for SCSI driver */ /* * Drop the interrupt level and allow interrupts. At this point * the DDI guarantees that interrupts are enabled. */ (void) spl0(); interrupts_unleashed = 1; /* * Create kmem cache for proc structures */ process_cache = kmem_cache_create("process_cache", sizeof (proc_t), 0, NULL, NULL, NULL, NULL, NULL, 0); vfs_mountroot(); /* Mount the root file system */ errorq_init(); /* after vfs_mountroot() so DDI root is ready */ cpu_kstat_init(CPU); /* after vfs_mountroot() so TOD is valid */ ddi_walk_devs(ddi_root_node(), pm_adjust_timestamps, NULL); /* after vfs_mountroot() so hrestime is valid */ post_startup(); swaploaded = 1; /* * Initialize Solaris Audit Subsystem */ audit_init(); /* * Plumb the protocol modules and drivers only if we are not * networked booted, in this case we already did it in rootconf(). */ if (netboot == 0 && iscsiboot_prop == NULL) (void) strplumb(); gethrestime(&PTOU(curproc)->u_start); curthread->t_start = PTOU(curproc)->u_start.tv_sec; p->p_mstart = gethrtime(); /* * Perform setup functions that can only be done after root * and swap have been set up. */ consconfig(); #ifndef __sparc release_bootstrap(); #endif /* * attach drivers with ddi-forceattach prop * It must be done early enough to load hotplug drivers (e.g. * pcmcia nexus) so that devices enumerated via hotplug is * available before I/O subsystem is fully initialized. */ i_ddi_forceattach_drivers(); /* * Set the scan rate and other parameters of the paging subsystem. */ setupclock(0); /* * Initialize process 0's lwp directory and lwpid hash table. */ p->p_lwpdir = p->p_lwpfree = p0_lwpdir; p->p_lwpdir->ld_next = p->p_lwpdir + 1; p->p_lwpdir_sz = 2; p->p_tidhash = p0_tidhash; p->p_tidhash_sz = 2; p0_lep.le_thread = curthread; p0_lep.le_lwpid = curthread->t_tid; p0_lep.le_start = curthread->t_start; lwp_hash_in(p, &p0_lep, p0_tidhash, 2, 0); /* * Initialize extended accounting. */ exacct_init(); /* * Initialize threads of sysevent event channels */ sysevent_evc_thrinit(); /* * This must be done after post_startup() but before * start_other_cpus() */ lgrp_init(LGRP_INIT_STAGE4); /* * Perform MP initialization, if any. */ start_other_cpus(0); #ifdef __sparc /* * Release bootstrap here since PROM interfaces are * used to start other CPUs above. */ release_bootstrap(); #endif /* * Finish lgrp initialization after all CPUS are brought online. */ lgrp_init(LGRP_INIT_STAGE5); /* * After mp_init(), number of cpus are known (this is * true for the time being, when there are actually * hot pluggable cpus then this scheme would not do). * Any per cpu initialization is done here. */ kmem_mp_init(); vmem_update(NULL); clock_tick_init_post(); for (initptr = &mp_init_tbl[0]; *initptr; initptr++) (**initptr)(); /* * These must be called after start_other_cpus */ pm_cfb_setup_intr(); #if defined(__x86) fastboot_post_startup(); #endif /* * Make init process; enter scheduling loop with system process. * * Note that we manually assign the pids for these processes, for * historical reasons. If more pre-assigned pids are needed, * FAMOUS_PIDS will have to be updated. */ /* create init process */ if (newproc(start_init, NULL, defaultcid, 59, NULL, FAMOUS_PID_INIT)) panic("main: unable to fork init."); /* create pageout daemon */ if (newproc(pageout, NULL, syscid, maxclsyspri - 1, NULL, FAMOUS_PID_PAGEOUT)) panic("main: unable to fork pageout()"); /* create fsflush daemon */ if (newproc(fsflush, NULL, syscid, minclsyspri, NULL, FAMOUS_PID_FSFLUSH)) panic("main: unable to fork fsflush()"); /* create cluster process if we're a member of one */ if (cluster_bootflags & CLUSTER_BOOTED) { if (newproc(cluster_wrapper, NULL, syscid, minclsyspri, NULL, 0)) { panic("main: unable to fork cluster()"); } } /* * Create system threads (threads are associated with p0) */ /* create module uninstall daemon */ /* BugID 1132273. If swapping over NFS need a bigger stack */ (void) thread_create(NULL, 0, (void (*)())mod_uninstall_daemon, NULL, 0, &p0, TS_RUN, minclsyspri); (void) thread_create(NULL, 0, seg_pasync_thread, NULL, 0, &p0, TS_RUN, minclsyspri); pid_setmin(); /* system is now ready */ mutex_exit(&ualock); bcopy("sched", PTOU(curproc)->u_psargs, 6); bcopy("sched", PTOU(curproc)->u_comm, 5); sched(); /* NOTREACHED */ }
/* * Now running in a thread. Create the rest of the kernel threads * and the bootstrap task. */ void start_kernel_threads() { register int i; /* * Create the idle threads and the other * service threads. */ for (i = 0; i < NCPUS; i++) { if (machine_slot[i].is_cpu) { thread_t th; (void) thread_create(kernel_task, &th); thread_bind(th, cpu_to_processor(i)); thread_start(th, idle_thread); thread_doswapin(th); (void) thread_resume(th); } } (void) kernel_thread(kernel_task, reaper_thread, (char *) 0); (void) kernel_thread(kernel_task, swapin_thread, (char *) 0); (void) kernel_thread(kernel_task, sched_thread, (char *) 0); #if NCPUS > 1 /* * Create the shutdown thread. */ (void) kernel_thread(kernel_task, action_thread, (char *) 0); /* * Allow other CPUs to run. */ start_other_cpus(); #endif NCPUS > 1 /* * Create the device service. */ device_service_create(); /* * Initialize NORMA ipc system. */ #if NORMA_IPC norma_ipc_init(); #endif NORMA_IPC /* * Initialize NORMA vm system. */ #if NORMA_VM norma_vm_init(); #endif NORMA_VM /* * Start the user bootstrap. */ bootstrap_create(); #if XPR_DEBUG xprinit(); /* XXX */ #endif XPR_DEBUG /* * Become the pageout daemon. */ (void) spl0(); vm_pageout(); /*NOTREACHED*/ }
/* * Now running in a thread. Create the rest of the kernel threads * and the bootstrap task. */ void start_kernel_threads() { register int i; /* * Create the idle threads and the other * service threads. */ for (i = 0; i < NCPUS; i++) { if (machine_slot[i].is_cpu) { thread_t th; (void) thread_create(kernel_task, &th); thread_bind(th, cpu_to_processor(i)); thread_start(th, idle_thread); thread_doswapin(th); (void) thread_resume(th); } } (void) kernel_thread(kernel_task, reaper_thread, (char *) 0); (void) kernel_thread(kernel_task, swapin_thread, (char *) 0); (void) kernel_thread(kernel_task, sched_thread, (char *) 0); #if NCPUS > 1 /* * Create the shutdown thread. */ (void) kernel_thread(kernel_task, action_thread, (char *) 0); /* * Allow other CPUs to run. */ start_other_cpus(); #endif /* NCPUS > 1 */ /* * Create the device service. */ device_service_create(); /* * Initialize kernel task's creation time. * When we created the kernel task in task_init, the mapped * time was not yet available. Now, last thing before starting * the user bootstrap, record the current time as the kernel * task's creation time. */ record_time_stamp (&kernel_task->creation_time); /* * Start the user bootstrap. */ bootstrap_create(); #if XPR_DEBUG xprinit(); /* XXX */ #endif /* XPR_DEBUG */ /* * Become the pageout daemon. */ (void) spl0(); vm_pageout(); /*NOTREACHED*/ }