FreeBSD-current/mipsのSMP実装#仮想メモリ編の補足

pmapのSMP対応の所をもう少し詳しく見てみた。

static void
pmap_invalidate_all(pmap_t pmap)
{
#ifdef SMP
	smp_rendezvous(0, pmap_invalidate_all_action, 0, (void *)pmap);
}

static void
pmap_invalidate_all_action(void *arg)
{
	pmap_t pmap = (pmap_t)arg;

#endif

	if (pmap->pm_active & PCPU_GET(cpumask)) {
		pmap_TLB_invalidate_all();
	} else
		pmap->pm_asid[PCPU_GET(cpuid)].gen = 0;
}

pmap_TLB_invalidate_all()はmips_TBIAP()の別名。
全CPUでmips_TBIAP()を呼び出す事になる模様。
アプリケーション終了時に同じASIDのTLBエントリを全部消す為にあるのかな?

struct pmap_invalidate_page_arg {
	pmap_t pmap;
	vm_offset_t va;
};

static __inline void
pmap_invalidate_page(pmap_t pmap, vm_offset_t va)
{
#ifdef SMP
	struct pmap_invalidate_page_arg arg;

	arg.pmap = pmap;
	arg.va = va;

	smp_rendezvous(0, pmap_invalidate_page_action, 0, (void *)&arg);
}

static void
pmap_invalidate_page_action(void *arg)
{
	pmap_t pmap = ((struct pmap_invalidate_page_arg *)arg)->pmap;
	vm_offset_t va = ((struct pmap_invalidate_page_arg *)arg)->va;

#endif

	if (is_kernel_pmap(pmap)) {
		pmap_TLB_invalidate_kernel(va);
		return;
	}
	if (pmap->pm_asid[PCPU_GET(cpuid)].gen != PCPU_GET(asid_generation))
		return;
	else if (!(pmap->pm_active & PCPU_GET(cpumask))) {
		pmap->pm_asid[PCPU_GET(cpuid)].gen = 0;
		return;
	}
	va = pmap_va_asid(pmap, (va & ~PGOFSET));
	mips_TBIS(va);
}

static void
pmap_TLB_invalidate_kernel(vm_offset_t va)
{
	u_int32_t pid;

	MachTLBGetPID(pid);
	va = va | (pid << VMTLB_PID_SHIFT);
	mips_TBIS(va);
}

pmapがkernel_pmapかどうかで処理が分かれるが、最終的にmips_TBIS()を実行している。

struct pmap_update_page_arg {
	pmap_t pmap;
	vm_offset_t va;
	pt_entry_t pte;
};

void
pmap_update_page(pmap_t pmap, vm_offset_t va, pt_entry_t pte)
{
#ifdef SMP
	struct pmap_update_page_arg arg;

	arg.pmap = pmap;
	arg.va = va;
	arg.pte = pte;

	smp_rendezvous(0, pmap_update_page_action, 0, (void *)&arg);
}

static void
pmap_update_page_action(void *arg)
{
	pmap_t pmap = ((struct pmap_update_page_arg *)arg)->pmap;
	vm_offset_t va = ((struct pmap_update_page_arg *)arg)->va;
	pt_entry_t pte = ((struct pmap_update_page_arg *)arg)->pte;

#endif
	if (is_kernel_pmap(pmap)) {
		pmap_TLB_update_kernel(va, pte);
		return;
	}
	if (pmap->pm_asid[PCPU_GET(cpuid)].gen != PCPU_GET(asid_generation))
		return;
	else if (!(pmap->pm_active & PCPU_GET(cpumask))) {
		pmap->pm_asid[PCPU_GET(cpuid)].gen = 0;
		return;
	}
	va = pmap_va_asid(pmap, va);
	MachTLBUpdate(va, pte);
}

static void
pmap_TLB_update_kernel(vm_offset_t va, pt_entry_t pte)
{
	u_int32_t pid;

	MachTLBGetPID(pid);
	va = va | (pid << VMTLB_PID_SHIFT);

	MachTLBUpdate(va, pte);
}

pmapがkernel_pmapかどうかで処理が分かれるが、最終的にMachTLBUpdate()を実行している。