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()を実行している。