|  | /* Copyright (c) 2015 Google Inc. | 
|  | * Barret Rhoden <brho@cs.berkeley.edu> | 
|  | * See LICENSE for details. | 
|  | * | 
|  | * 64 bit EPT helpers */ | 
|  |  | 
|  | #pragma once | 
|  |  | 
|  | #include <arch/vmm/intel/vmx.h>	/* for sync/flush helpers */ | 
|  | #include <smp.h>				/* for current */ | 
|  |  | 
|  | /* Some EPTE PTE flags are only valid for the last PTEs in a walk */ | 
|  | #define EPTE_R					(1ULL << 0)		/* Readable */ | 
|  | #define EPTE_W					(1ULL << 1)		/* Writeable */ | 
|  | #define EPTE_X					(1ULL << 2)		/* Executable */ | 
|  | #define EPTE_MEM_BITS			(7ULL << 3)		/* Memory type specifier */ | 
|  | #define EPTE_IGN_PAT			(1ULL << 6)		/* Ignore PAT */ | 
|  | #define EPTE_PS					(1ULL << 7)		/* Jumbo Page Size */ | 
|  | #define EPTE_A					(1ULL << 8)		/* Accessed */ | 
|  | #define EPTE_D					(1ULL << 9)		/* Dirty */ | 
|  | #define EPTE_SUP_VE				(1ULL << 63)	/* Suppress virt exceptions */ | 
|  | #define EPTE_P (EPTE_R | EPTE_W | EPTE_X) | 
|  |  | 
|  | /* Types available for the EPTE_MEM_TYPE */ | 
|  | #define EPT_MEM_TYPE_UC			0 | 
|  | #define EPT_MEM_TYPE_WC			1 | 
|  | #define EPT_MEM_TYPE_WT			4 | 
|  | #define EPT_MEM_TYPE_WP			5 | 
|  | #define EPT_MEM_TYPE_WB			6 | 
|  | /* Helper to align the type to its location in the PTE */ | 
|  | #define EPT_MEM_TYPE(type) ((type) << 3) | 
|  |  | 
|  | /* Some machines don't support A and D EPTE bits.  We'll |= 1 in those cases. */ | 
|  | extern int x86_ept_pte_fix_ups; | 
|  |  | 
|  | static inline epte_t *kpte_to_epte(kpte_t *kpte) | 
|  | { | 
|  | return (epte_t*)(((uintptr_t)kpte) + PGSIZE); | 
|  | } | 
|  |  | 
|  | static inline bool epte_is_present(epte_t *epte) | 
|  | { | 
|  | /* Actually, certain combos, like W but not R could be misconfigurations */ | 
|  | return *epte & EPTE_P ? TRUE : FALSE; | 
|  | } | 
|  |  | 
|  | static inline bool epte_is_unmapped(epte_t *epte) | 
|  | { | 
|  | return *epte == 0; | 
|  | } | 
|  |  | 
|  | static inline bool epte_is_mapped(epte_t *epte) | 
|  | { | 
|  | return *epte != 0; | 
|  | } | 
|  |  | 
|  | static inline bool epte_is_paged_out(epte_t *epte) | 
|  | { | 
|  | return *epte != 0; | 
|  | } | 
|  |  | 
|  | /* Some Intel machines don't support A or D.  In these cases, we must assume | 
|  | * the pages have been accessed or dirtied... */ | 
|  | static inline bool epte_is_dirty(epte_t *epte) | 
|  | { | 
|  | return (*epte | x86_ept_pte_fix_ups) & EPTE_D ? TRUE : FALSE; | 
|  | } | 
|  |  | 
|  | static inline bool epte_is_accessed(epte_t *epte) | 
|  | { | 
|  | return (*epte | x86_ept_pte_fix_ups) & EPTE_A ? TRUE : FALSE; | 
|  | } | 
|  |  | 
|  | static inline bool epte_is_jumbo(epte_t *epte) | 
|  | { | 
|  | return *epte & EPTE_PS ? TRUE : FALSE; | 
|  | } | 
|  |  | 
|  | static inline physaddr_t epte_get_paddr(epte_t *epte) | 
|  | { | 
|  | /* 63:52 are ignored/flags.  51:12 are the addr.  Technically 51:N must be | 
|  | * 0, where N is the physical addr width */ | 
|  | return *epte & 0x000ffffffffff000; | 
|  | } | 
|  |  | 
|  | static inline int __pte_to_epte_perm(int perm) | 
|  | { | 
|  | switch (perm) { | 
|  | /* Since we keep the EPT in lockstep with the KPT, we might get some | 
|  | * mapping requests for the kernel (e.g. vmap_pmem).  */ | 
|  | case PTE_KERN_RW: | 
|  | case PTE_KERN_RO: | 
|  | case PTE_NONE: | 
|  | return 0; | 
|  | case PTE_USER_RW: | 
|  | return EPTE_W | EPTE_R | EPTE_X; | 
|  | case PTE_USER_RO: | 
|  | return EPTE_R | EPTE_X; | 
|  | default: | 
|  | panic("Bad PTE type 0x%x\n", perm); | 
|  | } | 
|  | } | 
|  |  | 
|  | static inline void epte_write(epte_t *epte, physaddr_t pa, int settings) | 
|  | { | 
|  | /* Could put in a check against the max physaddr len */ | 
|  | epte_t temp = pa; | 
|  | temp |= __pte_to_epte_perm(settings & PTE_PERM); | 
|  | temp |= settings & PTE_PS ? EPTE_PS : 0; | 
|  | /* All memory is WB by default, but the guest can override that with their | 
|  | * PAT on the first page walk (guest KPT/cr3) */ | 
|  | temp |= EPT_MEM_TYPE(EPT_MEM_TYPE_WB); | 
|  | *epte = temp; | 
|  | } | 
|  |  | 
|  | static inline void epte_clear_present(epte_t *epte) | 
|  | { | 
|  | *epte &= ~EPTE_P; | 
|  | } | 
|  |  | 
|  | static inline void epte_clear(epte_t *epte) | 
|  | { | 
|  | *epte = 0; | 
|  | } | 
|  |  | 
|  | static inline bool epte_has_perm_ur(epte_t *epte) | 
|  | { | 
|  | return (*epte & (EPTE_R | EPTE_X)) == (EPTE_R | EPTE_X); | 
|  | } | 
|  |  | 
|  | static inline bool epte_has_perm_urw(epte_t *epte) | 
|  | { | 
|  | return (*epte & (EPTE_R | EPTE_W | EPTE_X)) == (EPTE_R | EPTE_W | EPTE_X); | 
|  | } | 
|  |  | 
|  | static inline int epte_get_settings(epte_t *epte) | 
|  | { | 
|  | int settings = 0; | 
|  | if (*epte & EPTE_P) { | 
|  | /* We want to know User and Writable, in the 'PTE' sense.  All present | 
|  | * epte entries are User PTEs. */ | 
|  | settings |= PTE_P | PTE_U; | 
|  | settings |= *epte & EPTE_W ? PTE_W : 0; | 
|  | } | 
|  | settings |= *epte & EPTE_PS ? PTE_PS : 0; | 
|  | settings |= *epte & EPTE_A ? PTE_A : 0; | 
|  | settings |= *epte & EPTE_D ? PTE_D : 0; | 
|  | return settings; | 
|  | } | 
|  |  | 
|  | /* Again, we're replacing the old perms with U and/or W.  Any non-U are ignored, | 
|  | * as with epte_write.  */ | 
|  | static inline void epte_replace_perm(epte_t *epte, int perm) | 
|  | { | 
|  | *epte = (*epte & ~EPTE_P) | __pte_to_epte_perm(perm & PTE_PERM); | 
|  | } | 
|  |  | 
|  | /* These ops might be the same for AMD as Intel; in which case we can move the | 
|  | * body of these ept_sync_* funcs into here */ | 
|  | static inline void ept_inval_addr(unsigned long addr) | 
|  | { | 
|  | if (current && current->vmm.vmmcp) | 
|  | ept_sync_individual_addr(current->env_pgdir.eptp, addr); | 
|  | } | 
|  |  | 
|  | static inline void ept_inval_context(void) | 
|  | { | 
|  | if (current && current->vmm.vmmcp) | 
|  | ept_sync_context(current->env_pgdir.eptp); | 
|  | } | 
|  |  | 
|  | static inline void ept_inval_global(void) | 
|  | { | 
|  | ept_sync_global(); | 
|  | } |