13446Smrj /*
23446Smrj * CDDL HEADER START
33446Smrj *
43446Smrj * The contents of this file are subject to the terms of the
53446Smrj * Common Development and Distribution License (the "License").
63446Smrj * You may not use this file except in compliance with the License.
73446Smrj *
83446Smrj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93446Smrj * or http://www.opensolaris.org/os/licensing.
103446Smrj * See the License for the specific language governing permissions
113446Smrj * and limitations under the License.
123446Smrj *
133446Smrj * When distributing Covered Code, include this CDDL HEADER in each
143446Smrj * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153446Smrj * If applicable, add the following below this CDDL HEADER, with the
163446Smrj * fields enclosed by brackets "[]" replaced with your own identifying
173446Smrj * information: Portions Copyright [yyyy] [name of copyright owner]
183446Smrj *
193446Smrj * CDDL HEADER END
203446Smrj */
213446Smrj
223446Smrj /*
23*7542SRichard.Bean@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
243446Smrj * Use is subject to license terms.
253446Smrj */
263446Smrj
273446Smrj #include <sys/types.h>
283446Smrj #include <sys/systm.h>
293446Smrj #include <sys/archsystm.h>
303446Smrj #include <sys/debug.h>
313446Smrj #include <sys/bootconf.h>
323446Smrj #include <sys/bootsvcs.h>
333446Smrj #include <sys/bootinfo.h>
343446Smrj #include <sys/mman.h>
353446Smrj #include <sys/cmn_err.h>
363446Smrj #include <sys/param.h>
373446Smrj #include <sys/machparam.h>
383446Smrj #include <sys/machsystm.h>
393446Smrj #include <sys/promif.h>
403446Smrj #include <sys/kobj.h>
415084Sjohnlev #ifdef __xpv
425084Sjohnlev #include <sys/hypervisor.h>
435084Sjohnlev #endif
443446Smrj #include <vm/kboot_mmu.h>
453446Smrj #include <vm/hat_pte.h>
463446Smrj #include <vm/hat_i86.h>
473446Smrj #include <vm/seg_kmem.h>
483446Smrj
493446Smrj #if 0
503446Smrj /*
513446Smrj * Joe's debug printing
523446Smrj */
533446Smrj #define DBG(x) \
54*7542SRichard.Bean@Sun.COM bop_printf(NULL, "kboot_mmu.c: %s is %" PRIx64 "\n", #x, (uint64_t)(x));
553446Smrj #else
563446Smrj #define DBG(x) /* naught */
573446Smrj #endif
583446Smrj
593446Smrj /*
603446Smrj * Page table and memory stuff.
613446Smrj */
623446Smrj static caddr_t window;
633446Smrj static caddr_t pte_to_window;
643446Smrj
653446Smrj /*
663446Smrj * this are needed by mmu_init()
673446Smrj */
683446Smrj int kbm_nx_support = 0; /* NX bit in PTEs is in use */
693446Smrj int kbm_pae_support = 0; /* PAE is 64 bit Page table entries */
703446Smrj int kbm_pge_support = 0; /* PGE is Page table global bit enabled */
713446Smrj int kbm_largepage_support = 0;
723446Smrj uint_t kbm_nucleus_size = 0;
733446Smrj
743446Smrj #define BOOT_SHIFT(l) (shift_amt[l])
753446Smrj #define BOOT_SZ(l) ((size_t)1 << BOOT_SHIFT(l))
763446Smrj #define BOOT_OFFSET(l) (BOOT_SZ(l) - 1)
773446Smrj #define BOOT_MASK(l) (~BOOT_OFFSET(l))
783446Smrj
793446Smrj /*
803446Smrj * Initialize memory management parameters for boot time page table management
813446Smrj */
823446Smrj void
kbm_init(struct xboot_info * bi)833446Smrj kbm_init(struct xboot_info *bi)
843446Smrj {
853446Smrj /*
863446Smrj * configure mmu information
873446Smrj */
883446Smrj kbm_nucleus_size = (uintptr_t)bi->bi_kseg_size;
893446Smrj kbm_largepage_support = bi->bi_use_largepage;
903446Smrj kbm_nx_support = bi->bi_use_nx;
913446Smrj kbm_pae_support = bi->bi_use_pae;
923446Smrj kbm_pge_support = bi->bi_use_pge;
933446Smrj window = bi->bi_pt_window;
943446Smrj DBG(window);
953446Smrj pte_to_window = bi->bi_pte_to_pt_window;
963446Smrj DBG(pte_to_window);
973446Smrj if (kbm_pae_support) {
983446Smrj shift_amt = shift_amt_pae;
993446Smrj ptes_per_table = 512;
1003446Smrj pte_size = 8;
1013446Smrj lpagesize = TWO_MEG;
1023446Smrj #ifdef __amd64
1033446Smrj top_level = 3;
1043446Smrj #else
1053446Smrj top_level = 2;
1063446Smrj #endif
1073446Smrj } else {
1083446Smrj shift_amt = shift_amt_nopae;
1093446Smrj ptes_per_table = 1024;
1103446Smrj pte_size = 4;
1113446Smrj lpagesize = FOUR_MEG;
1123446Smrj top_level = 1;
1133446Smrj }
1143446Smrj
1155084Sjohnlev #ifdef __xpv
1165084Sjohnlev xen_info = bi->bi_xen_start_info;
1175084Sjohnlev mfn_list = (mfn_t *)xen_info->mfn_list;
1185084Sjohnlev DBG(mfn_list);
1195084Sjohnlev mfn_count = xen_info->nr_pages;
1205084Sjohnlev DBG(mfn_count);
1215084Sjohnlev #endif
1223446Smrj top_page_table = bi->bi_top_page_table;
1233446Smrj DBG(top_page_table);
1243446Smrj }
1253446Smrj
1263446Smrj /*
1273446Smrj * Change the addressible page table window to point at a given page
1283446Smrj */
1293446Smrj /*ARGSUSED*/
1303446Smrj void *
kbm_remap_window(paddr_t physaddr,int writeable)1313446Smrj kbm_remap_window(paddr_t physaddr, int writeable)
1323446Smrj {
1335084Sjohnlev x86pte_t pt_bits = PT_NOCONSIST | PT_VALID | PT_WRITABLE;
1343446Smrj
1353446Smrj DBG(physaddr);
1363446Smrj
1375084Sjohnlev #ifdef __xpv
1385084Sjohnlev if (!writeable)
1395084Sjohnlev pt_bits &= ~PT_WRITABLE;
1405084Sjohnlev if (HYPERVISOR_update_va_mapping((uintptr_t)window,
1415084Sjohnlev pa_to_ma(physaddr) | pt_bits, UVMF_INVLPG | UVMF_LOCAL) < 0)
1425084Sjohnlev bop_panic("HYPERVISOR_update_va_mapping() failed");
1435084Sjohnlev #else
1443446Smrj if (kbm_pae_support)
1453446Smrj *((x86pte_t *)pte_to_window) = physaddr | pt_bits;
1463446Smrj else
1473446Smrj *((x86pte32_t *)pte_to_window) = physaddr | pt_bits;
1483446Smrj mmu_tlbflush_entry(window);
1495084Sjohnlev #endif
1503446Smrj DBG(window);
1513446Smrj return (window);
1523446Smrj }
1533446Smrj
1543446Smrj /*
1553446Smrj * Add a mapping for the physical page at the given virtual address.
1563446Smrj */
1573446Smrj void
kbm_map(uintptr_t va,paddr_t pa,uint_t level,uint_t is_kernel)1583446Smrj kbm_map(uintptr_t va, paddr_t pa, uint_t level, uint_t is_kernel)
1593446Smrj {
1603446Smrj x86pte_t *ptep;
1613446Smrj paddr_t pte_physaddr;
1623446Smrj x86pte_t pteval;
1633446Smrj
1643446Smrj if (khat_running)
1653446Smrj panic("kbm_map() called too late");
1663446Smrj
1673446Smrj pteval = pa_to_ma(pa) | PT_NOCONSIST | PT_VALID | PT_WRITABLE;
1685349Skchow if (level >= 1)
1693446Smrj pteval |= PT_PAGESIZE;
1703446Smrj if (kbm_pge_support && is_kernel)
1713446Smrj pteval |= PT_GLOBAL;
1723446Smrj
1735084Sjohnlev #ifdef __xpv
1745084Sjohnlev /*
1755084Sjohnlev * try update_va_mapping first - fails if page table is missing.
1765084Sjohnlev */
1775084Sjohnlev if (HYPERVISOR_update_va_mapping(va, pteval,
1785084Sjohnlev UVMF_INVLPG | UVMF_LOCAL) == 0)
1795084Sjohnlev return;
1805084Sjohnlev #endif
1815084Sjohnlev
1823446Smrj /*
1833446Smrj * Find the pte that will map this address. This creates any
1843446Smrj * missing intermediate level page tables.
1853446Smrj */
1863446Smrj ptep = find_pte(va, &pte_physaddr, level, 0);
1873446Smrj if (ptep == NULL)
1883446Smrj bop_panic("kbm_map: find_pte returned NULL");
1893446Smrj
1905084Sjohnlev #ifdef __xpv
1915084Sjohnlev if (HYPERVISOR_update_va_mapping(va, pteval, UVMF_INVLPG | UVMF_LOCAL))
1925084Sjohnlev bop_panic("HYPERVISOR_update_va_mapping() failed");
1935084Sjohnlev #else
1943446Smrj if (kbm_pae_support)
1953446Smrj *ptep = pteval;
1963446Smrj else
1973446Smrj *((x86pte32_t *)ptep) = pteval;
1983446Smrj mmu_tlbflush_entry((caddr_t)va);
1995084Sjohnlev #endif
2003446Smrj }
2013446Smrj
2025084Sjohnlev #ifdef __xpv
2035084Sjohnlev
2045084Sjohnlev /*
2055084Sjohnlev * Add a mapping for the machine page at the given virtual address.
2065084Sjohnlev */
2075084Sjohnlev void
kbm_map_ma(maddr_t ma,uintptr_t va,uint_t level)2085084Sjohnlev kbm_map_ma(maddr_t ma, uintptr_t va, uint_t level)
2095084Sjohnlev {
2105084Sjohnlev paddr_t pte_physaddr;
2115084Sjohnlev x86pte_t pteval;
2125084Sjohnlev
2135084Sjohnlev pteval = ma | PT_NOCONSIST | PT_VALID | PT_REF | PT_WRITABLE;
2145084Sjohnlev if (level == 1)
2155084Sjohnlev pteval |= PT_PAGESIZE;
2165084Sjohnlev
2175084Sjohnlev /*
2185084Sjohnlev * try update_va_mapping first - fails if page table is missing.
2195084Sjohnlev */
2205084Sjohnlev if (HYPERVISOR_update_va_mapping(va,
2215084Sjohnlev pteval, UVMF_INVLPG | UVMF_LOCAL) == 0)
2225084Sjohnlev return;
2235084Sjohnlev
2245084Sjohnlev /*
2255084Sjohnlev * Find the pte that will map this address. This creates any
2265084Sjohnlev * missing intermediate level page tables
2275084Sjohnlev */
2285084Sjohnlev (void) find_pte(va, &pte_physaddr, level, 0);
2295084Sjohnlev
2305084Sjohnlev if (HYPERVISOR_update_va_mapping(va,
2315084Sjohnlev pteval, UVMF_INVLPG | UVMF_LOCAL) != 0)
2325084Sjohnlev bop_panic("HYPERVISOR_update_va_mapping failed");
2335084Sjohnlev }
2345084Sjohnlev
2355084Sjohnlev #endif /* __xpv */
2365084Sjohnlev
2375084Sjohnlev
2383446Smrj /*
2393446Smrj * Probe the boot time page tables to find the first mapping
2403446Smrj * including va (or higher) and return non-zero if one is found.
2413446Smrj * va is updated to the starting address and len to the pagesize.
2423446Smrj * pp will be set to point to the 1st page_t of the mapped page(s).
2433446Smrj *
2443446Smrj * Note that if va is in the middle of a large page, the returned va
2453446Smrj * will be less than what was asked for.
2463446Smrj */
2473446Smrj int
kbm_probe(uintptr_t * va,size_t * len,pfn_t * pfn,uint_t * prot)2483446Smrj kbm_probe(uintptr_t *va, size_t *len, pfn_t *pfn, uint_t *prot)
2493446Smrj {
2503446Smrj uintptr_t probe_va;
2513446Smrj x86pte_t *ptep;
2523446Smrj paddr_t pte_physaddr;
2533446Smrj x86pte_t pte_val;
2543446Smrj level_t l;
2553446Smrj
2563446Smrj if (khat_running)
2573446Smrj panic("kbm_probe() called too late");
2583446Smrj *len = 0;
2593446Smrj *pfn = PFN_INVALID;
2603446Smrj *prot = 0;
2613446Smrj probe_va = *va;
2623446Smrj restart_new_va:
2633446Smrj l = top_level;
2643446Smrj for (;;) {
2653446Smrj if (IN_VA_HOLE(probe_va))
2663446Smrj probe_va = mmu.hole_end;
2673446Smrj
2683446Smrj if (IN_HYPERVISOR_VA(probe_va))
2695084Sjohnlev #if defined(__amd64) && defined(__xpv)
2705084Sjohnlev probe_va = HYPERVISOR_VIRT_END;
2715084Sjohnlev #else
2723446Smrj return (0);
2735084Sjohnlev #endif
2743446Smrj
2753446Smrj /*
2763446Smrj * If we don't have a valid PTP/PTE at this level
2773446Smrj * then we can bump VA by this level's pagesize and try again.
2783446Smrj * When the probe_va wraps around, we are done.
2793446Smrj */
2803446Smrj ptep = find_pte(probe_va, &pte_physaddr, l, 1);
2813446Smrj if (ptep == NULL)
2823446Smrj bop_panic("kbm_probe: find_pte returned NULL");
2833446Smrj if (kbm_pae_support)
2843446Smrj pte_val = *ptep;
2853446Smrj else
2863446Smrj pte_val = *((x86pte32_t *)ptep);
2873446Smrj if (!PTE_ISVALID(pte_val)) {
2883446Smrj probe_va = (probe_va & BOOT_MASK(l)) + BOOT_SZ(l);
2893446Smrj if (probe_va <= *va)
2903446Smrj return (0);
2913446Smrj goto restart_new_va;
2923446Smrj }
2933446Smrj
2943446Smrj /*
2953446Smrj * If this entry is a pointer to a lower level page table
2963446Smrj * go down to it.
2973446Smrj */
2983446Smrj if (!PTE_ISPAGE(pte_val, l)) {
2993446Smrj ASSERT(l > 0);
3003446Smrj --l;
3013446Smrj continue;
3023446Smrj }
3033446Smrj
3043446Smrj /*
3053446Smrj * We found a boot level page table entry
3063446Smrj */
3073446Smrj *len = BOOT_SZ(l);
3083446Smrj *va = probe_va & ~(*len - 1);
3093446Smrj *pfn = PTE2PFN(pte_val, l);
3103446Smrj
3113446Smrj
3123446Smrj *prot = PROT_READ | PROT_EXEC;
3133446Smrj if (PTE_GET(pte_val, PT_WRITABLE))
3143446Smrj *prot |= PROT_WRITE;
3153446Smrj
3163446Smrj /*
3173446Smrj * pt_nx is cleared if processor doesn't support NX bit
3183446Smrj */
3193446Smrj if (PTE_GET(pte_val, mmu.pt_nx))
3203446Smrj *prot &= ~PROT_EXEC;
3213446Smrj
3223446Smrj return (1);
3233446Smrj }
3243446Smrj }
3253446Smrj
3263446Smrj
3273446Smrj /*
3283446Smrj * Destroy a boot loader page table 4K mapping.
3293446Smrj */
3303446Smrj void
kbm_unmap(uintptr_t va)3313446Smrj kbm_unmap(uintptr_t va)
3323446Smrj {
3333446Smrj if (khat_running)
3343446Smrj panic("kbm_unmap() called too late");
3353446Smrj else {
3365084Sjohnlev #ifdef __xpv
3375084Sjohnlev (void) HYPERVISOR_update_va_mapping(va, 0,
3385084Sjohnlev UVMF_INVLPG | UVMF_LOCAL);
3395084Sjohnlev #else
3403446Smrj x86pte_t *ptep;
3413446Smrj level_t level = 0;
3423446Smrj uint_t probe_only = 1;
3433446Smrj
3443446Smrj ptep = find_pte(va, NULL, level, probe_only);
3453446Smrj if (ptep == NULL)
3463446Smrj return;
3473446Smrj
3483446Smrj if (kbm_pae_support)
3493446Smrj *ptep = 0;
3503446Smrj else
3513446Smrj *((x86pte32_t *)ptep) = 0;
3523446Smrj mmu_tlbflush_entry((caddr_t)va);
3535084Sjohnlev #endif
3543446Smrj }
3553446Smrj }
3563446Smrj
3573446Smrj
3583446Smrj /*
3593446Smrj * Change a boot loader page table 4K mapping.
3603446Smrj * Returns the pfn of the old mapping.
3613446Smrj */
3623446Smrj pfn_t
kbm_remap(uintptr_t va,pfn_t pfn)3633446Smrj kbm_remap(uintptr_t va, pfn_t pfn)
3643446Smrj {
3653446Smrj x86pte_t *ptep;
3663446Smrj level_t level = 0;
3673446Smrj uint_t probe_only = 1;
3683446Smrj x86pte_t pte_val = pa_to_ma(pfn_to_pa(pfn)) | PT_WRITABLE |
3693446Smrj PT_NOCONSIST | PT_VALID;
3703446Smrj x86pte_t old_pte;
3713446Smrj
3723446Smrj if (khat_running)
3733446Smrj panic("kbm_remap() called too late");
3743446Smrj ptep = find_pte(va, NULL, level, probe_only);
3753446Smrj if (ptep == NULL)
3763446Smrj bop_panic("kbm_remap: find_pte returned NULL");
3773446Smrj
3783446Smrj if (kbm_pae_support)
3793446Smrj old_pte = *ptep;
3803446Smrj else
3813446Smrj old_pte = *((x86pte32_t *)ptep);
3823446Smrj
3835084Sjohnlev #ifdef __xpv
3845084Sjohnlev if (HYPERVISOR_update_va_mapping(va, pte_val, UVMF_INVLPG | UVMF_LOCAL))
3855084Sjohnlev bop_panic("HYPERVISOR_update_va_mapping() failed");
3865084Sjohnlev #else
3873446Smrj if (kbm_pae_support)
3883446Smrj *((x86pte_t *)ptep) = pte_val;
3893446Smrj else
3903446Smrj *((x86pte32_t *)ptep) = pte_val;
3913446Smrj mmu_tlbflush_entry((caddr_t)va);
3925084Sjohnlev #endif
3933446Smrj
3943446Smrj if (!(old_pte & PT_VALID) || ma_to_pa(old_pte) == -1)
3953446Smrj return (PFN_INVALID);
3963446Smrj return (mmu_btop(ma_to_pa(old_pte)));
3973446Smrj }
3983446Smrj
3993446Smrj
4003446Smrj /*
4013446Smrj * Change a boot loader page table 4K mapping to read only.
4023446Smrj */
4033446Smrj void
kbm_read_only(uintptr_t va,paddr_t pa)4043446Smrj kbm_read_only(uintptr_t va, paddr_t pa)
4053446Smrj {
4063446Smrj x86pte_t pte_val = pa_to_ma(pa) |
4073446Smrj PT_NOCONSIST | PT_REF | PT_MOD | PT_VALID;
4085084Sjohnlev
4095084Sjohnlev #ifdef __xpv
4105084Sjohnlev if (HYPERVISOR_update_va_mapping(va, pte_val, UVMF_INVLPG | UVMF_LOCAL))
4115084Sjohnlev bop_panic("HYPERVISOR_update_va_mapping() failed");
4125084Sjohnlev #else
4133446Smrj x86pte_t *ptep;
4143446Smrj level_t level = 0;
4153446Smrj
4163446Smrj ptep = find_pte(va, NULL, level, 0);
4173446Smrj if (ptep == NULL)
4183446Smrj bop_panic("kbm_read_only: find_pte returned NULL");
4193446Smrj
4203446Smrj if (kbm_pae_support)
4213446Smrj *ptep = pte_val;
4223446Smrj else
4233446Smrj *((x86pte32_t *)ptep) = pte_val;
4243446Smrj mmu_tlbflush_entry((caddr_t)va);
4255084Sjohnlev #endif
4263446Smrj }
4273446Smrj
4283446Smrj /*
4293446Smrj * interfaces for kernel debugger to access physical memory
4303446Smrj */
4313446Smrj static x86pte_t save_pte;
4323446Smrj
4333446Smrj void *
kbm_push(paddr_t pa)4343446Smrj kbm_push(paddr_t pa)
4353446Smrj {
4363446Smrj static int first_time = 1;
4373446Smrj
4383446Smrj if (first_time) {
4393446Smrj first_time = 0;
4403446Smrj return (window);
4413446Smrj }
4423446Smrj
4433446Smrj if (kbm_pae_support)
4443446Smrj save_pte = *((x86pte_t *)pte_to_window);
4453446Smrj else
4463446Smrj save_pte = *((x86pte32_t *)pte_to_window);
4473446Smrj return (kbm_remap_window(pa, 0));
4483446Smrj }
4493446Smrj
4503446Smrj void
kbm_pop(void)4513446Smrj kbm_pop(void)
4523446Smrj {
4535084Sjohnlev #ifdef __xpv
4545084Sjohnlev if (HYPERVISOR_update_va_mapping((uintptr_t)window, save_pte,
4555084Sjohnlev UVMF_INVLPG | UVMF_LOCAL) < 0)
4565084Sjohnlev bop_panic("HYPERVISOR_update_va_mapping() failed");
4575084Sjohnlev #else
4583446Smrj if (kbm_pae_support)
4593446Smrj *((x86pte_t *)pte_to_window) = save_pte;
4603446Smrj else
4613446Smrj *((x86pte32_t *)pte_to_window) = save_pte;
4623446Smrj mmu_tlbflush_entry(window);
4635084Sjohnlev #endif
4643446Smrj }
4653446Smrj
4663446Smrj x86pte_t
get_pteval(paddr_t table,uint_t index)4673446Smrj get_pteval(paddr_t table, uint_t index)
4683446Smrj {
4693446Smrj void *table_ptr = kbm_remap_window(table, 0);
4703446Smrj
4713446Smrj if (kbm_pae_support)
4723446Smrj return (((x86pte_t *)table_ptr)[index]);
4733446Smrj return (((x86pte32_t *)table_ptr)[index]);
4743446Smrj }
4753446Smrj
4765084Sjohnlev #ifndef __xpv
4773446Smrj void
set_pteval(paddr_t table,uint_t index,uint_t level,x86pte_t pteval)4783446Smrj set_pteval(paddr_t table, uint_t index, uint_t level, x86pte_t pteval)
4793446Smrj {
4803446Smrj void *table_ptr = kbm_remap_window(table, 0);
4813446Smrj if (kbm_pae_support)
4823446Smrj ((x86pte_t *)table_ptr)[index] = pteval;
4833446Smrj else
4843446Smrj ((x86pte32_t *)table_ptr)[index] = pteval;
4853446Smrj if (level == top_level && level == 2)
4863446Smrj reload_cr3();
4873446Smrj }
4885084Sjohnlev #endif
4893446Smrj
4903446Smrj paddr_t
make_ptable(x86pte_t * pteval,uint_t level)4913446Smrj make_ptable(x86pte_t *pteval, uint_t level)
4923446Smrj {
4933446Smrj paddr_t new_table;
4943446Smrj void *table_ptr;
4953446Smrj
4963446Smrj new_table = do_bop_phys_alloc(MMU_PAGESIZE, MMU_PAGESIZE);
4973446Smrj table_ptr = kbm_remap_window(new_table, 1);
4983446Smrj bzero(table_ptr, MMU_PAGESIZE);
4995084Sjohnlev #ifdef __xpv
5005084Sjohnlev /* Remove write permission to the new page table. */
5015084Sjohnlev (void) kbm_remap_window(new_table, 0);
5025084Sjohnlev #endif
5033446Smrj
5043446Smrj if (level == top_level && level == 2)
5053446Smrj *pteval = pa_to_ma(new_table) | PT_VALID;
5063446Smrj else
5073446Smrj *pteval = pa_to_ma(new_table) |
5083446Smrj PT_VALID | PT_REF | PT_USER | PT_WRITABLE;
5093446Smrj
5103446Smrj return (new_table);
5113446Smrj }
5123446Smrj
5133446Smrj x86pte_t *
map_pte(paddr_t table,uint_t index)5143446Smrj map_pte(paddr_t table, uint_t index)
5153446Smrj {
5163446Smrj void *table_ptr = kbm_remap_window(table, 0);
5173446Smrj return ((x86pte_t *)((caddr_t)table_ptr + index * pte_size));
5183446Smrj }
519