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()を呼んでいるだけだろう。