xref: /illumos-gate/usr/src/uts/intel/io/vmm/vmm_sol_ept.c (revision da3b00f42ac14fc3d37aa0e149de7e9832c37b6d)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 /* This file is dual-licensed; see usr/src/contrib/bhyve/LICENSE */
12 
13 /*
14  * Copyright 2019 Joyent, Inc.
15  * Copyright 2025 Oxide Computer Company
16  */
17 
18 #include <sys/vmm_gpt_impl.h>
19 #include <sys/debug.h>
20 
21 #define	EPT_R		(1 << 0)
22 #define	EPT_W		(1 << 1)
23 #define	EPT_X		(1 << 2)
24 #define	EPT_RWX		(EPT_R | EPT_W | EPT_X)
25 #define	EPT_LGPG	(1 << 7)
26 #define	EPT_ACCESSED	(1 << 8)
27 #define	EPT_DIRTY	(1 << 9)
28 
29 #define	EPT_PA_MASK	(0x000ffffffffff000ull)
30 
31 #define	EPT_MAX_LEVELS	4
32 
33 #define	EPTP_FLAG_ACCESSED_DIRTY	(1 << 6)
34 
35 CTASSERT(EPT_R == PROT_READ);
36 CTASSERT(EPT_W == PROT_WRITE);
37 CTASSERT(EPT_X == PROT_EXEC);
38 
39 static inline uint64_t
40 ept_attr_to_pat(uint8_t attr)
41 {
42 	uint64_t bits = attr & 0x7;
43 	return (bits << 3);
44 }
45 
46 static uint64_t
47 ept_map_table(uint64_t pfn)
48 {
49 	const uint64_t paddr = pfn_to_pa(pfn) & EPT_PA_MASK;
50 	return (paddr | EPT_RWX);
51 }
52 
53 static uint64_t
54 ept_map_page(uint64_t pfn, uint_t prot, uint8_t attr)
55 {
56 	const uint64_t paddr = pfn_to_pa(pfn) & EPT_PA_MASK;
57 	const uint64_t pat = ept_attr_to_pat(attr);
58 	const uint64_t rprot = prot & EPT_RWX;
59 	return (paddr | pat | rprot);
60 }
61 
62 static bool
63 ept_pte_parse(uint64_t pte, pfn_t *pfnp, uint_t *protp)
64 {
65 	const uint_t prot = pte & EPT_RWX;
66 
67 	if (prot == 0) {
68 		return (false);
69 	}
70 
71 	if (pfnp != NULL) {
72 		*pfnp = (pte & PT_PADDR) >> PAGESHIFT;
73 	}
74 	if (protp != NULL) {
75 		*protp = prot;
76 	}
77 	return (true);
78 }
79 
80 static uint64_t
81 ept_get_pmtp(pfn_t root_pfn, bool track_dirty)
82 {
83 	const uint64_t ad_flag = track_dirty ? EPTP_FLAG_ACCESSED_DIRTY : 0;
84 	return ((root_pfn << PAGESHIFT | ad_flag |
85 	    (EPT_MAX_LEVELS - 1) << 3 | MTRR_TYPE_WB));
86 }
87 
88 static bool
89 ept_hw_ad_supported(void)
90 {
91 	uint64_t ept_caps = rdmsr(MSR_IA32_VMX_EPT_VPID_CAP);
92 	return ((ept_caps & IA32_VMX_EPT_VPID_HW_AD) != 0);
93 }
94 
95 const struct vmm_pte_impl ept_pte_impl = {
96 	.vpi_map_table		= ept_map_table,
97 	.vpi_map_page		= ept_map_page,
98 	.vpi_pte_parse		= ept_pte_parse,
99 	.vpi_bit_accessed	= EPT_ACCESSED,
100 	.vpi_bit_dirty		= EPT_DIRTY,
101 
102 	.vpi_get_pmtp		= ept_get_pmtp,
103 	.vpi_hw_ad_supported	= ept_hw_ad_supported,
104 };
105