/* * Bolt the kernel addr space into the HPT */ static void __init iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr) { unsigned long pa; unsigned long mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX; HPTE hpte; for (pa = saddr; pa < eaddr ;pa += PAGE_SIZE) { unsigned long ea = (unsigned long)__va(pa); unsigned long vsid = get_kernel_vsid(ea); unsigned long va = (vsid << 28) | (pa & 0xfffffff); unsigned long vpn = va >> PAGE_SHIFT; unsigned long slot = HvCallHpt_findValid(&hpte, vpn); /* Make non-kernel text non-executable */ if (!in_kernel_text(ea)) mode_rw |= HW_NO_EXEC; if (hpte.dw0.dw0.v) { /* HPTE exists, so just bolt it */ HvCallHpt_setSwBits(slot, 0x10, 0); /* And make sure the pp bits are correct */ HvCallHpt_setPp(slot, PP_RWXX); } else /* No HPTE exists, so create a new bolted one */ iSeries_make_pte(va, phys_to_abs(pa), mode_rw); } }
/* * 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 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; }
/* * Bolt the kernel addr space into the HPT */ static void __init iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr) { unsigned long pa; unsigned long mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX; HPTE hpte; for (pa=saddr; pa < eaddr ;pa+=PAGE_SIZE) { unsigned long ea = (unsigned long)__va(pa); unsigned long vsid = get_kernel_vsid( ea ); unsigned long va = ( vsid << 28 ) | ( pa & 0xfffffff ); unsigned long vpn = va >> PAGE_SHIFT; unsigned long slot = HvCallHpt_findValid( &hpte, vpn ); if (hpte.dw0.dw0.v) { /* HPTE exists, so just bolt it */ HvCallHpt_setSwBits(slot, 0x10, 0); } else { /* No HPTE exists, so create a new bolted one */ make_pte(NULL, va, (unsigned long)__v2a(ea), mode_rw, 0, 0); } } }
/* * Create a pte. Used during initialization only. */ static void iSeries_make_pte(unsigned long va, unsigned long pa, int mode) { HPTE local_hpte, rhpte; unsigned long hash, vpn; long slot; vpn = va >> PAGE_SHIFT; hash = hpt_hash(vpn, 0); local_hpte.dw1.dword1 = pa | mode; local_hpte.dw0.dword0 = 0; local_hpte.dw0.dw0.avpn = va >> 23; local_hpte.dw0.dw0.bolted = 1; /* bolted */ local_hpte.dw0.dw0.v = 1; slot = HvCallHpt_findValid(&rhpte, vpn); if (slot < 0) { /* Must find space in primary group */ panic("hash_page: hpte already exists\n"); } HvCallHpt_addValidate(slot, 0, (HPTE *)&local_hpte ); }