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にコピーしているだけの模様。