NetBSD-5.0BETA/i386のSMP実装#2
カーネルの主な初期化処理はsys/kern/init_main.cのmain()から始まるが、この中でconfigure()が呼ばれている場所がある:
/* Configure the system hardware. This will enable interrupts. */
configure();
configure()はsys/kern/subr_autoconf.cにあり、この中でconfig_init()を呼ぶ事で一連のデバイス検出・アタッチを行っているものと思われる:
/* Initialize data structures. */
config_init();
/* * Initialize the autoconfiguration data structures. Normally this * is done by configure(), but some platforms need to do this very * early (to e.g. initialize the console). */ void config_init(void) { const struct cfattachinit *cfai; int i, j; if (config_initialized) return; mutex_init(&alldevs_mtx, MUTEX_DEFAULT, IPL_NONE); cv_init(&alldevs_cv, "alldevs"); mutex_init(&config_misc_lock, MUTEX_DEFAULT, IPL_NONE); cv_init(&config_misc_cv, "cfgmisc"); /* allcfdrivers is statically initialized. */ for (i = 0; cfdriver_list_initial[i] != NULL; i++) { if (config_cfdriver_attach(cfdriver_list_initial[i]) != 0) panic("configure: duplicate `%s' drivers", cfdriver_list_initial[i]->cd_name); } for (cfai = &cfattachinit[0]; cfai->cfai_name != NULL; cfai++) { for (j = 0; cfai->cfai_list[j] != NULL; j++) { if (config_cfattach_attach(cfai->cfai_name, cfai->cfai_list[j]) != 0) panic("configure: duplicate `%s' attachment " "of `%s' driver", cfai->cfai_list[j]->ca_name, cfai->cfai_name); } } initcftable.ct_cfdata = cfdata; TAILQ_INSERT_TAIL(&allcftables, &initcftable, ct_list); config_initialized = 1; }
カーネル内にスタティックに保持されているコンフィグテーブルを山椒して、config_cfdriver_attach()を呼ぶ事によりデバイスをアタッチしていっている。
この後にcpu_configure()を呼んでいる:
/* * Do the machine-dependent portion of autoconfiguration. This * sets the configuration machinery here in motion by "finding" * the root bus. When this function returns, we expect interrupts * to be enabled. */ cpu_configure();
cpu_configure()はコメントにも書いてある通り、ハードウェア依存なオートコンフィグ関連処理を行うものだが、ここでもSMP対応の処理が行われているっぽい。
#ifdef MULTIPROCESSOR /* propagate this to the idle pcb's. */ cpu_init_idle_lwps(); #endif
cpu_init_idle_lwps()はsys/kern/arch/x86/x86/cpu.cにあり、中でcpu_init_idle_lwp()を呼んでいる:
static void cpu_init_idle_lwp(struct cpu_info *ci) { struct lwp *l = ci->ci_data.cpu_idlelwp; struct pcb *pcb = &l->l_addr->u_pcb; pcb->pcb_cr0 = rcr0(); } void cpu_init_idle_lwps(void) { struct cpu_info *ci; u_long i; for (i = 0; i < maxcpus; i++) { ci = cpu_lookup(i); if (ci == NULL) continue; if (ci->ci_data.cpu_idlelwp == NULL) continue; if ((ci->ci_flags & CPUF_PRESENT) == 0) continue; cpu_init_idle_lwp(ci); } }
init_idle_lwpという名前はついているものの、実際にやっている事は単に現在のcr0レジスタの内容をpcbにコピーしているだけの模様。