📄 htab.c
字号:
pgdir = mm->pgd; if (pgdir == NULL) return 1; /* * Lock the Linux page table to prevent mmap and kswapd * from modifying entries while we search and update */ spin_lock(&mm->page_table_lock); ptep = find_linux_pte(pgdir, ea); /* * If no pte found or not present, send the problem up to * do_page_fault */ if (ptep && pte_present(*ptep)) { ret = __hash_page(ea, access, vsid, ptep); } else { /* If no pte, send the problem up to do_page_fault */ ret = 1; } spin_unlock(&mm->page_table_lock); return ret;}void flush_hash_page(unsigned long context, unsigned long ea, pte_t *ptep){ unsigned long vsid, vpn, va, hash, secondary, slot, flags; unsigned long large = 0, local = 0; pte_t pte; if ((ea >= USER_START) && (ea <= USER_END)) vsid = get_vsid(context, ea); else vsid = get_kernel_vsid(ea); va = (vsid << 28) | (ea & 0x0fffffff); if (large) vpn = va >> LARGE_PAGE_SHIFT; else vpn = va >> PAGE_SHIFT; hash = hpt_hash(vpn, large); spin_lock_irqsave( &hash_table_lock, flags); pte = __pte(pte_update(ptep, _PAGE_HPTEFLAGS, 0)); secondary = (pte_val(pte) & _PAGE_SECONDARY) >> 15; if (secondary) hash = ~hash; slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP; slot += (pte_val(pte) & _PAGE_GROUP_IX) >> 12; if (pte_val(pte) & _PAGE_HASHPTE) { ppc_md.hpte_invalidate(slot, secondary, va, large, local); } spin_unlock_irqrestore( &hash_table_lock, flags );}long plpar_pte_enter(unsigned long flags, unsigned long ptex, unsigned long new_pteh, unsigned long new_ptel, unsigned long *old_pteh_ret, unsigned long *old_ptel_ret){ unsigned long dummy, ret; ret = plpar_hcall(H_ENTER, flags, ptex, new_pteh, new_ptel, old_pteh_ret, old_ptel_ret, &dummy); return(ret);}long plpar_pte_remove(unsigned long flags, unsigned long ptex, unsigned long avpn, unsigned long *old_pteh_ret, unsigned long *old_ptel_ret){ unsigned long dummy; return plpar_hcall(H_REMOVE, flags, ptex, avpn, 0, old_pteh_ret, old_ptel_ret, &dummy);}long plpar_pte_read(unsigned long flags, unsigned long ptex, unsigned long *old_pteh_ret, unsigned long *old_ptel_ret){ unsigned long dummy; return plpar_hcall(H_READ, flags, ptex, 0, 0, old_pteh_ret, old_ptel_ret, &dummy);}long plpar_pte_protect(unsigned long flags, unsigned long ptex, unsigned long avpn){ return plpar_hcall_norets(H_PROTECT, flags, ptex, avpn);}static __inline__ void set_pp_bit(unsigned long pp, HPTE *addr){ unsigned long old; unsigned long *p = &addr->dw1.dword1; __asm__ __volatile__( "1: ldarx %0,0,%3\n\ rldimi %0,%2,0,62\n\ stdcx. %0,0,%3\n\ bne 1b" : "=&r" (old), "=m" (*p) : "r" (pp), "r" (p), "m" (*p) : "cc");}/* * Functions used to retrieve word 0 of a given page table entry. * * Input : slot : PTE index within the page table of the entry to retrieve * Output: Contents of word 0 of the specified entry */static unsigned long rpa_lpar_hpte_getword0(unsigned long slot){ unsigned long dword0; unsigned long lpar_rc; unsigned long dummy_word1; unsigned long flags; /* Read 1 pte at a time */ /* Do not need RPN to logical page translation */ /* No cross CEC PFT access */ flags = 0; lpar_rc = plpar_pte_read(flags, slot, &dword0, &dummy_word1); if (lpar_rc != H_Success) panic("Error on pte read in get_hpte0 rc = %lx\n", lpar_rc); return dword0;}unsigned long iSeries_hpte_getword0(unsigned long slot){ unsigned long dword0; HPTE hpte; HvCallHpt_get(&hpte, slot); dword0 = hpte.dw0.dword0; return dword0;}/* * Functions used to find the PTE for a particular virtual address. * Only used during boot when bolting pages. * * Input : vpn : virtual page number * Output: PTE index within the page table of the entry * -1 on failure */static long hpte_find(unsigned long vpn){ HPTE *hptep; unsigned long hash; unsigned long i, j; long slot; Hpte_dword0 dw0; hash = hpt_hash(vpn, 0); for (j = 0; j < 2; j++) { slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP; for (i = 0; i < HPTES_PER_GROUP; i++) { hptep = htab_data.htab + slot; dw0 = hptep->dw0.dw0; if ((dw0.avpn == (vpn >> 11)) && dw0.v && (dw0.h == j)) { /* HPTE matches */ if (j) slot = -slot; return slot; } ++slot; } hash = ~hash; } return -1;}static long rpa_lpar_hpte_find(unsigned long vpn){ unsigned long hash; unsigned long i, j; long slot; union { unsigned long dword0; Hpte_dword0 dw0; } hpte_dw0; Hpte_dword0 dw0; hash = hpt_hash(vpn, 0); for (j = 0; j < 2; j++) { slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP; for (i = 0; i < HPTES_PER_GROUP; i++) { hpte_dw0.dword0 = rpa_lpar_hpte_getword0(slot); dw0 = hpte_dw0.dw0; if ((dw0.avpn == (vpn >> 11)) && dw0.v && (dw0.h == j)) { /* HPTE matches */ if (j) slot = -slot; return slot; } ++slot; } hash = ~hash; } return -1;} static long iSeries_hpte_find(unsigned long vpn){ HPTE hpte; long slot; /* * The HvCallHpt_findValid interface is as follows: * 0xffffffffffffffff : No entry found. * 0x00000000xxxxxxxx : Entry found in primary group, slot x * 0x80000000xxxxxxxx : Entry found in secondary group, slot x */ slot = HvCallHpt_findValid(&hpte, vpn); if (hpte.dw0.dw0.v) { if (slot < 0) { slot &= 0x7fffffffffffffff; slot = -slot; } } else { slot = -1; } return slot;}/* * Functions used to invalidate a page table entry from the page table * and tlb. * * Input : slot : PTE index within the page table of the entry to invalidated * va : Virtual address of the entry being invalidated * large : 1 = large page (16M) * local : 1 = Use tlbiel to only invalidate the local tlb */static void hpte_invalidate(unsigned long slot, unsigned long secondary, unsigned long va, int large, int local){ HPTE *hptep = htab_data.htab + slot; Hpte_dword0 dw0; unsigned long vpn, avpn; unsigned long flags; if (large) vpn = va >> LARGE_PAGE_SHIFT; else vpn = va >> PAGE_SHIFT; avpn = vpn >> 11; dw0 = hptep->dw0.dw0; /* * Do not remove bolted entries. Alternatively, we could check * the AVPN, hash group, and valid bits. By doing it this way, * it is common with the pSeries LPAR optimal path. */ if (dw0.bolted) return; /* Invalidate the hpte. */ hptep->dw0.dword0 = 0; /* Invalidate the tlb */ spin_lock_irqsave(&pSeries_tlbie_lock, flags); _tlbie(va, large); spin_unlock_irqrestore(&pSeries_tlbie_lock, flags);}static void rpa_lpar_hpte_invalidate(unsigned long slot, unsigned long secondary, unsigned long va, int large, int local){ unsigned long lpar_rc; unsigned long dummy1, dummy2; /* * Don't remove a bolted entry. This case can occur when we bolt * pages dynamically after initial boot. */ lpar_rc = plpar_pte_remove(H_ANDCOND, slot, (0x1UL << 4), &dummy1, &dummy2); if (lpar_rc != H_Success) panic("Bad return code from invalidate rc = %lx\n", lpar_rc);}static void iSeries_hpte_invalidate(unsigned long slot, unsigned long secondary, unsigned long va, int large, int local){ HPTE lhpte; unsigned long vpn, avpn; if (large) vpn = va >> LARGE_PAGE_SHIFT; else vpn = va >> PAGE_SHIFT; avpn = vpn >> 11; lhpte.dw0.dword0 = iSeries_hpte_getword0(slot); if ((lhpte.dw0.dw0.avpn == avpn) && (lhpte.dw0.dw0.v) && (lhpte.dw0.dw0.h == secondary)) { HvCallHpt_invalidateSetSwBitsGet(slot, 0, 0); }}/* * Functions used to update page protection bits. * * Input : slot : PTE index within the page table of the entry to update * newpp : new page protection bits * va : Virtual address of the entry being updated * large : 1 = large page (16M) * Output: 0 on success, -1 on failure */static long hpte_updatepp(unsigned long slot, unsigned long secondary, unsigned long newpp, unsigned long va, int large){ HPTE *hptep = htab_data.htab + slot; Hpte_dword0 dw0; Hpte_dword1 dw1; unsigned long vpn, avpn; unsigned long flags; if (large) vpn = va >> LARGE_PAGE_SHIFT; else vpn = va >> PAGE_SHIFT; avpn = vpn >> 11; dw0 = hptep->dw0.dw0; if ((dw0.avpn == avpn) && (dw0.v) && (dw0.h == secondary)) { /* Turn off valid bit in HPTE */ dw0.v = 0; hptep->dw0.dw0 = dw0; /* Ensure it is out of the tlb too */ spin_lock_irqsave(&pSeries_tlbie_lock, flags); _tlbie(va, large); spin_unlock_irqrestore(&pSeries_tlbie_lock, flags); /* Insert the new pp bits into the HPTE */ dw1 = hptep->dw1.dw1; dw1.pp = newpp; hptep->dw1.dw1 = dw1; /* Ensure it is visible before validating */ __asm__ __volatile__ ("eieio" : : : "memory"); /* Turn the valid bit back on in HPTE */ dw0.v = 1; hptep->dw0.dw0 = dw0; __asm__ __volatile__ ("ptesync" : : : "memory"); return 0; } return -1;}static long rpa_lpar_hpte_updatepp(unsigned long slot, unsigned long secondary, unsigned long newpp, unsigned long va, int large){ unsigned long lpar_rc; unsigned long flags = (newpp & 7); unsigned long avpn = va >> 23; HPTE hpte; lpar_rc = plpar_pte_read(0, slot, &hpte.dw0.dword0, &hpte.dw1.dword1); if ((hpte.dw0.dw0.avpn == avpn) && (hpte.dw0.dw0.v) && (hpte.dw0.dw0.h == secondary)) { lpar_rc = plpar_pte_protect(flags, slot, 0); if (lpar_rc != H_Success) panic("bad return code from pte protect rc = %lx\n", lpar_rc); return 0; } return -1;}static long iSeries_hpte_updatepp(unsigned long slot, unsigned long secondary, unsigned long newpp, unsigned long va, int large){ unsigned long vpn, avpn; HPTE hpte; if (large) vpn = va >> LARGE_PAGE_SHIFT; else vpn = va >> PAGE_SHIFT; avpn = vpn >> 11; HvCallHpt_get(&hpte, slot); if ((hpte.dw0.dw0.avpn == avpn) && (hpte.dw0.dw0.v) && (hpte.dw0.dw0.h == secondary)) { HvCallHpt_setPp(slot, newpp); return 0; } return -1;}/* * Functions used to update the page protection bits. Intended to be used * to create guard pages for kernel data structures on pages which are bolted * in the HPT. Assumes pages being operated on will not be stolen. * Does not work on large pages. No need to lock here because we are the * only user. * * Input : newpp : page protection flags * ea : effective kernel address to bolt. */static void hpte_updateboltedpp(unsigned long newpp, unsigned long ea){ unsigned long vsid, va, vpn, flags; long slot;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -