NetBSD-5.0BETA/macppcのSMP実装を駆け足で#2

駆け足でみていったらやっぱり抜けが有ったので、引き続きmacppcについて眺めてみようと思う。

	/*
	 * Initialize cpu_info[0]
	 */
	INIT_CPUINFO(4,1,9,0)

	lis	3,__start@ha
	addi	3,3,__start@l
	mr	5,6			/* args string */
	bl	_C_LABEL(initppc)

locore.Sのエントリポイントからinitppc()が呼ばれている。

void
initppc(u_int startkernel, u_int endkernel, char *args)
{
	ofwoea_initppc(startkernel, endkernel, args);
}

macppcのinitppc()はofwoea_initppc()を呼ぶだけのラッパー関数になっている。

void
ofwoea_initppc(u_int startkernel, u_int endkernel, char *args)
{
	int ofmaplen, node, l;
	register_t scratch;

#if defined(MULTIPROCESSOR) && defined(ofppc)
	char cpupath[32];
	int i;
#endif

	/* initialze bats */
	if ((oeacpufeat & OEACPU_NOBAT) == 0)
		ofwoea_batinit();

#if NKSYMS || defined(DDB) || defined(LKM)
	/* get info of kernel symbol table from bootloader */
	memcpy(&startsym, args + strlen(args) + 1, sizeof(startsym));
	memcpy(&endsym, args + strlen(args) + 1 + sizeof(startsym),
	    sizeof(endsym));
	if (startsym == NULL || endsym == NULL)
	    startsym = endsym = NULL;
#endif

	/* get model name and perform model-specific actions */
	memset(model_name, 0, sizeof(model_name));
	node = OF_finddevice("/");
	if (node >= 0) {
		l = OF_getprop(node, "model", model_name, sizeof(model_name));
		if (l == -1)
			OF_getprop(node, "name", model_name,
			    sizeof(model_name));
		model_init();
	}

	ofwoea_consinit();

#if defined(MULTIPROCESSOR) && defined(ofppc)
	for (i=1; i < CPU_MAXNUM; i++) {
		sprintf(cpupath, "/cpus/@%x", i);
		node = OF_finddevice(cpupath);
		if (node <= 0)
			continue;
		aprint_verbose("Starting up CPU %d %s\n", i, cpupath);
		OF_start_cpu(node, (u_int)cpu_spinstart, i);
		for (l=0; l < 100000000; l++) {
			if (cpu_spinstart_ack == i) {
				aprint_verbose("CPU %d spun up.\n", i);
				break;
			}
			__asm volatile ("sync");
		}
	}
#endif

	oea_init(pic_ext_intr);

	ofmaplen = save_ofmap(NULL, 0);
	if (ofmaplen > 0)
		save_ofmap(ofmap, ofmaplen);

	ofmsr &= ~PSL_IP;

	/* Parse the args string */
	if (args) {
		strcpy(bootpath, args);
		args = bootpath;
		while (*++args && *args != ' ');
		if (*args) {
			*args++ = 0;
			while (*args)
				BOOT_FLAG(*args++, boothowto);
		}
	}

	uvm_setpagesize();

#if defined (PPC_OEA64_BRIDGE) && defined (PPC_OEA)
	if (oeacpufeat & OEACPU_64_BRIDGE)
		pmap_setup64bridge();
	else
		pmap_setup32();
#endif
	pmap_bootstrap(startkernel, endkernel);

/* as far as I can tell, the pmap_setup_seg0 stuff is horribly broken */
#if defined(PPC_OEA64) || defined (PPC_OEA64_BRIDGE)
#if defined (PMAC_G5)
	/* Mapin 1st 256MB segment 1:1, also map in mem needed to access OFW*/
	if (oeacpufeat & OEACPU_64_BRIDGE)
		pmap_setup_segment0_map(0, 0xff800000, 0x3fc00000, 0x400000,
		    0x0);
#elif defined (MAMBO)
	/* Mapin 1st 256MB segment 1:1, also map in mem needed to access OFW*/
	if (oeacpufeat & OEACPU_64_BRIDGE)
		pmap_setup_segment0_map(0, 0xf4000000, 0xf4000000, 0x1000, 0x0);
#endif /* PMAC_G5 */
#endif /* PPC_OEA64 || PPC_OEA64_BRIDGE */

	/* Now enable translation (and machine checks/recoverable interrupts) */
	__asm __volatile ("sync; mfmsr %0; ori %0,%0,%1; mtmsr %0; isync"
	    : "=r"(scratch)
	    : "K"(PSL_IR|PSL_DR|PSL_ME|PSL_RI));

	restore_ofmap(ofmap, ofmaplen);

#if NKSYMS || defined(DDB) || defined(LKM)
	ksyms_init((int)((u_int)endsym - (u_int)startsym), startsym, endsym);
#endif

	/* CPU clock stuff */
	set_timebase();
}

MULTIPROCESSORがoptionで定義されている時は、cpuの数の分だけOF_start_cpu()を呼んでいる。引数にエントリポイントのcpu_spinstart()が指定されているようだ。
昨日はcpu_spinup_trampoline()がエントリポイントとして指定されているようだと書いたのだが、よくよくみると#ifdef OPENPICと書いてあるのでmacppcはOPENPICではなくてopenfirmwareで初期化している、という事だろう。

#ifdef MULTIPROCESSOR
void
OF_start_cpu(int phandle, u_int pc, int arg)
{
	static struct {
		const char *name;
		int nargs;
		int nreturns;
		int phandle;
		u_int pc;
		int arg;
	} args = {
		"start-cpu",
		3,
		0,
	};
	ofw_stack();
	args.phandle = phandle;
	args.pc = pc;
	args.arg = arg;
	if (openfirmware(&args) == -1)
		panic("WTF?");
}
#endif

OF_start_cpu()は簡潔な作りになっていて、CPU idとエントリポイントと引数を渡しopenfirmwareを叩くだけのようだ。

ENTRY(cpu_spinstart)
	li	%r0,0
	mtmsr	%r0
	lis	%r5,oeacpufeat@ha
	lwz	%r5,oeacpufeat@l(%r5)
	andi.	%r5,%r5,OEACPU_64_BRIDGE
	beq	4f
	sync
	slbia
	sync
	isync
	clrldi	%r0,%r0,32
	mtmsrd	%r0
	mtspr	SPR_ASR,%r0
4:	
	lis	%r5,_C_LABEL(cpu_spinstart_ack)@ha
	addi	%r5,%r5,_C_LABEL(cpu_spinstart_ack)@l
	stw	%r3,0(%r5)
	dcbf	0,%r5
	lis	%r6,_C_LABEL(cpu_spinstart_cpunum)@ha
5:
	lwz	%r4,_C_LABEL(cpu_spinstart_cpunum)@l(%r6)
	cmpw	%r4,%r3
	bne	5b
	lis	%r4,_C_LABEL(cpu_hatch_stack)@ha
	lwz	%r1,_C_LABEL(cpu_hatch_stack)@l(%r4)
	bla	_C_LABEL(cpu_hatch)
	mr	%r1,%r3	/* move the return from cpu_hatch to the stackpointer*/
	b	_C_LABEL(idle_loop)

#endif /*MULTIPROCESSOR + OEA*/

ppcアセンブリが読めないので何がどうなのかよく分からないが、恐らくは簡単な初期化をやって引数を積んでcpu_hatch()を呼んでいるだけだろう。