1ae115bc7Smrj /* 2ae115bc7Smrj * CDDL HEADER START 3ae115bc7Smrj * 4ae115bc7Smrj * The contents of this file are subject to the terms of the 5ae115bc7Smrj * Common Development and Distribution License (the "License"). 6ae115bc7Smrj * You may not use this file except in compliance with the License. 7ae115bc7Smrj * 8ae115bc7Smrj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9ae115bc7Smrj * or http://www.opensolaris.org/os/licensing. 10ae115bc7Smrj * See the License for the specific language governing permissions 11ae115bc7Smrj * and limitations under the License. 12ae115bc7Smrj * 13ae115bc7Smrj * When distributing Covered Code, include this CDDL HEADER in each 14ae115bc7Smrj * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15ae115bc7Smrj * If applicable, add the following below this CDDL HEADER, with the 16ae115bc7Smrj * fields enclosed by brackets "[]" replaced with your own identifying 17ae115bc7Smrj * information: Portions Copyright [yyyy] [name of copyright owner] 18ae115bc7Smrj * 19ae115bc7Smrj * CDDL HEADER END 20ae115bc7Smrj */ 21ae115bc7Smrj 22ae115bc7Smrj /* 23*613b2871SRichard Bean * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24ae115bc7Smrj * Use is subject to license terms. 25ae115bc7Smrj */ 26ae115bc7Smrj 27ae115bc7Smrj #include <sys/types.h> 28ae115bc7Smrj #include <sys/systm.h> 29ae115bc7Smrj #include <sys/archsystm.h> 30ae115bc7Smrj #include <sys/debug.h> 31ae115bc7Smrj #include <sys/bootconf.h> 32ae115bc7Smrj #include <sys/bootsvcs.h> 33ae115bc7Smrj #include <sys/bootinfo.h> 34ae115bc7Smrj #include <sys/mman.h> 35ae115bc7Smrj #include <sys/cmn_err.h> 36ae115bc7Smrj #include <sys/param.h> 37ae115bc7Smrj #include <sys/machparam.h> 38ae115bc7Smrj #include <sys/machsystm.h> 39ae115bc7Smrj #include <sys/promif.h> 40ae115bc7Smrj #include <sys/kobj.h> 41843e1988Sjohnlev #ifdef __xpv 42843e1988Sjohnlev #include <sys/hypervisor.h> 43843e1988Sjohnlev #endif 44ae115bc7Smrj #include <vm/kboot_mmu.h> 45ae115bc7Smrj #include <vm/hat_pte.h> 46ae115bc7Smrj #include <vm/hat_i86.h> 47ae115bc7Smrj #include <vm/seg_kmem.h> 48ae115bc7Smrj 49ae115bc7Smrj #if 0 50ae115bc7Smrj /* 51ae115bc7Smrj * Joe's debug printing 52ae115bc7Smrj */ 53ae115bc7Smrj #define DBG(x) \ 54*613b2871SRichard Bean bop_printf(NULL, "kboot_mmu.c: %s is %" PRIx64 "\n", #x, (uint64_t)(x)); 55ae115bc7Smrj #else 56ae115bc7Smrj #define DBG(x) /* naught */ 57ae115bc7Smrj #endif 58ae115bc7Smrj 59ae115bc7Smrj /* 60ae115bc7Smrj * Page table and memory stuff. 61ae115bc7Smrj */ 62ae115bc7Smrj static caddr_t window; 63ae115bc7Smrj static caddr_t pte_to_window; 64ae115bc7Smrj 65ae115bc7Smrj /* 66ae115bc7Smrj * this are needed by mmu_init() 67ae115bc7Smrj */ 68ae115bc7Smrj int kbm_nx_support = 0; /* NX bit in PTEs is in use */ 69ae115bc7Smrj int kbm_pae_support = 0; /* PAE is 64 bit Page table entries */ 70ae115bc7Smrj int kbm_pge_support = 0; /* PGE is Page table global bit enabled */ 71ae115bc7Smrj int kbm_largepage_support = 0; 72ae115bc7Smrj uint_t kbm_nucleus_size = 0; 73ae115bc7Smrj 74ae115bc7Smrj #define BOOT_SHIFT(l) (shift_amt[l]) 75ae115bc7Smrj #define BOOT_SZ(l) ((size_t)1 << BOOT_SHIFT(l)) 76ae115bc7Smrj #define BOOT_OFFSET(l) (BOOT_SZ(l) - 1) 77ae115bc7Smrj #define BOOT_MASK(l) (~BOOT_OFFSET(l)) 78ae115bc7Smrj 79ae115bc7Smrj /* 80ae115bc7Smrj * Initialize memory management parameters for boot time page table management 81ae115bc7Smrj */ 82ae115bc7Smrj void 83ae115bc7Smrj kbm_init(struct xboot_info *bi) 84ae115bc7Smrj { 85ae115bc7Smrj /* 86ae115bc7Smrj * configure mmu information 87ae115bc7Smrj */ 88ae115bc7Smrj kbm_nucleus_size = (uintptr_t)bi->bi_kseg_size; 89ae115bc7Smrj kbm_largepage_support = bi->bi_use_largepage; 90ae115bc7Smrj kbm_nx_support = bi->bi_use_nx; 91ae115bc7Smrj kbm_pae_support = bi->bi_use_pae; 92ae115bc7Smrj kbm_pge_support = bi->bi_use_pge; 93ae115bc7Smrj window = bi->bi_pt_window; 94ae115bc7Smrj DBG(window); 95ae115bc7Smrj pte_to_window = bi->bi_pte_to_pt_window; 96ae115bc7Smrj DBG(pte_to_window); 97ae115bc7Smrj if (kbm_pae_support) { 98ae115bc7Smrj shift_amt = shift_amt_pae; 99ae115bc7Smrj ptes_per_table = 512; 100ae115bc7Smrj pte_size = 8; 101ae115bc7Smrj lpagesize = TWO_MEG; 102ae115bc7Smrj #ifdef __amd64 103ae115bc7Smrj top_level = 3; 104ae115bc7Smrj #else 105ae115bc7Smrj top_level = 2; 106ae115bc7Smrj #endif 107ae115bc7Smrj } else { 108ae115bc7Smrj shift_amt = shift_amt_nopae; 109ae115bc7Smrj ptes_per_table = 1024; 110ae115bc7Smrj pte_size = 4; 111ae115bc7Smrj lpagesize = FOUR_MEG; 112ae115bc7Smrj top_level = 1; 113ae115bc7Smrj } 114ae115bc7Smrj 115843e1988Sjohnlev #ifdef __xpv 116843e1988Sjohnlev xen_info = bi->bi_xen_start_info; 117843e1988Sjohnlev mfn_list = (mfn_t *)xen_info->mfn_list; 118843e1988Sjohnlev DBG(mfn_list); 119843e1988Sjohnlev mfn_count = xen_info->nr_pages; 120843e1988Sjohnlev DBG(mfn_count); 121843e1988Sjohnlev #endif 122ae115bc7Smrj top_page_table = bi->bi_top_page_table; 123ae115bc7Smrj DBG(top_page_table); 124ae115bc7Smrj } 125ae115bc7Smrj 126ae115bc7Smrj /* 127ae115bc7Smrj * Change the addressible page table window to point at a given page 128ae115bc7Smrj */ 129ae115bc7Smrj /*ARGSUSED*/ 130ae115bc7Smrj void * 131ae115bc7Smrj kbm_remap_window(paddr_t physaddr, int writeable) 132ae115bc7Smrj { 133843e1988Sjohnlev x86pte_t pt_bits = PT_NOCONSIST | PT_VALID | PT_WRITABLE; 134ae115bc7Smrj 135ae115bc7Smrj DBG(physaddr); 136ae115bc7Smrj 137843e1988Sjohnlev #ifdef __xpv 138843e1988Sjohnlev if (!writeable) 139843e1988Sjohnlev pt_bits &= ~PT_WRITABLE; 140843e1988Sjohnlev if (HYPERVISOR_update_va_mapping((uintptr_t)window, 141843e1988Sjohnlev pa_to_ma(physaddr) | pt_bits, UVMF_INVLPG | UVMF_LOCAL) < 0) 142843e1988Sjohnlev bop_panic("HYPERVISOR_update_va_mapping() failed"); 143843e1988Sjohnlev #else 144ae115bc7Smrj if (kbm_pae_support) 145ae115bc7Smrj *((x86pte_t *)pte_to_window) = physaddr | pt_bits; 146ae115bc7Smrj else 147ae115bc7Smrj *((x86pte32_t *)pte_to_window) = physaddr | pt_bits; 148ae115bc7Smrj mmu_tlbflush_entry(window); 149843e1988Sjohnlev #endif 150ae115bc7Smrj DBG(window); 151ae115bc7Smrj return (window); 152ae115bc7Smrj } 153ae115bc7Smrj 154ae115bc7Smrj /* 155ae115bc7Smrj * Add a mapping for the physical page at the given virtual address. 156ae115bc7Smrj */ 157ae115bc7Smrj void 158ae115bc7Smrj kbm_map(uintptr_t va, paddr_t pa, uint_t level, uint_t is_kernel) 159ae115bc7Smrj { 160ae115bc7Smrj x86pte_t *ptep; 161ae115bc7Smrj paddr_t pte_physaddr; 162ae115bc7Smrj x86pte_t pteval; 163ae115bc7Smrj 164ae115bc7Smrj if (khat_running) 165ae115bc7Smrj panic("kbm_map() called too late"); 166ae115bc7Smrj 167ae115bc7Smrj pteval = pa_to_ma(pa) | PT_NOCONSIST | PT_VALID | PT_WRITABLE; 16802bc52beSkchow if (level >= 1) 169ae115bc7Smrj pteval |= PT_PAGESIZE; 170ae115bc7Smrj if (kbm_pge_support && is_kernel) 171ae115bc7Smrj pteval |= PT_GLOBAL; 172ae115bc7Smrj 173843e1988Sjohnlev #ifdef __xpv 174843e1988Sjohnlev /* 175843e1988Sjohnlev * try update_va_mapping first - fails if page table is missing. 176843e1988Sjohnlev */ 177843e1988Sjohnlev if (HYPERVISOR_update_va_mapping(va, pteval, 178843e1988Sjohnlev UVMF_INVLPG | UVMF_LOCAL) == 0) 179843e1988Sjohnlev return; 180843e1988Sjohnlev #endif 181843e1988Sjohnlev 182ae115bc7Smrj /* 183ae115bc7Smrj * Find the pte that will map this address. This creates any 184ae115bc7Smrj * missing intermediate level page tables. 185ae115bc7Smrj */ 186ae115bc7Smrj ptep = find_pte(va, &pte_physaddr, level, 0); 187ae115bc7Smrj if (ptep == NULL) 188ae115bc7Smrj bop_panic("kbm_map: find_pte returned NULL"); 189ae115bc7Smrj 190843e1988Sjohnlev #ifdef __xpv 191843e1988Sjohnlev if (HYPERVISOR_update_va_mapping(va, pteval, UVMF_INVLPG | UVMF_LOCAL)) 192843e1988Sjohnlev bop_panic("HYPERVISOR_update_va_mapping() failed"); 193843e1988Sjohnlev #else 194ae115bc7Smrj if (kbm_pae_support) 195ae115bc7Smrj *ptep = pteval; 196ae115bc7Smrj else 197ae115bc7Smrj *((x86pte32_t *)ptep) = pteval; 198ae115bc7Smrj mmu_tlbflush_entry((caddr_t)va); 199843e1988Sjohnlev #endif 200ae115bc7Smrj } 201ae115bc7Smrj 202843e1988Sjohnlev #ifdef __xpv 203843e1988Sjohnlev 204843e1988Sjohnlev /* 205843e1988Sjohnlev * Add a mapping for the machine page at the given virtual address. 206843e1988Sjohnlev */ 207843e1988Sjohnlev void 208843e1988Sjohnlev kbm_map_ma(maddr_t ma, uintptr_t va, uint_t level) 209843e1988Sjohnlev { 210843e1988Sjohnlev paddr_t pte_physaddr; 211843e1988Sjohnlev x86pte_t pteval; 212843e1988Sjohnlev 213843e1988Sjohnlev pteval = ma | PT_NOCONSIST | PT_VALID | PT_REF | PT_WRITABLE; 214843e1988Sjohnlev if (level == 1) 215843e1988Sjohnlev pteval |= PT_PAGESIZE; 216843e1988Sjohnlev 217843e1988Sjohnlev /* 218843e1988Sjohnlev * try update_va_mapping first - fails if page table is missing. 219843e1988Sjohnlev */ 220843e1988Sjohnlev if (HYPERVISOR_update_va_mapping(va, 221843e1988Sjohnlev pteval, UVMF_INVLPG | UVMF_LOCAL) == 0) 222843e1988Sjohnlev return; 223843e1988Sjohnlev 224843e1988Sjohnlev /* 225843e1988Sjohnlev * Find the pte that will map this address. This creates any 226843e1988Sjohnlev * missing intermediate level page tables 227843e1988Sjohnlev */ 228843e1988Sjohnlev (void) find_pte(va, &pte_physaddr, level, 0); 229843e1988Sjohnlev 230843e1988Sjohnlev if (HYPERVISOR_update_va_mapping(va, 231843e1988Sjohnlev pteval, UVMF_INVLPG | UVMF_LOCAL) != 0) 232843e1988Sjohnlev bop_panic("HYPERVISOR_update_va_mapping failed"); 233843e1988Sjohnlev } 234843e1988Sjohnlev 235843e1988Sjohnlev #endif /* __xpv */ 236843e1988Sjohnlev 237843e1988Sjohnlev 238ae115bc7Smrj /* 239ae115bc7Smrj * Probe the boot time page tables to find the first mapping 240ae115bc7Smrj * including va (or higher) and return non-zero if one is found. 241ae115bc7Smrj * va is updated to the starting address and len to the pagesize. 242ae115bc7Smrj * pp will be set to point to the 1st page_t of the mapped page(s). 243ae115bc7Smrj * 244ae115bc7Smrj * Note that if va is in the middle of a large page, the returned va 245ae115bc7Smrj * will be less than what was asked for. 246ae115bc7Smrj */ 247ae115bc7Smrj int 248ae115bc7Smrj kbm_probe(uintptr_t *va, size_t *len, pfn_t *pfn, uint_t *prot) 249ae115bc7Smrj { 250ae115bc7Smrj uintptr_t probe_va; 251ae115bc7Smrj x86pte_t *ptep; 252ae115bc7Smrj paddr_t pte_physaddr; 253ae115bc7Smrj x86pte_t pte_val; 254ae115bc7Smrj level_t l; 255ae115bc7Smrj 256ae115bc7Smrj if (khat_running) 257ae115bc7Smrj panic("kbm_probe() called too late"); 258ae115bc7Smrj *len = 0; 259ae115bc7Smrj *pfn = PFN_INVALID; 260ae115bc7Smrj *prot = 0; 261ae115bc7Smrj probe_va = *va; 262ae115bc7Smrj restart_new_va: 263ae115bc7Smrj l = top_level; 264ae115bc7Smrj for (;;) { 265ae115bc7Smrj if (IN_VA_HOLE(probe_va)) 266ae115bc7Smrj probe_va = mmu.hole_end; 267ae115bc7Smrj 268ae115bc7Smrj if (IN_HYPERVISOR_VA(probe_va)) 269843e1988Sjohnlev #if defined(__amd64) && defined(__xpv) 270843e1988Sjohnlev probe_va = HYPERVISOR_VIRT_END; 271843e1988Sjohnlev #else 272ae115bc7Smrj return (0); 273843e1988Sjohnlev #endif 274ae115bc7Smrj 275ae115bc7Smrj /* 276ae115bc7Smrj * If we don't have a valid PTP/PTE at this level 277ae115bc7Smrj * then we can bump VA by this level's pagesize and try again. 278ae115bc7Smrj * When the probe_va wraps around, we are done. 279ae115bc7Smrj */ 280ae115bc7Smrj ptep = find_pte(probe_va, &pte_physaddr, l, 1); 281ae115bc7Smrj if (ptep == NULL) 282ae115bc7Smrj bop_panic("kbm_probe: find_pte returned NULL"); 283ae115bc7Smrj if (kbm_pae_support) 284ae115bc7Smrj pte_val = *ptep; 285ae115bc7Smrj else 286ae115bc7Smrj pte_val = *((x86pte32_t *)ptep); 287ae115bc7Smrj if (!PTE_ISVALID(pte_val)) { 288ae115bc7Smrj probe_va = (probe_va & BOOT_MASK(l)) + BOOT_SZ(l); 289ae115bc7Smrj if (probe_va <= *va) 290ae115bc7Smrj return (0); 291ae115bc7Smrj goto restart_new_va; 292ae115bc7Smrj } 293ae115bc7Smrj 294ae115bc7Smrj /* 295ae115bc7Smrj * If this entry is a pointer to a lower level page table 296ae115bc7Smrj * go down to it. 297ae115bc7Smrj */ 298ae115bc7Smrj if (!PTE_ISPAGE(pte_val, l)) { 299ae115bc7Smrj ASSERT(l > 0); 300ae115bc7Smrj --l; 301ae115bc7Smrj continue; 302ae115bc7Smrj } 303ae115bc7Smrj 304ae115bc7Smrj /* 305ae115bc7Smrj * We found a boot level page table entry 306ae115bc7Smrj */ 307ae115bc7Smrj *len = BOOT_SZ(l); 308ae115bc7Smrj *va = probe_va & ~(*len - 1); 309ae115bc7Smrj *pfn = PTE2PFN(pte_val, l); 310ae115bc7Smrj 311ae115bc7Smrj 312ae115bc7Smrj *prot = PROT_READ | PROT_EXEC; 313ae115bc7Smrj if (PTE_GET(pte_val, PT_WRITABLE)) 314ae115bc7Smrj *prot |= PROT_WRITE; 315ae115bc7Smrj 316ae115bc7Smrj /* 317ae115bc7Smrj * pt_nx is cleared if processor doesn't support NX bit 318ae115bc7Smrj */ 319ae115bc7Smrj if (PTE_GET(pte_val, mmu.pt_nx)) 320ae115bc7Smrj *prot &= ~PROT_EXEC; 321ae115bc7Smrj 322ae115bc7Smrj return (1); 323ae115bc7Smrj } 324ae115bc7Smrj } 325ae115bc7Smrj 326ae115bc7Smrj 327ae115bc7Smrj /* 328ae115bc7Smrj * Destroy a boot loader page table 4K mapping. 329ae115bc7Smrj */ 330ae115bc7Smrj void 331ae115bc7Smrj kbm_unmap(uintptr_t va) 332ae115bc7Smrj { 333ae115bc7Smrj if (khat_running) 334ae115bc7Smrj panic("kbm_unmap() called too late"); 335ae115bc7Smrj else { 336843e1988Sjohnlev #ifdef __xpv 337843e1988Sjohnlev (void) HYPERVISOR_update_va_mapping(va, 0, 338843e1988Sjohnlev UVMF_INVLPG | UVMF_LOCAL); 339843e1988Sjohnlev #else 340ae115bc7Smrj x86pte_t *ptep; 341ae115bc7Smrj level_t level = 0; 342ae115bc7Smrj uint_t probe_only = 1; 343ae115bc7Smrj 344ae115bc7Smrj ptep = find_pte(va, NULL, level, probe_only); 345ae115bc7Smrj if (ptep == NULL) 346ae115bc7Smrj return; 347ae115bc7Smrj 348ae115bc7Smrj if (kbm_pae_support) 349ae115bc7Smrj *ptep = 0; 350ae115bc7Smrj else 351ae115bc7Smrj *((x86pte32_t *)ptep) = 0; 352ae115bc7Smrj mmu_tlbflush_entry((caddr_t)va); 353843e1988Sjohnlev #endif 354ae115bc7Smrj } 355ae115bc7Smrj } 356ae115bc7Smrj 357ae115bc7Smrj 358ae115bc7Smrj /* 359ae115bc7Smrj * Change a boot loader page table 4K mapping. 360ae115bc7Smrj * Returns the pfn of the old mapping. 361ae115bc7Smrj */ 362ae115bc7Smrj pfn_t 363ae115bc7Smrj kbm_remap(uintptr_t va, pfn_t pfn) 364ae115bc7Smrj { 365ae115bc7Smrj x86pte_t *ptep; 366ae115bc7Smrj level_t level = 0; 367ae115bc7Smrj uint_t probe_only = 1; 368ae115bc7Smrj x86pte_t pte_val = pa_to_ma(pfn_to_pa(pfn)) | PT_WRITABLE | 369ae115bc7Smrj PT_NOCONSIST | PT_VALID; 370ae115bc7Smrj x86pte_t old_pte; 371ae115bc7Smrj 372ae115bc7Smrj if (khat_running) 373ae115bc7Smrj panic("kbm_remap() called too late"); 374ae115bc7Smrj ptep = find_pte(va, NULL, level, probe_only); 375ae115bc7Smrj if (ptep == NULL) 376ae115bc7Smrj bop_panic("kbm_remap: find_pte returned NULL"); 377ae115bc7Smrj 378ae115bc7Smrj if (kbm_pae_support) 379ae115bc7Smrj old_pte = *ptep; 380ae115bc7Smrj else 381ae115bc7Smrj old_pte = *((x86pte32_t *)ptep); 382ae115bc7Smrj 383843e1988Sjohnlev #ifdef __xpv 384843e1988Sjohnlev if (HYPERVISOR_update_va_mapping(va, pte_val, UVMF_INVLPG | UVMF_LOCAL)) 385843e1988Sjohnlev bop_panic("HYPERVISOR_update_va_mapping() failed"); 386843e1988Sjohnlev #else 387ae115bc7Smrj if (kbm_pae_support) 388ae115bc7Smrj *((x86pte_t *)ptep) = pte_val; 389ae115bc7Smrj else 390ae115bc7Smrj *((x86pte32_t *)ptep) = pte_val; 391ae115bc7Smrj mmu_tlbflush_entry((caddr_t)va); 392843e1988Sjohnlev #endif 393ae115bc7Smrj 394ae115bc7Smrj if (!(old_pte & PT_VALID) || ma_to_pa(old_pte) == -1) 395ae115bc7Smrj return (PFN_INVALID); 396ae115bc7Smrj return (mmu_btop(ma_to_pa(old_pte))); 397ae115bc7Smrj } 398ae115bc7Smrj 399ae115bc7Smrj 400ae115bc7Smrj /* 401ae115bc7Smrj * Change a boot loader page table 4K mapping to read only. 402ae115bc7Smrj */ 403ae115bc7Smrj void 404ae115bc7Smrj kbm_read_only(uintptr_t va, paddr_t pa) 405ae115bc7Smrj { 406ae115bc7Smrj x86pte_t pte_val = pa_to_ma(pa) | 407ae115bc7Smrj PT_NOCONSIST | PT_REF | PT_MOD | PT_VALID; 408843e1988Sjohnlev 409843e1988Sjohnlev #ifdef __xpv 410843e1988Sjohnlev if (HYPERVISOR_update_va_mapping(va, pte_val, UVMF_INVLPG | UVMF_LOCAL)) 411843e1988Sjohnlev bop_panic("HYPERVISOR_update_va_mapping() failed"); 412843e1988Sjohnlev #else 413ae115bc7Smrj x86pte_t *ptep; 414ae115bc7Smrj level_t level = 0; 415ae115bc7Smrj 416ae115bc7Smrj ptep = find_pte(va, NULL, level, 0); 417ae115bc7Smrj if (ptep == NULL) 418ae115bc7Smrj bop_panic("kbm_read_only: find_pte returned NULL"); 419ae115bc7Smrj 420ae115bc7Smrj if (kbm_pae_support) 421ae115bc7Smrj *ptep = pte_val; 422ae115bc7Smrj else 423ae115bc7Smrj *((x86pte32_t *)ptep) = pte_val; 424ae115bc7Smrj mmu_tlbflush_entry((caddr_t)va); 425843e1988Sjohnlev #endif 426ae115bc7Smrj } 427ae115bc7Smrj 428ae115bc7Smrj /* 429ae115bc7Smrj * interfaces for kernel debugger to access physical memory 430ae115bc7Smrj */ 431ae115bc7Smrj static x86pte_t save_pte; 432ae115bc7Smrj 433ae115bc7Smrj void * 434ae115bc7Smrj kbm_push(paddr_t pa) 435ae115bc7Smrj { 436ae115bc7Smrj static int first_time = 1; 437ae115bc7Smrj 438ae115bc7Smrj if (first_time) { 439ae115bc7Smrj first_time = 0; 440ae115bc7Smrj return (window); 441ae115bc7Smrj } 442ae115bc7Smrj 443ae115bc7Smrj if (kbm_pae_support) 444ae115bc7Smrj save_pte = *((x86pte_t *)pte_to_window); 445ae115bc7Smrj else 446ae115bc7Smrj save_pte = *((x86pte32_t *)pte_to_window); 447ae115bc7Smrj return (kbm_remap_window(pa, 0)); 448ae115bc7Smrj } 449ae115bc7Smrj 450ae115bc7Smrj void 451ae115bc7Smrj kbm_pop(void) 452ae115bc7Smrj { 453843e1988Sjohnlev #ifdef __xpv 454843e1988Sjohnlev if (HYPERVISOR_update_va_mapping((uintptr_t)window, save_pte, 455843e1988Sjohnlev UVMF_INVLPG | UVMF_LOCAL) < 0) 456843e1988Sjohnlev bop_panic("HYPERVISOR_update_va_mapping() failed"); 457843e1988Sjohnlev #else 458ae115bc7Smrj if (kbm_pae_support) 459ae115bc7Smrj *((x86pte_t *)pte_to_window) = save_pte; 460ae115bc7Smrj else 461ae115bc7Smrj *((x86pte32_t *)pte_to_window) = save_pte; 462ae115bc7Smrj mmu_tlbflush_entry(window); 463843e1988Sjohnlev #endif 464ae115bc7Smrj } 465ae115bc7Smrj 466ae115bc7Smrj x86pte_t 467ae115bc7Smrj get_pteval(paddr_t table, uint_t index) 468ae115bc7Smrj { 469ae115bc7Smrj void *table_ptr = kbm_remap_window(table, 0); 470ae115bc7Smrj 471ae115bc7Smrj if (kbm_pae_support) 472ae115bc7Smrj return (((x86pte_t *)table_ptr)[index]); 473ae115bc7Smrj return (((x86pte32_t *)table_ptr)[index]); 474ae115bc7Smrj } 475ae115bc7Smrj 476843e1988Sjohnlev #ifndef __xpv 477ae115bc7Smrj void 478ae115bc7Smrj set_pteval(paddr_t table, uint_t index, uint_t level, x86pte_t pteval) 479ae115bc7Smrj { 480ae115bc7Smrj void *table_ptr = kbm_remap_window(table, 0); 481ae115bc7Smrj if (kbm_pae_support) 482ae115bc7Smrj ((x86pte_t *)table_ptr)[index] = pteval; 483ae115bc7Smrj else 484ae115bc7Smrj ((x86pte32_t *)table_ptr)[index] = pteval; 485ae115bc7Smrj if (level == top_level && level == 2) 486ae115bc7Smrj reload_cr3(); 487ae115bc7Smrj } 488843e1988Sjohnlev #endif 489ae115bc7Smrj 490ae115bc7Smrj paddr_t 491ae115bc7Smrj make_ptable(x86pte_t *pteval, uint_t level) 492ae115bc7Smrj { 493ae115bc7Smrj paddr_t new_table; 494ae115bc7Smrj void *table_ptr; 495ae115bc7Smrj 496ae115bc7Smrj new_table = do_bop_phys_alloc(MMU_PAGESIZE, MMU_PAGESIZE); 497ae115bc7Smrj table_ptr = kbm_remap_window(new_table, 1); 498ae115bc7Smrj bzero(table_ptr, MMU_PAGESIZE); 499843e1988Sjohnlev #ifdef __xpv 500843e1988Sjohnlev /* Remove write permission to the new page table. */ 501843e1988Sjohnlev (void) kbm_remap_window(new_table, 0); 502843e1988Sjohnlev #endif 503ae115bc7Smrj 504ae115bc7Smrj if (level == top_level && level == 2) 505ae115bc7Smrj *pteval = pa_to_ma(new_table) | PT_VALID; 506ae115bc7Smrj else 507ae115bc7Smrj *pteval = pa_to_ma(new_table) | 508ae115bc7Smrj PT_VALID | PT_REF | PT_USER | PT_WRITABLE; 509ae115bc7Smrj 510ae115bc7Smrj return (new_table); 511ae115bc7Smrj } 512ae115bc7Smrj 513ae115bc7Smrj x86pte_t * 514ae115bc7Smrj map_pte(paddr_t table, uint_t index) 515ae115bc7Smrj { 516ae115bc7Smrj void *table_ptr = kbm_remap_window(table, 0); 517ae115bc7Smrj return ((x86pte_t *)((caddr_t)table_ptr + index * pte_size)); 518ae115bc7Smrj } 519