| /* 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_dirty(epte_t *epte) | 
 | { | 
 | 	*epte &= ~EPTE_D; | 
 | } | 
 |  | 
 | 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(); | 
 | } |