/root/src/xen/xen/arch/x86/mm/hap/nested_ept.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * nested_ept.c: Handling virtulized EPT for guest in nested case. |
3 | | * |
4 | | * Copyright (c) 2012, Intel Corporation |
5 | | * Xiantao Zhang <xiantao.zhang@intel.com> |
6 | | * |
7 | | * This program is free software; you can redistribute it and/or modify it |
8 | | * under the terms and conditions of the GNU General Public License, |
9 | | * version 2, as published by the Free Software Foundation. |
10 | | * |
11 | | * This program is distributed in the hope it will be useful, but WITHOUT |
12 | | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
14 | | * more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License along with |
17 | | * this program; If not, see <http://www.gnu.org/licenses/>. |
18 | | */ |
19 | | #include <xen/vm_event.h> |
20 | | #include <xen/event.h> |
21 | | #include <public/vm_event.h> |
22 | | #include <asm/domain.h> |
23 | | #include <asm/page.h> |
24 | | #include <asm/paging.h> |
25 | | #include <asm/p2m.h> |
26 | | #include <asm/mem_sharing.h> |
27 | | #include <asm/hap.h> |
28 | | #include <asm/hvm/support.h> |
29 | | |
30 | | #include <asm/hvm/nestedhvm.h> |
31 | | |
32 | | #include "private.h" |
33 | | |
34 | | #include <asm/hvm/vmx/vmx.h> |
35 | | #include <asm/hvm/vmx/vvmx.h> |
36 | | |
37 | | /* Must reserved bits in all level entries */ |
38 | 0 | #define EPT_MUST_RSV_BITS (((1ull << PADDR_BITS) - 1) & \ |
39 | 0 | ~((1ull << paddr_bits) - 1)) |
40 | | |
41 | | #define NEPT_CAP_BITS \ |
42 | 0 | (VMX_EPT_INVEPT_ALL_CONTEXT | VMX_EPT_INVEPT_SINGLE_CONTEXT | \ |
43 | 0 | VMX_EPT_INVEPT_INSTRUCTION | VMX_EPT_SUPERPAGE_1GB | \ |
44 | 0 | VMX_EPT_SUPERPAGE_2MB | VMX_EPT_MEMORY_TYPE_WB | \ |
45 | 0 | VMX_EPT_MEMORY_TYPE_UC | VMX_EPT_WALK_LENGTH_4_SUPPORTED | \ |
46 | 0 | VMX_EPT_EXEC_ONLY_SUPPORTED) |
47 | | |
48 | | #define NVPID_CAP_BITS \ |
49 | 0 | (VMX_VPID_INVVPID_INSTRUCTION | VMX_VPID_INVVPID_INDIVIDUAL_ADDR | \ |
50 | 0 | VMX_VPID_INVVPID_SINGLE_CONTEXT | VMX_VPID_INVVPID_ALL_CONTEXT | \ |
51 | 0 | VMX_VPID_INVVPID_SINGLE_CONTEXT_RETAINING_GLOBAL) |
52 | | |
53 | 0 | #define NEPT_1G_ENTRY_FLAG (1 << 11) |
54 | 0 | #define NEPT_2M_ENTRY_FLAG (1 << 10) |
55 | 0 | #define NEPT_4K_ENTRY_FLAG (1 << 9) |
56 | | |
57 | | bool_t nept_sp_entry(ept_entry_t e) |
58 | 0 | { |
59 | 0 | return !!(e.sp); |
60 | 0 | } |
61 | | |
62 | | static bool_t nept_rsv_bits_check(ept_entry_t e, uint32_t level) |
63 | 0 | { |
64 | 0 | uint64_t rsv_bits = EPT_MUST_RSV_BITS; |
65 | 0 |
|
66 | 0 | switch ( level ) |
67 | 0 | { |
68 | 0 | case 1: |
69 | 0 | break; |
70 | 0 | case 2 ... 3: |
71 | 0 | if ( nept_sp_entry(e) ) |
72 | 0 | rsv_bits |= ((1ull << (9 * (level - 1))) - 1) << PAGE_SHIFT; |
73 | 0 | else |
74 | 0 | rsv_bits |= EPTE_EMT_MASK | EPTE_IGMT_MASK; |
75 | 0 | break; |
76 | 0 | case 4: |
77 | 0 | rsv_bits |= EPTE_EMT_MASK | EPTE_IGMT_MASK | EPTE_SUPER_PAGE_MASK; |
78 | 0 | break; |
79 | 0 | default: |
80 | 0 | gdprintk(XENLOG_ERR,"Unsupported EPT paging level: %d\n", level); |
81 | 0 | BUG(); |
82 | 0 | break; |
83 | 0 | } |
84 | 0 | return !!(e.epte & rsv_bits); |
85 | 0 | } |
86 | | |
87 | | /* EMT checking*/ |
88 | | static bool_t nept_emt_bits_check(ept_entry_t e, uint32_t level) |
89 | 0 | { |
90 | 0 | if ( e.sp || level == 1 ) |
91 | 0 | { |
92 | 0 | if ( e.emt == EPT_EMT_RSV0 || e.emt == EPT_EMT_RSV1 || |
93 | 0 | e.emt == EPT_EMT_RSV2 ) |
94 | 0 | return 1; |
95 | 0 | } |
96 | 0 | return 0; |
97 | 0 | } |
98 | | |
99 | | static bool_t nept_permission_check(uint32_t rwx_acc, uint32_t rwx_bits) |
100 | 0 | { |
101 | 0 | return !(EPTE_RWX_MASK & rwx_acc & ~rwx_bits); |
102 | 0 | } |
103 | | |
104 | | /* nept's non-present check */ |
105 | | static bool_t nept_non_present_check(ept_entry_t e) |
106 | 0 | { |
107 | 0 | if ( e.epte & EPTE_RWX_MASK ) |
108 | 0 | return 0; |
109 | 0 | return 1; |
110 | 0 | } |
111 | | |
112 | | uint64_t nept_get_ept_vpid_cap(void) |
113 | 0 | { |
114 | 0 | uint64_t caps = 0; |
115 | 0 |
|
116 | 0 | if ( cpu_has_vmx_ept ) |
117 | 0 | caps |= NEPT_CAP_BITS; |
118 | 0 | if ( !cpu_has_vmx_ept_exec_only_supported ) |
119 | 0 | caps &= ~VMX_EPT_EXEC_ONLY_SUPPORTED; |
120 | 0 | if ( cpu_has_vmx_vpid ) |
121 | 0 | caps |= NVPID_CAP_BITS; |
122 | 0 |
|
123 | 0 | return caps; |
124 | 0 | } |
125 | | |
126 | | static bool_t nept_rwx_bits_check(ept_entry_t e) |
127 | 0 | { |
128 | 0 | /*write only or write/execute only*/ |
129 | 0 | uint8_t rwx_bits = e.epte & EPTE_RWX_MASK; |
130 | 0 |
|
131 | 0 | if ( rwx_bits == ept_access_w || rwx_bits == ept_access_wx ) |
132 | 0 | return 1; |
133 | 0 |
|
134 | 0 | if ( rwx_bits == ept_access_x && |
135 | 0 | !(nept_get_ept_vpid_cap() & VMX_EPT_EXEC_ONLY_SUPPORTED) ) |
136 | 0 | return 1; |
137 | 0 |
|
138 | 0 | return 0; |
139 | 0 | } |
140 | | |
141 | | /* nept's misconfiguration check */ |
142 | | static bool_t nept_misconfiguration_check(ept_entry_t e, uint32_t level) |
143 | 0 | { |
144 | 0 | return nept_rsv_bits_check(e, level) || |
145 | 0 | nept_emt_bits_check(e, level) || |
146 | 0 | nept_rwx_bits_check(e); |
147 | 0 | } |
148 | | |
149 | | static int ept_lvl_table_offset(unsigned long gpa, int lvl) |
150 | 0 | { |
151 | 0 | return (gpa >> (EPT_L4_PAGETABLE_SHIFT -(4 - lvl) * 9)) & |
152 | 0 | (EPT_PAGETABLE_ENTRIES - 1); |
153 | 0 | } |
154 | | |
155 | | static uint32_t |
156 | | nept_walk_tables(struct vcpu *v, unsigned long l2ga, ept_walk_t *gw) |
157 | 0 | { |
158 | 0 | int lvl; |
159 | 0 | p2m_type_t p2mt; |
160 | 0 | uint32_t rc = 0, ret = 0, gflags; |
161 | 0 | struct domain *d = v->domain; |
162 | 0 | struct p2m_domain *p2m = d->arch.p2m; |
163 | 0 | gfn_t base_gfn = _gfn(nhvm_vcpu_p2m_base(v) >> PAGE_SHIFT); |
164 | 0 | mfn_t lxmfn; |
165 | 0 | ept_entry_t *lxp = NULL; |
166 | 0 |
|
167 | 0 | memset(gw, 0, sizeof(*gw)); |
168 | 0 |
|
169 | 0 | for (lvl = 4; lvl > 0; lvl--) |
170 | 0 | { |
171 | 0 | lxp = map_domain_gfn(p2m, base_gfn, &lxmfn, &p2mt, P2M_ALLOC, &rc); |
172 | 0 | if ( !lxp ) |
173 | 0 | goto map_err; |
174 | 0 | gw->lxe[lvl] = lxp[ept_lvl_table_offset(l2ga, lvl)]; |
175 | 0 | unmap_domain_page(lxp); |
176 | 0 | put_page(mfn_to_page(mfn_x(lxmfn))); |
177 | 0 |
|
178 | 0 | if ( nept_non_present_check(gw->lxe[lvl]) ) |
179 | 0 | goto non_present; |
180 | 0 |
|
181 | 0 | if ( nept_misconfiguration_check(gw->lxe[lvl], lvl) ) |
182 | 0 | goto misconfig_err; |
183 | 0 |
|
184 | 0 | if ( (lvl == 2 || lvl == 3) && nept_sp_entry(gw->lxe[lvl]) ) |
185 | 0 | { |
186 | 0 | /* Generate a fake l1 table entry so callers don't all |
187 | 0 | * have to understand superpages. */ |
188 | 0 | unsigned long gfn_lvl_mask = (1ull << ((lvl - 1) * 9)) - 1; |
189 | 0 | gfn_t start = _gfn(gw->lxe[lvl].mfn); |
190 | 0 | /* Increment the pfn by the right number of 4k pages. */ |
191 | 0 | start = _gfn((gfn_x(start) & ~gfn_lvl_mask) + |
192 | 0 | ((l2ga >> PAGE_SHIFT) & gfn_lvl_mask)); |
193 | 0 | gflags = (gw->lxe[lvl].epte & EPTE_FLAG_MASK) | |
194 | 0 | (lvl == 3 ? NEPT_1G_ENTRY_FLAG: NEPT_2M_ENTRY_FLAG); |
195 | 0 | gw->lxe[0].epte = (gfn_x(start) << PAGE_SHIFT) | gflags; |
196 | 0 | goto done; |
197 | 0 | } |
198 | 0 | if ( lvl > 1 ) |
199 | 0 | base_gfn = _gfn(gw->lxe[lvl].mfn); |
200 | 0 | } |
201 | 0 |
|
202 | 0 | /* If this is not a super entry, we can reach here. */ |
203 | 0 | gflags = (gw->lxe[1].epte & EPTE_FLAG_MASK) | NEPT_4K_ENTRY_FLAG; |
204 | 0 | gw->lxe[0].epte = (gw->lxe[1].epte & PAGE_MASK) | gflags; |
205 | 0 |
|
206 | 0 | done: |
207 | 0 | ret = EPT_TRANSLATE_SUCCEED; |
208 | 0 | goto out; |
209 | 0 |
|
210 | 0 | map_err: |
211 | 0 | if ( rc == PFEC_page_paged ) |
212 | 0 | { |
213 | 0 | ret = EPT_TRANSLATE_RETRY; |
214 | 0 | goto out; |
215 | 0 | } |
216 | 0 | /* fall through to misconfig error */ |
217 | 0 | misconfig_err: |
218 | 0 | ret = EPT_TRANSLATE_MISCONFIG; |
219 | 0 | goto out; |
220 | 0 |
|
221 | 0 | non_present: |
222 | 0 | ret = EPT_TRANSLATE_VIOLATION; |
223 | 0 | /* fall through. */ |
224 | 0 | out: |
225 | 0 | return ret; |
226 | 0 | } |
227 | | |
228 | | /* Translate a L2 guest address to L1 gpa via L1 EPT paging structure */ |
229 | | |
230 | | int nept_translate_l2ga(struct vcpu *v, paddr_t l2ga, |
231 | | unsigned int *page_order, uint32_t rwx_acc, |
232 | | unsigned long *l1gfn, uint8_t *p2m_acc, |
233 | | uint64_t *exit_qual, uint32_t *exit_reason) |
234 | 0 | { |
235 | 0 | uint32_t rc, rwx_bits = 0; |
236 | 0 | ept_walk_t gw; |
237 | 0 | rwx_acc &= EPTE_RWX_MASK; |
238 | 0 |
|
239 | 0 | *l1gfn = gfn_x(INVALID_GFN); |
240 | 0 |
|
241 | 0 | rc = nept_walk_tables(v, l2ga, &gw); |
242 | 0 | switch ( rc ) |
243 | 0 | { |
244 | 0 | case EPT_TRANSLATE_SUCCEED: |
245 | 0 | if ( likely(gw.lxe[0].epte & NEPT_2M_ENTRY_FLAG) ) |
246 | 0 | { |
247 | 0 | rwx_bits = gw.lxe[4].epte & gw.lxe[3].epte & gw.lxe[2].epte & |
248 | 0 | EPTE_RWX_MASK; |
249 | 0 | *page_order = 9; |
250 | 0 | } |
251 | 0 | else if ( gw.lxe[0].epte & NEPT_4K_ENTRY_FLAG ) |
252 | 0 | { |
253 | 0 | rwx_bits = gw.lxe[4].epte & gw.lxe[3].epte & gw.lxe[2].epte & |
254 | 0 | gw.lxe[1].epte & EPTE_RWX_MASK; |
255 | 0 | *page_order = 0; |
256 | 0 | } |
257 | 0 | else if ( gw.lxe[0].epte & NEPT_1G_ENTRY_FLAG ) |
258 | 0 | { |
259 | 0 | rwx_bits = gw.lxe[4].epte & gw.lxe[3].epte & EPTE_RWX_MASK; |
260 | 0 | *page_order = 18; |
261 | 0 | } |
262 | 0 | else |
263 | 0 | { |
264 | 0 | gdprintk(XENLOG_ERR, "Uncorrect l1 entry!\n"); |
265 | 0 | BUG(); |
266 | 0 | } |
267 | 0 | if ( nept_permission_check(rwx_acc, rwx_bits) ) |
268 | 0 | { |
269 | 0 | *l1gfn = gw.lxe[0].mfn; |
270 | 0 | *p2m_acc = (uint8_t)rwx_bits; |
271 | 0 | break; |
272 | 0 | } |
273 | 0 | rc = EPT_TRANSLATE_VIOLATION; |
274 | 0 | /* Fall through to EPT violation if permission check fails. */ |
275 | 0 | case EPT_TRANSLATE_VIOLATION: |
276 | 0 | *exit_qual = (*exit_qual & 0xffffffc0) | (rwx_bits << 3) | rwx_acc; |
277 | 0 | *exit_reason = EXIT_REASON_EPT_VIOLATION; |
278 | 0 | break; |
279 | 0 |
|
280 | 0 | case EPT_TRANSLATE_MISCONFIG: |
281 | 0 | rc = EPT_TRANSLATE_MISCONFIG; |
282 | 0 | *exit_qual = 0; |
283 | 0 | *exit_reason = EXIT_REASON_EPT_MISCONFIG; |
284 | 0 | break; |
285 | 0 | case EPT_TRANSLATE_RETRY: |
286 | 0 | break; |
287 | 0 | default: |
288 | 0 | gdprintk(XENLOG_ERR, "Unsupported ept translation type!:%d\n", rc); |
289 | 0 | BUG(); |
290 | 0 | break; |
291 | 0 | } |
292 | 0 | return rc; |
293 | 0 | } |