📄 htab.c
字号:
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; HPTE *hptep; vsid = get_kernel_vsid(ea); va = (vsid << 28) | (ea & 0x0fffffff); vpn = va >> PAGE_SHIFT; slot = hpte_find(vpn); if (slot == -1) panic("could not find page to bolt\n"); hptep = htab_data.htab + slot; set_pp_bit(newpp, hptep); /* Ensure it is out of the tlb too */ spin_lock_irqsave(&pSeries_tlbie_lock, flags); _tlbie(va, 0); spin_unlock_irqrestore(&pSeries_tlbie_lock, flags);}static void rpa_lpar_hpte_updateboltedpp(unsigned long newpp, unsigned long ea){ unsigned long lpar_rc; unsigned long vsid, va, vpn, flags; long slot; vsid = get_kernel_vsid(ea); va = (vsid << 28) | (ea & 0x0fffffff); vpn = va >> PAGE_SHIFT; slot = rpa_lpar_hpte_find(vpn); if (slot == -1) panic("updateboltedpp: Could not find page to bolt\n"); flags = newpp & 3; lpar_rc = plpar_pte_protect(flags, slot, 0); if (lpar_rc != H_Success) panic("Bad return code from pte bolted protect rc = %lx\n", lpar_rc); }void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea){ unsigned long vsid,va,vpn; long slot; vsid = get_kernel_vsid( ea ); va = ( vsid << 28 ) | ( ea & 0x0fffffff ); vpn = va >> PAGE_SHIFT; slot = iSeries_hpte_find(vpn); if (slot == -1) panic("updateboltedpp: Could not find page to bolt\n"); HvCallHpt_setPp(slot, newpp);}/* * Functions used to insert new hardware page table entries. * Will castout non-bolted entries as necessary using a random * algorithm. * * Input : vpn : virtual page number * prpn : real page number in absolute space * hpteflags: page protection flags * bolted : 1 = bolt the page * large : 1 = large page (16M) * Output: hsss, where h = hash group, sss = slot within that group */static long hpte_insert(unsigned long vpn, unsigned long prpn, unsigned long hpteflags, int bolted, int large){ HPTE *hptep; Hpte_dword0 dw0; HPTE lhpte; int i, secondary; unsigned long hash = hpt_hash(vpn, 0); unsigned long avpn = vpn >> 11; unsigned long arpn = physRpn_to_absRpn(prpn); unsigned long hpte_group;repeat: secondary = 0; hpte_group = ((hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL; hptep = htab_data.htab + hpte_group; for (i = 0; i < HPTES_PER_GROUP; i++) { dw0 = hptep->dw0.dw0; if (!dw0.v) { /* retry with lock held */ dw0 = hptep->dw0.dw0; if (!dw0.v) break; } hptep++; } if (i == HPTES_PER_GROUP) { secondary = 1; hpte_group = ((~hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL; hptep = htab_data.htab + hpte_group; for (i = 0; i < HPTES_PER_GROUP; i++) { dw0 = hptep->dw0.dw0; if (!dw0.v) { /* retry with lock held */ dw0 = hptep->dw0.dw0; if (!dw0.v) break; } hptep++; } if (i == HPTES_PER_GROUP) { if (mftb() & 0x1) hpte_group=((hash & htab_data.htab_hash_mask)* HPTES_PER_GROUP) & ~0x7UL; hpte_remove(hpte_group); goto repeat; } } lhpte.dw1.dword1 = 0; lhpte.dw1.dw1.rpn = arpn; lhpte.dw1.flags.flags = hpteflags; lhpte.dw0.dword0 = 0; lhpte.dw0.dw0.avpn = avpn; lhpte.dw0.dw0.h = secondary; lhpte.dw0.dw0.bolted = bolted; lhpte.dw0.dw0.v = 1; if (large) lhpte.dw0.dw0.l = 1; hptep->dw1.dword1 = lhpte.dw1.dword1; /* Guarantee the second dword is visible before the valid bit */ __asm__ __volatile__ ("eieio" : : : "memory"); /* * Now set the first dword including the valid bit * NOTE: this also unlocks the hpte */ hptep->dw0.dword0 = lhpte.dw0.dword0; __asm__ __volatile__ ("ptesync" : : : "memory"); return ((secondary << 3) | i);}static long rpa_lpar_hpte_insert(unsigned long vpn, unsigned long prpn, unsigned long hpteflags, int bolted, int large){ /* XXX fix for large page */ unsigned long lpar_rc; unsigned long flags; unsigned long slot; HPTE lhpte; int secondary; unsigned long hash = hpt_hash(vpn, 0); unsigned long avpn = vpn >> 11; unsigned long arpn = physRpn_to_absRpn(prpn); unsigned long hpte_group; /* Fill in the local HPTE with absolute rpn, avpn and flags */ lhpte.dw1.dword1 = 0; lhpte.dw1.dw1.rpn = arpn; lhpte.dw1.flags.flags = hpteflags; lhpte.dw0.dword0 = 0; lhpte.dw0.dw0.avpn = avpn; lhpte.dw0.dw0.bolted = bolted; lhpte.dw0.dw0.v = 1; if (large) lhpte.dw0.dw0.l = 1; /* Now fill in the actual HPTE */ /* Set CEC cookie to 0 */ /* Large page = 0 */ /* Zero page = 0 */ /* I-cache Invalidate = 0 */ /* I-cache synchronize = 0 */ /* Exact = 0 */ flags = 0; /* XXX why is this here? - Anton */ /* -- Because at one point we hit a case where non cachable * pages where marked coherent & this is rejected by the HV. * Perhaps it is no longer an issue ... DRENG. */ if (hpteflags & (_PAGE_GUARDED|_PAGE_NO_CACHE)) lhpte.dw1.flags.flags &= ~_PAGE_COHERENT;repeat: secondary = 0; lhpte.dw0.dw0.h = secondary; hpte_group = ((hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL; __asm__ __volatile__ ( H_ENTER_r3 "mr 4, %2\n" "mr 5, %3\n" "mr 6, %4\n" "mr 7, %5\n" HVSC "mr %0, 3\n" "mr %1, 4\n" : "=r" (lpar_rc), "=r" (slot) : "r" (flags), "r" (hpte_group), "r" (lhpte.dw0.dword0), "r" (lhpte.dw1.dword1) : "r0", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "cc"); if (lpar_rc == H_PTEG_Full) { secondary = 1; lhpte.dw0.dw0.h = secondary; hpte_group = ((~hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL; __asm__ __volatile__ ( H_ENTER_r3 "mr 4, %2\n" "mr 5, %3\n" "mr 6, %4\n" "mr 7, %5\n" HVSC "mr %0, 3\n" "mr %1, 4\n" : "=r" (lpar_rc), "=r" (slot) : "r" (flags), "r" (hpte_group), "r" (lhpte.dw0.dword0), "r" (lhpte.dw1.dword1) : "r0", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "cc"); if (lpar_rc == H_PTEG_Full) { if (mftb() & 0x1) hpte_group=((hash & htab_data.htab_hash_mask)* HPTES_PER_GROUP) & ~0x7UL; rpa_lpar_hpte_remove(hpte_group); goto repeat; } } if (lpar_rc != H_Success) panic("Bad return code from pte enter rc = %lx\n", lpar_rc); return ((secondary << 3) | (slot & 0x7));}static long iSeries_hpte_insert(unsigned long vpn, unsigned long prpn, unsigned long hpteflags, int bolted, int large){ HPTE lhpte; unsigned long hash, hpte_group; unsigned long avpn = vpn >> 11; unsigned long arpn = physRpn_to_absRpn( prpn ); int secondary = 0; long slot; hash = hpt_hash(vpn, 0);repeat: slot = HvCallHpt_findValid(&lhpte, vpn); if (lhpte.dw0.dw0.v) { panic("select_hpte_slot found entry already valid\n"); } if (slot == -1) { /* No available entry found in either group */ if (mftb() & 0x1) { hpte_group=((hash & htab_data.htab_hash_mask)* HPTES_PER_GROUP) & ~0x7UL; } else { hpte_group=((~hash & htab_data.htab_hash_mask)* HPTES_PER_GROUP) & ~0x7UL; } hash = hpt_hash(vpn, 0); iSeries_hpte_remove(hpte_group); goto repeat; } else if (slot < 0) { slot &= 0x7fffffffffffffff; secondary = 1; } /* Create the HPTE */ lhpte.dw1.dword1 = 0; lhpte.dw1.dw1.rpn = arpn; lhpte.dw1.flags.flags = hpteflags; lhpte.dw0.dword0 = 0; lhpte.dw0.dw0.avpn = avpn; lhpte.dw0.dw0.h = secondary; lhpte.dw0.dw0.bolted = bolted; lhpte.dw0.dw0.v = 1; /* Now fill in the actual HPTE */ HvCallHpt_addValidate(slot, secondary, (HPTE *)&lhpte); return ((secondary << 3) | (slot & 0x7));}/* * Functions used to remove hardware page table entries. * * Input : hpte_group: PTE index of the first entry in a group * Output: offset within the group of the entry removed or * -1 on failure */static long hpte_remove(unsigned long hpte_group){ HPTE *hptep; Hpte_dword0 dw0; int i; int slot_offset; unsigned long vsid, group, pi, pi_high; unsigned long slot; unsigned long flags; int large; unsigned long va; /* pick a random slot to start at */ slot_offset = mftb() & 0x7; for (i = 0; i < HPTES_PER_GROUP; i++) { hptep = htab_data.htab + hpte_group + slot_offset; dw0 = hptep->dw0.dw0; if (dw0.v && !dw0.bolted) { /* retry with lock held */ dw0 = hptep->dw0.dw0; if (dw0.v && !dw0.bolted) break; } slot_offset++; slot_offset &= 0x7; } if (i == HPTES_PER_GROUP) return -1; large = dw0.l; /* Invalidate the hpte. NOTE: this also unlocks it */ hptep->dw0.dword0 = 0; /* Invalidate the tlb */ vsid = dw0.avpn >> 5; slot = hptep - htab_data.htab; group = slot >> 3; if (dw0.h) group = ~group; pi = (vsid ^ group) & 0x7ff; pi_high = (dw0.avpn & 0x1f) << 11; pi |= pi_high; if (large) va = pi << LARGE_PAGE_SHIFT; else va = pi << PAGE_SHIFT; spin_lock_irqsave(&pSeries_tlbie_lock, flags); _tlbie(va, large); spin_unlock_irqrestore(&pSeries_tlbie_lock, flags); return i;}static long rpa_lpar_hpte_remove(unsigned long hpte_group){ unsigned long slot_offset; unsigned long lpar_rc; int i; unsigned long dummy1, dummy2; /* pick a random slot to start at */ slot_offset = mftb() & 0x7; for (i = 0; i < HPTES_PER_GROUP; i++) { /* Don't remove a bolted entry */ lpar_rc = plpar_pte_remove(H_ANDCOND, hpte_group + slot_offset, (0x1UL << 4), &dummy1, &dummy2); if (lpar_rc == H_Success) return i; if (lpar_rc != H_Not_Found) panic("Bad return code from pte remove rc = %lx\n", lpar_rc); slot_offset++; slot_offset &= 0x7; } return -1;}static long iSeries_hpte_remove(unsigned long hpte_group){ unsigned long slot_offset; int i; HPTE lhpte; /* Pick a random slot to start at */ slot_offset = mftb() & 0x7; for (i = 0; i < HPTES_PER_GROUP; i++) { lhpte.dw0.dword0 = iSeries_hpte_getword0(hpte_group + slot_offset); if (!lhpte.dw0.dw0.bolted) { HvCallHpt_invalidateSetSwBitsGet(hpte_group + slot_offset, 0, 0); return i; } slot_offset++; slot_offset &= 0x7; } return -1;}void hpte_init_pSeries(void){ ppc_md.hpte_invalidate = hpte_invalidate; ppc_md.hpte_updatepp = hpte_updatepp; ppc_md.hpte_updateboltedpp = hpte_updateboltedpp; ppc_md.hpte_insert = hpte_insert; ppc_md.hpte_remove = hpte_remove;}void pSeries_lpar_mm_init(void){ ppc_md.hpte_invalidate = rpa_lpar_hpte_invalidate; ppc_md.hpte_updatepp = rpa_lpar_hpte_updatepp; ppc_md.hpte_updateboltedpp = rpa_lpar_hpte_updateboltedpp; ppc_md.hpte_insert = rpa_lpar_hpte_insert; ppc_md.hpte_remove = rpa_lpar_hpte_remove;}void hpte_init_iSeries(void){ ppc_md.hpte_invalidate = iSeries_hpte_invalidate; ppc_md.hpte_updatepp = iSeries_hpte_updatepp; ppc_md.hpte_updateboltedpp = iSeries_hpte_updateboltedpp; ppc_md.hpte_insert = iSeries_hpte_insert; ppc_md.hpte_remove = iSeries_hpte_remove;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -