Print this page
8956 Implement KPTI
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>


   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.


  25  */
  26 
  27 #include <sys/types.h>
  28 #include <sys/systm.h>
  29 #include <sys/archsystm.h>
  30 #include <sys/debug.h>
  31 #include <sys/bootconf.h>
  32 #include <sys/bootsvcs.h>
  33 #include <sys/bootinfo.h>
  34 #include <sys/mman.h>
  35 #include <sys/cmn_err.h>
  36 #include <sys/param.h>
  37 #include <sys/machparam.h>
  38 #include <sys/machsystm.h>
  39 #include <sys/promif.h>
  40 #include <sys/kobj.h>
  41 #ifdef __xpv
  42 #include <sys/hypervisor.h>
  43 #endif
  44 #include <vm/kboot_mmu.h>


 128  */
 129 /*ARGSUSED*/
 130 void *
 131 kbm_remap_window(paddr_t physaddr, int writeable)
 132 {
 133         x86pte_t pt_bits = PT_NOCONSIST | PT_VALID | PT_WRITABLE;
 134 
 135         DBG(physaddr);
 136 
 137 #ifdef __xpv
 138         if (!writeable)
 139                 pt_bits &= ~PT_WRITABLE;
 140         if (HYPERVISOR_update_va_mapping((uintptr_t)window,
 141             pa_to_ma(physaddr) | pt_bits, UVMF_INVLPG | UVMF_LOCAL) < 0)
 142                 bop_panic("HYPERVISOR_update_va_mapping() failed");
 143 #else
 144         if (kbm_pae_support)
 145                 *((x86pte_t *)pte_to_window) = physaddr | pt_bits;
 146         else
 147                 *((x86pte32_t *)pte_to_window) = physaddr | pt_bits;
 148         mmu_tlbflush_entry(window);
 149 #endif
 150         DBG(window);
 151         return (window);
 152 }
 153 
 154 /*
 155  * Add a mapping for the physical page at the given virtual address.
 156  */
 157 void
 158 kbm_map(uintptr_t va, paddr_t pa, uint_t level, uint_t is_kernel)
 159 {
 160         x86pte_t *ptep;
 161         paddr_t pte_physaddr;
 162         x86pte_t pteval;
 163 
 164         if (khat_running)
 165                 panic("kbm_map() called too late");
 166 
 167         pteval = pa_to_ma(pa) | PT_NOCONSIST | PT_VALID | PT_WRITABLE;
 168         if (level >= 1)


 178             UVMF_INVLPG | UVMF_LOCAL) == 0)
 179                 return;
 180 #endif
 181 
 182         /*
 183          * Find the pte that will map this address. This creates any
 184          * missing intermediate level page tables.
 185          */
 186         ptep = find_pte(va, &pte_physaddr, level, 0);
 187         if (ptep == NULL)
 188                 bop_panic("kbm_map: find_pte returned NULL");
 189 
 190 #ifdef __xpv
 191         if (HYPERVISOR_update_va_mapping(va, pteval, UVMF_INVLPG | UVMF_LOCAL))
 192                 bop_panic("HYPERVISOR_update_va_mapping() failed");
 193 #else
 194         if (kbm_pae_support)
 195                 *ptep = pteval;
 196         else
 197                 *((x86pte32_t *)ptep) = pteval;
 198         mmu_tlbflush_entry((caddr_t)va);
 199 #endif
 200 }
 201 
 202 #ifdef __xpv
 203 
 204 /*
 205  * Add a mapping for the machine page at the given virtual address.
 206  */
 207 void
 208 kbm_map_ma(maddr_t ma, uintptr_t va, uint_t level)
 209 {
 210         paddr_t pte_physaddr;
 211         x86pte_t pteval;
 212 
 213         pteval = ma | PT_NOCONSIST | PT_VALID | PT_REF | PT_WRITABLE;
 214         if (level == 1)
 215                 pteval |= PT_PAGESIZE;
 216 
 217         /*
 218          * try update_va_mapping first - fails if page table is missing.


 332 {
 333         if (khat_running)
 334                 panic("kbm_unmap() called too late");
 335         else {
 336 #ifdef __xpv
 337                 (void) HYPERVISOR_update_va_mapping(va, 0,
 338                     UVMF_INVLPG | UVMF_LOCAL);
 339 #else
 340                 x86pte_t *ptep;
 341                 level_t level = 0;
 342                 uint_t  probe_only = 1;
 343 
 344                 ptep = find_pte(va, NULL, level, probe_only);
 345                 if (ptep == NULL)
 346                         return;
 347 
 348                 if (kbm_pae_support)
 349                         *ptep = 0;
 350                 else
 351                         *((x86pte32_t *)ptep) = 0;
 352                 mmu_tlbflush_entry((caddr_t)va);
 353 #endif
 354         }
 355 }
 356 
 357 
 358 /*
 359  * Change a boot loader page table 4K mapping.
 360  * Returns the pfn of the old mapping.
 361  */
 362 pfn_t
 363 kbm_remap(uintptr_t va, pfn_t pfn)
 364 {
 365         x86pte_t *ptep;
 366         level_t level = 0;
 367         uint_t  probe_only = 1;
 368         x86pte_t pte_val = pa_to_ma(pfn_to_pa(pfn)) | PT_WRITABLE |
 369             PT_NOCONSIST | PT_VALID;
 370         x86pte_t old_pte;
 371 
 372         if (khat_running)
 373                 panic("kbm_remap() called too late");
 374         ptep = find_pte(va, NULL, level, probe_only);
 375         if (ptep == NULL)
 376                 bop_panic("kbm_remap: find_pte returned NULL");
 377 
 378         if (kbm_pae_support)
 379                 old_pte = *ptep;
 380         else
 381                 old_pte = *((x86pte32_t *)ptep);
 382 
 383 #ifdef __xpv
 384         if (HYPERVISOR_update_va_mapping(va, pte_val, UVMF_INVLPG | UVMF_LOCAL))
 385                 bop_panic("HYPERVISOR_update_va_mapping() failed");
 386 #else
 387         if (kbm_pae_support)
 388                 *((x86pte_t *)ptep) = pte_val;
 389         else
 390                 *((x86pte32_t *)ptep) = pte_val;
 391         mmu_tlbflush_entry((caddr_t)va);
 392 #endif
 393 
 394         if (!(old_pte & PT_VALID) || ma_to_pa(old_pte) == -1)
 395                 return (PFN_INVALID);
 396         return (mmu_btop(ma_to_pa(old_pte)));
 397 }
 398 
 399 
 400 /*
 401  * Change a boot loader page table 4K mapping to read only.
 402  */
 403 void
 404 kbm_read_only(uintptr_t va, paddr_t pa)
 405 {
 406         x86pte_t pte_val = pa_to_ma(pa) |
 407             PT_NOCONSIST | PT_REF | PT_MOD | PT_VALID;
 408 
 409 #ifdef __xpv
 410         if (HYPERVISOR_update_va_mapping(va, pte_val, UVMF_INVLPG | UVMF_LOCAL))
 411                 bop_panic("HYPERVISOR_update_va_mapping() failed");
 412 #else
 413         x86pte_t *ptep;
 414         level_t level = 0;
 415 
 416         ptep = find_pte(va, NULL, level, 0);
 417         if (ptep == NULL)
 418                 bop_panic("kbm_read_only: find_pte returned NULL");
 419 
 420         if (kbm_pae_support)
 421                 *ptep = pte_val;
 422         else
 423                 *((x86pte32_t *)ptep) = pte_val;
 424         mmu_tlbflush_entry((caddr_t)va);
 425 #endif
 426 }
 427 
 428 /*
 429  * interfaces for kernel debugger to access physical memory
 430  */
 431 static x86pte_t save_pte;
 432 
 433 void *
 434 kbm_push(paddr_t pa)
 435 {
 436         static int first_time = 1;
 437 
 438         if (first_time) {
 439                 first_time = 0;
 440                 return (window);
 441         }
 442 
 443         if (kbm_pae_support)
 444                 save_pte = *((x86pte_t *)pte_to_window);
 445         else
 446                 save_pte = *((x86pte32_t *)pte_to_window);
 447         return (kbm_remap_window(pa, 0));
 448 }
 449 
 450 void
 451 kbm_pop(void)
 452 {
 453 #ifdef __xpv
 454         if (HYPERVISOR_update_va_mapping((uintptr_t)window, save_pte,
 455             UVMF_INVLPG | UVMF_LOCAL) < 0)
 456                 bop_panic("HYPERVISOR_update_va_mapping() failed");
 457 #else
 458         if (kbm_pae_support)
 459                 *((x86pte_t *)pte_to_window) = save_pte;
 460         else
 461                 *((x86pte32_t *)pte_to_window) = save_pte;
 462         mmu_tlbflush_entry(window);
 463 #endif
 464 }
 465 
 466 x86pte_t
 467 get_pteval(paddr_t table, uint_t index)
 468 {
 469         void *table_ptr = kbm_remap_window(table, 0);
 470 
 471         if (kbm_pae_support)
 472                 return (((x86pte_t *)table_ptr)[index]);
 473         return (((x86pte32_t *)table_ptr)[index]);
 474 }
 475 
 476 #ifndef __xpv
 477 void
 478 set_pteval(paddr_t table, uint_t index, uint_t level, x86pte_t pteval)
 479 {
 480         void *table_ptr = kbm_remap_window(table, 0);
 481         if (kbm_pae_support)
 482                 ((x86pte_t *)table_ptr)[index] = pteval;




   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  *
  26  * Copyright 2018 Joyent, Inc.
  27  */
  28 
  29 #include <sys/types.h>
  30 #include <sys/systm.h>
  31 #include <sys/archsystm.h>
  32 #include <sys/debug.h>
  33 #include <sys/bootconf.h>
  34 #include <sys/bootsvcs.h>
  35 #include <sys/bootinfo.h>
  36 #include <sys/mman.h>
  37 #include <sys/cmn_err.h>
  38 #include <sys/param.h>
  39 #include <sys/machparam.h>
  40 #include <sys/machsystm.h>
  41 #include <sys/promif.h>
  42 #include <sys/kobj.h>
  43 #ifdef __xpv
  44 #include <sys/hypervisor.h>
  45 #endif
  46 #include <vm/kboot_mmu.h>


 130  */
 131 /*ARGSUSED*/
 132 void *
 133 kbm_remap_window(paddr_t physaddr, int writeable)
 134 {
 135         x86pte_t pt_bits = PT_NOCONSIST | PT_VALID | PT_WRITABLE;
 136 
 137         DBG(physaddr);
 138 
 139 #ifdef __xpv
 140         if (!writeable)
 141                 pt_bits &= ~PT_WRITABLE;
 142         if (HYPERVISOR_update_va_mapping((uintptr_t)window,
 143             pa_to_ma(physaddr) | pt_bits, UVMF_INVLPG | UVMF_LOCAL) < 0)
 144                 bop_panic("HYPERVISOR_update_va_mapping() failed");
 145 #else
 146         if (kbm_pae_support)
 147                 *((x86pte_t *)pte_to_window) = physaddr | pt_bits;
 148         else
 149                 *((x86pte32_t *)pte_to_window) = physaddr | pt_bits;
 150         mmu_invlpg(window);
 151 #endif
 152         DBG(window);
 153         return (window);
 154 }
 155 
 156 /*
 157  * Add a mapping for the physical page at the given virtual address.
 158  */
 159 void
 160 kbm_map(uintptr_t va, paddr_t pa, uint_t level, uint_t is_kernel)
 161 {
 162         x86pte_t *ptep;
 163         paddr_t pte_physaddr;
 164         x86pte_t pteval;
 165 
 166         if (khat_running)
 167                 panic("kbm_map() called too late");
 168 
 169         pteval = pa_to_ma(pa) | PT_NOCONSIST | PT_VALID | PT_WRITABLE;
 170         if (level >= 1)


 180             UVMF_INVLPG | UVMF_LOCAL) == 0)
 181                 return;
 182 #endif
 183 
 184         /*
 185          * Find the pte that will map this address. This creates any
 186          * missing intermediate level page tables.
 187          */
 188         ptep = find_pte(va, &pte_physaddr, level, 0);
 189         if (ptep == NULL)
 190                 bop_panic("kbm_map: find_pte returned NULL");
 191 
 192 #ifdef __xpv
 193         if (HYPERVISOR_update_va_mapping(va, pteval, UVMF_INVLPG | UVMF_LOCAL))
 194                 bop_panic("HYPERVISOR_update_va_mapping() failed");
 195 #else
 196         if (kbm_pae_support)
 197                 *ptep = pteval;
 198         else
 199                 *((x86pte32_t *)ptep) = pteval;
 200         mmu_invlpg((caddr_t)va);
 201 #endif
 202 }
 203 
 204 #ifdef __xpv
 205 
 206 /*
 207  * Add a mapping for the machine page at the given virtual address.
 208  */
 209 void
 210 kbm_map_ma(maddr_t ma, uintptr_t va, uint_t level)
 211 {
 212         paddr_t pte_physaddr;
 213         x86pte_t pteval;
 214 
 215         pteval = ma | PT_NOCONSIST | PT_VALID | PT_REF | PT_WRITABLE;
 216         if (level == 1)
 217                 pteval |= PT_PAGESIZE;
 218 
 219         /*
 220          * try update_va_mapping first - fails if page table is missing.


 334 {
 335         if (khat_running)
 336                 panic("kbm_unmap() called too late");
 337         else {
 338 #ifdef __xpv
 339                 (void) HYPERVISOR_update_va_mapping(va, 0,
 340                     UVMF_INVLPG | UVMF_LOCAL);
 341 #else
 342                 x86pte_t *ptep;
 343                 level_t level = 0;
 344                 uint_t  probe_only = 1;
 345 
 346                 ptep = find_pte(va, NULL, level, probe_only);
 347                 if (ptep == NULL)
 348                         return;
 349 
 350                 if (kbm_pae_support)
 351                         *ptep = 0;
 352                 else
 353                         *((x86pte32_t *)ptep) = 0;
 354                 mmu_invlpg((caddr_t)va);
 355 #endif
 356         }
 357 }
 358 
 359 
 360 /*
 361  * Change a boot loader page table 4K mapping.
 362  * Returns the pfn of the old mapping.
 363  */
 364 pfn_t
 365 kbm_remap(uintptr_t va, pfn_t pfn)
 366 {
 367         x86pte_t *ptep;
 368         level_t level = 0;
 369         uint_t  probe_only = 1;
 370         x86pte_t pte_val = pa_to_ma(pfn_to_pa(pfn)) | PT_WRITABLE |
 371             PT_NOCONSIST | PT_VALID;
 372         x86pte_t old_pte;
 373 
 374         if (khat_running)
 375                 panic("kbm_remap() called too late");
 376         ptep = find_pte(va, NULL, level, probe_only);
 377         if (ptep == NULL)
 378                 bop_panic("kbm_remap: find_pte returned NULL");
 379 
 380         if (kbm_pae_support)
 381                 old_pte = *ptep;
 382         else
 383                 old_pte = *((x86pte32_t *)ptep);
 384 
 385 #ifdef __xpv
 386         if (HYPERVISOR_update_va_mapping(va, pte_val, UVMF_INVLPG | UVMF_LOCAL))
 387                 bop_panic("HYPERVISOR_update_va_mapping() failed");
 388 #else
 389         if (kbm_pae_support)
 390                 *((x86pte_t *)ptep) = pte_val;
 391         else
 392                 *((x86pte32_t *)ptep) = pte_val;
 393         mmu_invlpg((caddr_t)va);
 394 #endif
 395 
 396         if (!(old_pte & PT_VALID) || ma_to_pa(old_pte) == -1)
 397                 return (PFN_INVALID);
 398         return (mmu_btop(ma_to_pa(old_pte)));
 399 }
 400 
 401 
 402 /*
 403  * Change a boot loader page table 4K mapping to read only.
 404  */
 405 void
 406 kbm_read_only(uintptr_t va, paddr_t pa)
 407 {
 408         x86pte_t pte_val = pa_to_ma(pa) |
 409             PT_NOCONSIST | PT_REF | PT_MOD | PT_VALID;
 410 
 411 #ifdef __xpv
 412         if (HYPERVISOR_update_va_mapping(va, pte_val, UVMF_INVLPG | UVMF_LOCAL))
 413                 bop_panic("HYPERVISOR_update_va_mapping() failed");
 414 #else
 415         x86pte_t *ptep;
 416         level_t level = 0;
 417 
 418         ptep = find_pte(va, NULL, level, 0);
 419         if (ptep == NULL)
 420                 bop_panic("kbm_read_only: find_pte returned NULL");
 421 
 422         if (kbm_pae_support)
 423                 *ptep = pte_val;
 424         else
 425                 *((x86pte32_t *)ptep) = pte_val;
 426         mmu_invlpg((caddr_t)va);
 427 #endif
 428 }
 429 
 430 /*
 431  * interfaces for kernel debugger to access physical memory
 432  */
 433 static x86pte_t save_pte;
 434 
 435 void *
 436 kbm_push(paddr_t pa)
 437 {
 438         static int first_time = 1;
 439 
 440         if (first_time) {
 441                 first_time = 0;
 442                 return (window);
 443         }
 444 
 445         if (kbm_pae_support)
 446                 save_pte = *((x86pte_t *)pte_to_window);
 447         else
 448                 save_pte = *((x86pte32_t *)pte_to_window);
 449         return (kbm_remap_window(pa, 0));
 450 }
 451 
 452 void
 453 kbm_pop(void)
 454 {
 455 #ifdef __xpv
 456         if (HYPERVISOR_update_va_mapping((uintptr_t)window, save_pte,
 457             UVMF_INVLPG | UVMF_LOCAL) < 0)
 458                 bop_panic("HYPERVISOR_update_va_mapping() failed");
 459 #else
 460         if (kbm_pae_support)
 461                 *((x86pte_t *)pte_to_window) = save_pte;
 462         else
 463                 *((x86pte32_t *)pte_to_window) = save_pte;
 464         mmu_invlpg(window);
 465 #endif
 466 }
 467 
 468 x86pte_t
 469 get_pteval(paddr_t table, uint_t index)
 470 {
 471         void *table_ptr = kbm_remap_window(table, 0);
 472 
 473         if (kbm_pae_support)
 474                 return (((x86pte_t *)table_ptr)[index]);
 475         return (((x86pte32_t *)table_ptr)[index]);
 476 }
 477 
 478 #ifndef __xpv
 479 void
 480 set_pteval(paddr_t table, uint_t index, uint_t level, x86pte_t pteval)
 481 {
 482         void *table_ptr = kbm_remap_window(table, 0);
 483         if (kbm_pae_support)
 484                 ((x86pte_t *)table_ptr)[index] = pteval;