akaros/kern/arch/x86/vmm/ept.h
<<
>>
Prefs
   1/* Copyright (c) 2015 Google Inc.
   2 * Barret Rhoden <brho@cs.berkeley.edu>
   3 * See LICENSE for details.
   4 *
   5 * 64 bit EPT helpers */
   6
   7#pragma once
   8
   9#include <arch/vmm/intel/vmx.h> /* for sync/flush helpers */
  10#include <smp.h>                                /* for current */
  11
  12/* Some EPTE PTE flags are only valid for the last PTEs in a walk */
  13#define EPTE_R                  (1ULL << 0)     /* Readable */
  14#define EPTE_W                  (1ULL << 1)     /* Writeable */
  15#define EPTE_X                  (1ULL << 2)     /* Executable */
  16#define EPTE_MEM_BITS           (7ULL << 3)     /* Memory type specifier */
  17#define EPTE_IGN_PAT            (1ULL << 6)     /* Ignore PAT */
  18#define EPTE_PS                 (1ULL << 7)     /* Jumbo Page Size */
  19#define EPTE_A                  (1ULL << 8)     /* Accessed */
  20#define EPTE_D                  (1ULL << 9)     /* Dirty */
  21#define EPTE_SUP_VE             (1ULL << 63)    /* Suppress virt exceptions */
  22#define EPTE_P (EPTE_R | EPTE_W | EPTE_X)
  23
  24/* Types available for the EPTE_MEM_TYPE */
  25#define EPT_MEM_TYPE_UC         0
  26#define EPT_MEM_TYPE_WC         1
  27#define EPT_MEM_TYPE_WT         4
  28#define EPT_MEM_TYPE_WP         5
  29#define EPT_MEM_TYPE_WB         6
  30/* Helper to align the type to its location in the PTE */
  31#define EPT_MEM_TYPE(type) ((type) << 3)
  32
  33/* Some machines don't support A and D EPTE bits.  We'll |= 1 in those cases. */
  34extern int x86_ept_pte_fix_ups;
  35
  36static inline epte_t *kpte_to_epte(kpte_t *kpte)
  37{
  38        return (epte_t*)(((uintptr_t)kpte) + PGSIZE);
  39}
  40
  41static inline bool epte_is_present(epte_t *epte)
  42{
  43        /* Actually, certain combos, like W but not R could be
  44         * misconfigurations. */
  45        return *epte & EPTE_P ? TRUE : FALSE;
  46}
  47
  48static inline bool epte_is_unmapped(epte_t *epte)
  49{
  50        return *epte == 0;
  51}
  52
  53static inline bool epte_is_mapped(epte_t *epte)
  54{
  55        return *epte != 0;
  56}
  57
  58static inline bool epte_is_paged_out(epte_t *epte)
  59{
  60        return *epte != 0;
  61}
  62
  63/* Some Intel machines don't support A or D.  In these cases, we must assume
  64 * the pages have been accessed or dirtied... */
  65static inline bool epte_is_dirty(epte_t *epte)
  66{
  67        return (*epte | x86_ept_pte_fix_ups) & EPTE_D ? TRUE : FALSE;
  68}
  69
  70static inline bool epte_is_accessed(epte_t *epte)
  71{
  72        return (*epte | x86_ept_pte_fix_ups) & EPTE_A ? TRUE : FALSE;
  73}
  74
  75static inline bool epte_is_jumbo(epte_t *epte)
  76{
  77        return *epte & EPTE_PS ? TRUE : FALSE;
  78}
  79
  80static inline physaddr_t epte_get_paddr(epte_t *epte)
  81{
  82        /* 63:52 are ignored/flags.  51:12 are the addr.  Technically 51:N must
  83         * be 0, where N is the physical addr width */
  84        return *epte & 0x000ffffffffff000;
  85}
  86
  87static inline int __pte_to_epte_perm(int perm)
  88{
  89        switch (perm) {
  90        /* Since we keep the EPT in lockstep with the KPT, we might get
  91         * some mapping requests for the kernel (e.g. vmap_pmem).  */
  92        case PTE_KERN_RW:
  93        case PTE_KERN_RO:
  94        case PTE_NONE:
  95                return 0;
  96        case PTE_USER_RW:
  97                return EPTE_W | EPTE_R | EPTE_X;
  98        case PTE_USER_RO:
  99                return EPTE_R | EPTE_X;
 100        default:
 101                panic("Bad PTE type 0x%x\n", perm);
 102        }
 103}
 104
 105static inline void epte_write(epte_t *epte, physaddr_t pa, int settings)
 106{
 107        /* Could put in a check against the max physaddr len */
 108        epte_t temp = pa;
 109        temp |= __pte_to_epte_perm(settings & PTE_PERM);
 110        temp |= settings & PTE_PS ? EPTE_PS : 0;
 111        /* All memory is WB by default, but the guest can override that with
 112         * their PAT on the first page walk (guest KPT/cr3) */
 113        temp |= EPT_MEM_TYPE(EPT_MEM_TYPE_WB);
 114        *epte = temp;
 115}
 116
 117static inline void epte_clear_present(epte_t *epte)
 118{
 119        *epte &= ~EPTE_P;
 120}
 121
 122static inline void epte_clear_dirty(epte_t *epte)
 123{
 124        *epte &= ~EPTE_D;
 125}
 126
 127static inline void epte_clear(epte_t *epte)
 128{
 129        *epte = 0;
 130}
 131
 132static inline bool epte_has_perm_ur(epte_t *epte)
 133{
 134        return (*epte & (EPTE_R | EPTE_X)) == (EPTE_R | EPTE_X);
 135}
 136
 137static inline bool epte_has_perm_urw(epte_t *epte)
 138{
 139        return (*epte & (EPTE_R | EPTE_W | EPTE_X)) == (EPTE_R | EPTE_W | EPTE_X);
 140}
 141
 142static inline int epte_get_settings(epte_t *epte)
 143{
 144        int settings = 0;
 145        if (*epte & EPTE_P) {
 146                /* We want to know User and Writable, in the 'PTE' sense.  All
 147                 * present epte entries are User PTEs. */
 148                settings |= PTE_P | PTE_U;
 149                settings |= *epte & EPTE_W ? PTE_W : 0;
 150        }
 151        settings |= *epte & EPTE_PS ? PTE_PS : 0;
 152        settings |= *epte & EPTE_A ? PTE_A : 0;
 153        settings |= *epte & EPTE_D ? PTE_D : 0;
 154        return settings;
 155}
 156
 157/* Again, we're replacing the old perms with U and/or W.  Any non-U are ignored,
 158 * as with epte_write.  */
 159static inline void epte_replace_perm(epte_t *epte, int perm)
 160{
 161        *epte = (*epte & ~EPTE_P) | __pte_to_epte_perm(perm & PTE_PERM);
 162}
 163
 164/* These ops might be the same for AMD as Intel; in which case we can move the
 165 * body of these ept_sync_* funcs into here */
 166static inline void ept_inval_addr(unsigned long addr)
 167{
 168        if (current && current->vmm.vmmcp)
 169                ept_sync_individual_addr(current->env_pgdir.eptp, addr);
 170}
 171
 172static inline void ept_inval_context(void)
 173{
 174        if (current && current->vmm.vmmcp)
 175                ept_sync_context(current->env_pgdir.eptp);
 176}
 177
 178static inline void ept_inval_global(void)
 179{
 180        ept_sync_global();
 181}
 182