OpenBSD/sgi on octane2 - cpu_info_primaryへの参照をcpu_info[]への参照に書き換え
mplockの問題が解決したので、SMP非対応な部分の書き換えに進もうと思う。
以前一息に実装してバグがとりきれなかった時のコードが残っているので、これをちょっとずつ適用しながら前に進める。
まず、arch/mips64/include/cpu.hをSMP対応出来るように書き換えていく。
struct cpu_info *cpu_info[]を定義してcurcpu()はcpu_info[cpu_number()]とし、cpu_number()はprom_cpu_number()の別名としておいて機器毎に定義出来るようにした。
struct cpu_info { struct device ci_dev; /* our device */ struct cpu_info *ci_self; /* pointer to this structure */ struct schedstate_percpu ci_schedstate; /* scheduler state */ struct cpu_info *ci_next; /* next cpu */ struct proc *ci_curproc; /* current owner of the processor */ struct user *ci_curprocpaddr; cpuid_t ci_cpuid; /* our CPU ID */ u_int32_t ci_randseed; #ifdef MULTIPROCESSOR u_long ci_flags; /* flags; see below */ #endif int ci_want_resched; intrmask_t ci_cpl; intrmask_t ci_ipending; }; #define CPUF_PRIMARY 0x01 /* CPU is primary CPU */ #define CPUF_PRESENT 0x02 /* CPU is present */ #define CPUF_RUNNING 0x04 /* CPU is running */ extern struct cpu_info cpu_info_primary; extern struct cpu_info *cpu_info_list; #define CPU_INFO_ITERATOR int #define CPU_INFO_FOREACH(cii, ci) for (cii = 0, ci = cpu_info_list; \ ci != NULL; ci = ci->ci_next) #define CPU_INFO_UNIT(ci) ((ci)->ci_dev.dv_unit) #ifdef MULTIPROCESSOR #define MAXCPUS 4 #define curcpu() (cpu_info[cpu_number()]) #define CPU_IS_PRIMARY(ci) ((ci)->ci_flags & CPUF_PRIMARY) #define cpu_number() prom_cpu_number() extern struct cpu_info *cpu_info[]; void cpu_unidle(struct cpu_info *); void cpu_boot_secondary_processors(void); void cpu_boot_secondary(struct cpu_info *); void cpu_hatch(struct cpu_info *); #include <sys/mplock.h> #else #define MAXCPUS 1 #define curcpu() (&cpu_info_primary) #define CPU_IS_PRIMARY(ci) 1 #define cpu_number() 0 #define cpu_unidle(ci) #endif
あと、これはアセンブリからcurcpuを取り出すコード。
cpu_number()はPROM_CPU_NUMBER()というマクロを機器毎に定義してもらう事にする。
#define GET_CPU_INFO(ci, tmp) \ PROM_CPU_NUMBER(tmp); \ dsll tmp, tmp, 0x3; \ dla ci, cpu_info; \ daddu ci, ci, tmp; \ ld ci, 0(ci)
arch/mips64/mips64/cpu.cでは新たに定義した部分のインプリメントを行う。
取り合えず、まだセカンダリCPUが起動できなくてもいいからコンパイルは通るようにしておこう。
こんなのを書き加え、
#ifdef MULTIPROCESSOR __volatile int cpus_running; /* * Array of CPU info structures. Must be statically-allocated because * curproc, etc. are used early. */ struct cpu_info *cpu_info[MAXCPUS] = { &cpu_info_primary }; #endif
attach時の作業も他アーキテクチャを参考にcpu_infoへのポインタ設定、ci_flagsの設定、ci_nextの設定、ci_cpuidの設定などを行うように書き足した。
void cpuattach(struct device *parent, struct device *dev, void *aux) { struct cpu_info *ci = (struct cpu_info *)dev; int cpuno = dev->dv_unit; if(cpuno == 0) { ci = &cpu_info_primary; #ifdef MULTIPROCESSOR ci->ci_flags |= CPUF_RUNNING | CPUF_PRESENT | CPUF_PRIMARY; atomic_setbits_int(&cpus_running, (1UL << cpuno)); #endif bcopy(dev, &ci->ci_dev, sizeof *dev); } #ifdef MULTIPROCESSOR else { ci->ci_next = cpu_info_list->ci_next; cpu_info_list->ci_next = ci; ci->ci_flags |= CPUF_PRESENT; } cpu_info[cpuno] = ci; ncpus++; #endif ci->ci_self = ci; ci->ci_cpuid = cpuno;
セカンダリCPU起動部分は未だstub。
cpu_boot_secondary()とcpu_hatch()は全機種共通には出来そうにないから、それぞれprom_cpu_boot_secondary()とprom_cpu_hatch()を呼ぶように書いておく。
#ifdef MULTIPROCESSOR void cpu_boot_secondary_processors(void) { struct cpu_info *ci; u_long i; // mips64_ipi_init(); for (i = 0; i < MAXCPUS; i++) { ci = cpu_info[i]; if (ci == NULL) continue; if ((ci->ci_flags & CPUF_PRESENT) == 0) continue; if (ci->ci_flags & CPUF_PRIMARY) continue; cpu_boot_secondary(ci); } } void cpu_boot_secondary(struct cpu_info *ci) { u_long cpumask = (1UL << ci->ci_cpuid); prom_cpu_boot_secondary(ci); do asm volatile ("sync"); while(!(cpus_running & cpumask)); } void cpu_hatch(struct cpu_info *ci) { u_long cpumask = (1UL << ci->ci_cpuid); /* * 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); prom_cpu_hatch(ci); atomic_setbits_int(&cpus_running, cpumask); for (;;) ; } void cpu_unidle(struct cpu_info *ci) { /* if(ci != curcpu()) mips64_send_ipi(something); */ }
arch/mips64/include/cpu.hで使う事にしたprom_cpu_number()、PROM_CPU_NUMBER()はarch/sgi/include/cpu.hで定義。
アセンブリ用がこれで、
#define PROM_CPU_NUMBER(reg) \ LA reg, 0x900000000ff50000; \
C用がこれだ。
#define prom_cpu_number() (*(uint64_t *)0x900000000ff50000)
ベタ書きなのは後で何とかするとしよう。
arch/mips64/mips64/cpu.cで呼ぶことにしたprom_cpu_boot_secondary(), prom_cpu_hatch()はarch/sgi/sgi/ip30_machdep.cで定義。
これはOpenBSD/sgi on octane2 - セカンダリCPUが動いた! - かーねる・う゛いえむにっき、OpenBSD/sgi on octane2 - セカンダリCPUの起動とMPCONFについて - かーねる・う゛いえむにっき辺りで書いたネタなので省略。
次に、アセンブリ部分でcpu_info_primary(1番目のCPUのstruct cpu_infoを保存する変数)をcurcpu(現在のCPUのstruct cpu_info *を指すマクロ)として固定的に参照している所を書き換える。
具体的には、arch/mips64/mips64/context.Sの#define curproc (cpu_info_primary + CI_CURPROC)などがそれに当たる。
40,41d39 < #define curproc (cpu_info_primary + CI_CURPROC) < 149,150c148,150 < PTR_S s0, curproc # set curproc --- > GET_CPU_INFO(t1, t0) > PTR_S s0, CI_CURPROC(t1) # set curproc
こんな風に書き換えた。
これだけでももうお腹一杯な感じだが、まだまだ険しい道は続くのであった。