curcpu()の仕様を変えたい in OpenBSD/sgi
OpenBSDでカレントプロセッサのcpu_info(※per-CPUなデータを保存する構造体)のポインタを取得するにはcurcpu()というマクロを呼ぶのだが、現状のOpenBSD/sgiではこんな風になっている:
#define curcpu() cpu_info[cpu_number()]
で、cpu_number()はハードウェアレジスタを読んでCPUの物理IDを取得している。
が、先日書いたようにOrigin 350においては物理IDとautoconfで割り当てるIDを分けたい。
また、curcpu()の度に毎回物理IDをロードして配列からポインタを取り出すのはあまり速くはない。
出来ればあるレジスタにポインタが入ってて、取り出すだけで使えるというような状態だと嬉しい。
ここで、CP0のLLAddrレジスタが未使用で使えるという話が以前からあった。
しかし、32bit幅なので64bitポインタをツッコむにはちょっと工夫が必要。でも不可能じゃない。
この二点を一度に解決するパッチを書いた。
Index: mips64/include/asm.h =================================================================== RCS file: /cvs/src/sys/arch/mips64/include/asm.h,v retrieving revision 1.10 diff -u -p -r1.10 asm.h --- mips64/include/asm.h 9 Jan 2010 23:34:29 -0000 1.10 +++ mips64/include/asm.h 25 Apr 2010 20:53:02 -0000 @@ -299,11 +299,9 @@ x: ; \ #ifdef MULTIPROCESSOR #define GET_CPU_INFO(ci, tmp) \ - HW_CPU_NUMBER(tmp); \ - PTR_SLL tmp, tmp, LOGREGSZ; \ - LA ci, cpu_info; \ - PTR_ADDU ci, ci, tmp; \ - PTR_L ci, 0(ci) + LOAD_XKPHYS(ci, CCA_CACHED); \ + mfc0 tmp, COP_0_LLADDR; \ + or ci, ci, tmp #else /* MULTIPROCESSOR */ #define GET_CPU_INFO(ci, tmp) \ LA ci, cpu_info_primary
curcpu()のアセンブリ版マクロ。
ここで、配列からポインタを取り出す代わりにLLADDRからポインタを取り出し64bitアドレスを復元。
Index: mips64/include/cpu.h =================================================================== RCS file: /cvs/src/sys/arch/mips64/include/cpu.h,v retrieving revision 1.57 diff -u -p -r1.57 cpu.h --- mips64/include/cpu.h 28 Feb 2010 18:01:36 -0000 1.57 +++ mips64/include/cpu.h 25 Apr 2010 20:53:02 -0000 @@ -428,18 +428,22 @@ extern struct cpu_info *cpu_info_list; #ifdef MULTIPROCESSOR #define MAXCPUS 4 -#define curcpu() (cpu_info[cpu_number()]) +extern struct cpu_info *getcurcpu(void); +extern void setcurcpu(struct cpu_info *); +#ifdef DEBUG +extern struct cpu_info *get_cpu_info(int); +#endif +#define curcpu() getcurcpu() #define CPU_IS_PRIMARY(ci) ((ci)->ci_flags & CPUF_PRIMARY) -#define cpu_number() hw_cpu_number() +#define cpu_number() (curcpu()->ci_cpuid) extern struct cpuset cpus_running; -extern struct cpu_info *cpu_info[]; void cpu_unidle(struct cpu_info *); void cpu_boot_secondary_processors(void); #define cpu_boot_secondary(ci) hw_cpu_boot_secondary(ci) #define cpu_hatch(ci) hw_cpu_hatch(ci) -vaddr_t smp_malloc(size_t); +vaddr_t alloc_contiguous_pages(size_t); #define MIPS64_IPI_NOP 0x00000001 #define MIPS64_IPI_RENDEZVOUS 0x00000002
cpu_info[]配列を削除。代わりにlladdrへアクセスするgetcurcpu(), setcurcpu(ci)を追加。
curcpu()はgetcurcpu()を呼ぶだけ。
Index: mips64/mips64/context.S =================================================================== RCS file: /cvs/src/sys/arch/mips64/mips64/context.S,v retrieving revision 1.44 diff -u -p -r1.44 context.S --- mips64/mips64/context.S 13 Feb 2010 14:04:45 -0000 1.44 +++ mips64/mips64/context.S 25 Apr 2010 20:53:03 -0000 @@ -145,7 +145,8 @@ NON_LEAF(cpu_switchto_asm, FRAMESZ(CF_SZ PTR_L t0, P_VMSPACE(s0) # p->p_vmspace PTR_L t1, VMSPACE_PMAP(t0) # ->vm_map.pmap #ifdef MULTIPROCESSOR - HW_CPU_NUMBER(v0) # cpuid + GET_CPU_INFO(v0, t2) + PTR_L v0, CI_CPUID(v0) PTR_SLL v0, v0, 0x3 # size of pmap_asid_info PTR_ADDU t1, t1, v0 #endif
物理IDをコードから排除。全てautoconfの番号へ。
Index: mips64/mips64/cp0access.S =================================================================== RCS file: /cvs/src/sys/arch/mips64/mips64/cp0access.S,v retrieving revision 1.12 diff -u -p -r1.12 cp0access.S --- mips64/mips64/cp0access.S 9 Jan 2010 23:34:29 -0000 1.12 +++ mips64/mips64/cp0access.S 25 Apr 2010 20:53:03 -0000 @@ -192,3 +192,17 @@ LEAF(cp0_setperfctrl, 0) j ra nop END(cp0_setperfctrl) + +#ifdef MULTIPROCESSOR +LEAF(getcurcpu, 0) + GET_CPU_INFO(v0, v1) + jr ra +END(getcurcpu) + +LEAF(setcurcpu, 0) + mtc0 a0, COP_0_LLADDR + nop; nop + j ra + nop +END(setcurcpu) +#endif
getcurcpu(), setcurcpu()の実体。
単にLLADDRへアクセスするだけ。
Index: mips64/mips64/cpu.c =================================================================== RCS file: /cvs/src/sys/arch/mips64/mips64/cpu.c,v retrieving revision 1.28 diff -u -p -r1.28 cpu.c --- mips64/mips64/cpu.c 28 Mar 2010 17:09:36 -0000 1.28 +++ mips64/mips64/cpu.c 25 Apr 2010 20:53:03 -0000 @@ -41,15 +41,9 @@ void cpuattach(struct device *, struct d struct cpu_info cpu_info_primary; struct cpu_info *cpu_info_list = &cpu_info_primary; +struct cpu_info *cpu_info_secondaries; #ifdef MULTIPROCESSOR struct cpuset 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 vaddr_t CpuCacheAliasMask; @@ -91,18 +85,19 @@ cpuattach(struct device *parent, struct #ifdef MULTIPROCESSOR ci->ci_flags |= CPUF_RUNNING | CPUF_PRESENT | CPUF_PRIMARY; cpuset_add(&cpus_running, ci); + cpu_info_secondaries = (struct cpu_info *)alloc_contiguous_pages( + sizeof(struct cpu_info) * ncpusfound - 1); + if (cpu_info_secondaries == NULL) + panic("unable to allocate cpu_info\n"); + bzero((char *)cpu_info_secondaries, sizeof(struct cpu_info) * ncpusfound - 1); #endif } #ifdef MULTIPROCESSOR else { - ci = (struct cpu_info *)smp_malloc(sizeof(*ci)); - if (ci == NULL) - panic("unable to allocate cpu_info\n"); - bzero((char *)ci, sizeof(*ci)); + ci = &cpu_info_secondaries[cpuno - 1]; ci->ci_next = cpu_info_list->ci_next; cpu_info_list->ci_next = ci; ci->ci_flags |= CPUF_PRESENT; - cpu_info[cpuno] = ci; } #endif ci->ci_self = ci; @@ -373,16 +368,28 @@ save_fpu(void) } #ifdef MULTIPROCESSOR +#ifdef DEBUG +struct cpu_info * +get_cpu_info(int cpuno) +{ + struct cpu_info *ci; + CPU_INFO_ITERATOR cii; + + CPU_INFO_FOREACH(cii, ci) { + if (ci->ci_cpuid == cpuno) + return ci; + } + return NULL; +} +#endif + void cpu_boot_secondary_processors(void) { struct cpu_info *ci; - u_long i; + CPU_INFO_ITERATOR cii; - for (i = 0; i < MAXCPUS; i++) { - ci = cpu_info[i]; - if (ci == NULL) - continue; + CPU_INFO_FOREACH(cii, ci) { if ((ci->ci_flags & CPUF_PRESENT) == 0) continue; if (ci->ci_flags & CPUF_PRIMARY) @@ -391,7 +398,7 @@ cpu_boot_secondary_processors(void) sched_init_cpu(ci); ci->ci_randseed = random(); cpu_boot_secondary(ci); - } + } /* This must called after xheart0 has initialized, so here is * the best place to do so. @@ -407,31 +414,21 @@ cpu_unidle(struct cpu_info *ci) } vaddr_t -smp_malloc(size_t size) +alloc_contiguous_pages(size_t size) { - struct pglist mlist; - struct vm_page *m; - int error; - vaddr_t va; - paddr_t pa; - - if (size < PAGE_SIZE) { - va = (vaddr_t)malloc(size, M_DEVBUF, M_NOWAIT); - if (va == NULL) - return NULL; - error = pmap_extract(pmap_kernel(), va, &pa); - if (error == FALSE) - return NULL; - } else { - TAILQ_INIT(&mlist); - error = uvm_pglistalloc(size, 0, -1L, 0, 0, - &mlist, 1, UVM_PLA_NOWAIT); - if (error) - return NULL; - m = TAILQ_FIRST(&mlist); - pa = VM_PAGE_TO_PHYS(m); - } + struct pglist mlist; + struct vm_page *m; + int error; + paddr_t pa; + + TAILQ_INIT(&mlist); + error = uvm_pglistalloc(size, 0, -1, 0, 0, + &mlist, 1, UVM_PLA_NOWAIT); + if (error) + return NULL; + m = TAILQ_FIRST(&mlist); + pa = VM_PAGE_TO_PHYS(m); - return PHYS_TO_XKPHYS(pa, CCA_CACHED); + return PHYS_TO_XKPHYS(pa, CCA_CACHED); } #endif
複数の問題を一度に片付けていて少々ややこしくなっている。
まず、cpu_info[]をやめた。
lladdrが32bit幅な関係上、smp_malloc()内でアロケート出来るのは32bit空間で表現出来るアドレスまでなので、位置が指定できないmalloc()をやめてuvm_pglistalloc()だけにする。
ページ単位でアロケートしなければならなくなったので、毎度呼ぶのをやめて一括でcpu_info_secondariesへアロケートすることに。
なので関数名もalloc_contiguous_pages()へ変えてみた。
Index: mips64/mips64/genassym.cf =================================================================== RCS file: /cvs/src/sys/arch/mips64/mips64/genassym.cf,v retrieving revision 1.6 diff -u -p -r1.6 genassym.cf --- mips64/mips64/genassym.cf 9 Jan 2010 23:43:43 -0000 1.6 +++ mips64/mips64/genassym.cf 25 Apr 2010 20:53:03 -0000 @@ -58,6 +58,7 @@ member pcb_onfault member pcb_segtab struct cpu_info +member ci_cpuid member ci_curproc member ci_curprocpaddr member ci_fpuproc
CI_CPUIDマクロの生成。
Index: mips64/mips64/ipifuncs.c =================================================================== RCS file: /cvs/src/sys/arch/mips64/mips64/ipifuncs.c,v retrieving revision 1.3 diff -u -p -r1.3 ipifuncs.c --- mips64/mips64/ipifuncs.c 21 Apr 2010 14:57:11 -0000 1.3 +++ mips64/mips64/ipifuncs.c 25 Apr 2010 20:53:03 -0000 @@ -119,10 +119,10 @@ mips64_ipi_intr(void *arg) void mips64_send_ipi(unsigned int cpuid, unsigned int ipimask) { -#ifdef DIAGNOSTIC - if (cpuid >= CPU_MAXID || cpu_info[cpuid] == NULL) +#ifdef DEBUG + if (cpuid >= CPU_MAXID || get_cpu_info(cpuid) == NULL) panic("mips_send_ipi: bogus cpu_id"); - if (!cpuset_isset(&cpus_running, cpu_info[cpuid])) + if (!cpuset_isset(&cpus_running, get_cpu_info(cpuid))) panic("mips_send_ipi: CPU %ld not running", cpuid); #endif
cpu_info[]の排除。
代わりにcpu.cへget_cpu_info()を用意した。
Index: sgi/include/asm.h =================================================================== RCS file: /cvs/src/sys/arch/sgi/include/asm.h,v retrieving revision 1.2 diff -u -p -r1.2 asm.h --- sgi/include/asm.h 30 Sep 2009 06:22:00 -0000 1.2 +++ sgi/include/asm.h 25 Apr 2010 20:53:03 -0000 @@ -2,13 +2,4 @@ /* Use Mips generic include file */ -#ifdef MULTIPROCESSOR -#define HW_CPU_NUMBER(reg) \ - LA reg, HW_CPU_NUMBER_REG; \ - PTR_L reg, 0(reg) -#else /* MULTIPROCESSOR */ -#define HW_CPU_NUMBER(reg) \ - LI reg, 0 -#endif /* MULTIPROCESSOR */ - #include <mips64/asm.h>
物理IDの排除。
Index: sgi/include/cpu.h =================================================================== RCS file: /cvs/src/sys/arch/sgi/include/cpu.h,v retrieving revision 1.8 diff -u -p -r1.8 cpu.h --- sgi/include/cpu.h 9 Jan 2010 23:34:29 -0000 1.8 +++ sgi/include/cpu.h 25 Apr 2010 20:53:03 -0000 @@ -45,16 +45,7 @@ #define _SGI_CPU_H_ #ifdef _KERNEL - -#ifdef MULTIPROCESSOR - -#if defined(TGT_OCTANE) -#define HW_CPU_NUMBER_REG 0x900000000ff50000 /* HEART_PRID */ -#else -#error MULTIPROCESSOR kernel not supported on this configuration -#endif - -#if !defined(_LOCORE) +#if defined(MULTIPROCESSOR) && !defined(_LOCORE) struct cpu_info; void hw_cpu_boot_secondary(struct cpu_info *); void hw_cpu_hatch(struct cpu_info *); @@ -62,15 +53,7 @@ void hw_cpu_spinup_trampoline(struct cpu int hw_ipi_intr_establish(int (*)(void *), u_long); void hw_ipi_intr_set(u_long); void hw_ipi_intr_clear(u_long); -#endif - -#define hw_cpu_number() (*(uint64_t *)HW_CPU_NUMBER_REG) - -#else /* MULTIPROCESSOR */ - -#define hw_cpu_number() 0 - -#endif /* MULTIPROCESSOR */ +#endif /* MULTIPROCESSOR && !_LOCORE */ /* * Define soft selected cache functions.
物理IDの排除。
Index: sgi/sgi/ip30_machdep.c =================================================================== RCS file: /cvs/src/sys/arch/sgi/sgi/ip30_machdep.c,v retrieving revision 1.41 diff -u -p -r1.41 ip30_machdep.c --- sgi/sgi/ip30_machdep.c 21 Apr 2010 14:57:11 -0000 1.41 +++ sgi/sgi/ip30_machdep.c 25 Apr 2010 20:53:03 -0000 @@ -531,7 +531,7 @@ hw_cpu_boot_secondary(struct cpu_info *c scachesz, fanloads, launch, rndvz, stackaddr, lparam, rparam, idleflag); #endif - kstack = smp_malloc(USPACE); + kstack = alloc_contiguous_pages(USPACE); if (kstack == NULL) panic("unable to allocate idle stack\n"); bzero((char *)kstack, USPACE); @@ -552,6 +552,11 @@ void hw_cpu_hatch(struct cpu_info *ci) { int s; + + /* + * Set curcpu address on this processor. + */ + setcurcpu(ci); /* * Make sure we can access the extended address space.
smp_malloc()の名称変更、あと重要なlladdrへのcurcpuのセット。
Index: sgi/sgi/ip30_nmi.S =================================================================== RCS file: /cvs/src/sys/arch/sgi/sgi/ip30_nmi.S,v retrieving revision 1.2 diff -u -p -r1.2 ip30_nmi.S --- sgi/sgi/ip30_nmi.S 13 Jan 2010 23:24:27 -0000 1.2 +++ sgi/sgi/ip30_nmi.S 25 Apr 2010 20:53:03 -0000 @@ -23,9 +23,7 @@ #include <arch/sgi/sgi/ip30.h> -#ifndef MULTIPROCESSOR #define HW_CPU_NUMBER_REG 0x900000000ff50000 /* HEART_PRID */ -#endif #include "assym.h"
つじつま合わせ。
Index: sgi/sgi/machdep.c =================================================================== RCS file: /cvs/src/sys/arch/sgi/sgi/machdep.c,v retrieving revision 1.100 diff -u -p -r1.100 machdep.c --- sgi/sgi/machdep.c 3 Mar 2010 12:25:09 -0000 1.100 +++ sgi/sgi/machdep.c 25 Apr 2010 20:53:04 -0000 @@ -150,6 +150,11 @@ mips_init(int argc, void *argv, caddr_t extern char *hw_vendor; /* + * Set curcpu address on primary processor. + */ + setcurcpu(&cpu_info_primary); + + /* * 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.
こちらも重要なlladdrへのセット。