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

こんな風に書き換えた。

これだけでももうお腹一杯な感じだが、まだまだ険しい道は続くのであった。