OpenBSD/sgi on octane2 - clock割り込み
cpu1でclock割り込みを起こしてみた。
cpu_hatchでcpu_initclocks()を呼び、statusレジスタで割り込み有効にする。
void prom_cpu_hatch(struct cpu_info *ci) { char *cp; void *gp, *sp; asm volatile( "move %0, $gp\n" "move %1, $sp\n" : "=r"(gp), "=r"(sp)); int cpuid = cpu_number(); combinit(); combprintf("comb initialized by cpu%d\n", cpuid); combprintf("ci:%p\n", ci); combprintf("gp:%p\n", gp); combprintf("sp:%p\n", sp); /* * Make sure we can access the extended address space. * Note that r10k and later do not allow XUSEG accesses * from kernel mode unless SR_UX is set. */ setsr(getsr() | SR_KX | SR_UX); combprintf("[%s:%s:%d]\n", __FILE__, __func__, __LINE__); /* * Determine system type and set up configuration record data. */ sys_config.cpu[cpuid].clock = 175000000; /* Reasonable default */ cp = Bios_GetEnvironmentVariable("cpufreq"); if (cp && atoi(cp, 10, NULL) > 100) sys_config.cpu[cpuid].clock = atoi(cp, 10, NULL) * 1000000; combprintf("[%s:%s:%d]\n", __FILE__, __func__, __LINE__); sys_config.cpu[cpuid].type = (cp0_get_prid() >> 8) & 0xff; sys_config.cpu[cpuid].vers_maj = (cp0_get_prid() >> 4) & 0x0f; sys_config.cpu[cpuid].vers_min = cp0_get_prid() & 0x0f; sys_config.cpu[cpuid].fptype = (cp1_get_prid() >> 8) & 0xff; sys_config.cpu[cpuid].fpvers_maj = (cp1_get_prid() >> 4) & 0x0f; sys_config.cpu[cpuid].fpvers_min = cp1_get_prid() & 0x0f; sys_config.cpu[cpuid].tlbsize = 64; combprintf("[%s:%s:%d]\n", __FILE__, __func__, __LINE__); Mips10k_ConfigCache(); combprintf("[%s:%s:%d]\n", __FILE__, __func__, __LINE__); /* * Last chance to call the BIOS. Wiping the TLB means the BIOS' data * areas are demapped on most systems. O2s are okay as they do not have * mapped BIOS text or data. */ delay(20*1000); /* Let any UART FIFO drain... */ combprintf("[%s:%s:%d]\n", __FILE__, __func__, __LINE__); sys_config.cpu[cpuid].tlbwired = UPAGES / 2; tlb_set_wired(0); combprintf("[%s:%s:%d]\n", __FILE__, __func__, __LINE__); tlb_flush(sys_config.cpu[cpuid].tlbsize); combprintf("[%s:%s:%d]\n", __FILE__, __func__, __LINE__); tlb_set_wired(sys_config.cpu[cpuid].tlbwired); combprintf("[%s:%s:%d]\n", __FILE__, __func__, __LINE__); /* XXX does it correct? */ tlb_set_pid(1); combprintf("[%s:%s:%d]\n", __FILE__, __func__, __LINE__); /* * Turn off bootstrap exception vectors. */ setsr(getsr() & ~SR_BOOT_EXC_VEC); combprintf("[%s:%s:%d]\n", __FILE__, __func__, __LINE__); /* * Clear out the I and D caches. */ Mips_SyncCache(); combprintf("[%s:%s:%d]\n", __FILE__, __func__, __LINE__); cpu_initclocks(); setsr(getsr() | SR_INT_ENAB | SR_INT_MASK); while(1) ; }
cpu_initclocks()では初期化に必要な処理をひとしきり行い、最後にcp0_set_compare()を実行する。ここで設定されたカウンタ値に応じて次の割り込みが発生する。
void cpu_initclocks() { struct cpu_info *ci = curcpu(); struct tod_desc *cd = &sys_tod; struct tod_time ct; u_int first_cp0, second_cp0, cycles_per_sec; int first_sec; int s; hz = 100; profhz = 100; stathz = 0; /* XXX no stat clock yet */ /* * Calibrate the cycle counter frequency. */ if (cd->tod_get != NULL) { (*cd->tod_get)(cd->tod_cookie, 0, &ct); first_sec = ct.sec; /* Let the clock tick one second. */ do { first_cp0 = cp0_get_count(); (*cd->tod_get)(cd->tod_cookie, 0, &ct); } while (ct.sec == first_sec); first_sec = ct.sec; /* Let the clock tick one more second. */ do { second_cp0 = cp0_get_count(); (*cd->tod_get)(cd->tod_cookie, 0, &ct); } while (ct.sec == first_sec); cycles_per_sec = second_cp0 - first_cp0; sys_config.cpu[0].clock = cycles_per_sec * 2; } tick = 1000000 / hz; /* number of micro-seconds between interrupts */ tickadj = 240000 / (60 * hz); /* can adjust 240ms in 60s */ cp0_timecounter.tc_frequency = sys_config.cpu[0].clock / 2; tc_init(&cp0_timecounter); /* Start the clock. */ s = splclock(); ci->ci_cpu_counter_interval = cp0_timecounter.tc_frequency / hz; ci->ci_cpu_counter_last = cp0_get_count() + ci->ci_cpu_counter_interval; cp0_set_compare(ci->ci_cpu_counter_last); ci->ci_clock_started++; splx(s); }
割り込みハンドラルーチンに、combprintf()を仕込んでcpu1へ割り込みが着たらinterruptと表示させる。
extern int combprintf(const char *fmt, ...); void interrupt(struct trap_frame *trapframe) { struct cpu_info *ci = curcpu(); u_int32_t pending; u_int32_t cause; int i; intrmask_t xcpl; /* * Paranoic? Perhaps. But if we got here with the enable * bit reset a mtc0 COP_0_STATUS_REG may have been interrupted. * If this was a disable and the pipeline had advanced long * enough... i don't know but better safe than sorry... * The main effect is not the interrupts but the spl mechanism. */ if (!(trapframe->sr & SR_INT_ENAB)) { return; } if (cpu_number()) combprintf("interrupt\n");
かくして、com1の出力はinterruptという文字だらけになったのであった。
めでたしめでたし。
これでIPIのテストにとりかかれるな。