1 /*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7 #include <config.h>
8 #include <types.h>
9 #include <api/failures.h>
10 #include <kernel/vspace.h>
11 #include <object/structures.h>
12 #include <arch/machine.h>
13 #include <arch/model/statedata.h>
14 #include <machine/fpu.h>
15 #include <arch/object/objecttype.h>
16 #include <arch/object/ioport.h>
17 #include <plat/machine/devices.h>
18
19 #include <arch/object/iospace.h>
20 #include <arch/object/vcpu.h>
21 #include <plat/machine/intel-vtd.h>
22
Arch_deriveCap(cte_t * slot,cap_t cap)23 deriveCap_ret_t Arch_deriveCap(cte_t *slot, cap_t cap)
24 {
25 deriveCap_ret_t ret;
26
27 switch (cap_get_capType(cap)) {
28 case cap_page_table_cap:
29 if (cap_page_table_cap_get_capPTIsMapped(cap)) {
30 ret.cap = cap;
31 ret.status = EXCEPTION_NONE;
32 } else {
33 userError("Deriving an unmapped PT cap");
34 current_syscall_error.type = seL4_IllegalOperation;
35 ret.cap = cap_null_cap_new();
36 ret.status = EXCEPTION_SYSCALL_ERROR;
37 }
38 return ret;
39
40 case cap_page_directory_cap:
41 if (cap_page_directory_cap_get_capPDIsMapped(cap)) {
42 ret.cap = cap;
43 ret.status = EXCEPTION_NONE;
44 } else {
45 userError("Deriving a PD cap without an assigned ASID");
46 current_syscall_error.type = seL4_IllegalOperation;
47 ret.cap = cap_null_cap_new();
48 ret.status = EXCEPTION_SYSCALL_ERROR;
49 }
50 return ret;
51
52 case cap_asid_control_cap:
53 case cap_asid_pool_cap:
54 ret.cap = cap;
55 ret.status = EXCEPTION_NONE;
56 return ret;
57 case cap_io_port_control_cap:
58 ret.status = EXCEPTION_NONE;
59 ret.cap = cap_null_cap_new();
60 return ret;
61 case cap_io_port_cap:
62 ret.cap = cap;
63 ret.status = EXCEPTION_NONE;
64 return ret;
65
66 #ifdef CONFIG_IOMMU
67 case cap_io_space_cap:
68 ret.cap = cap;
69 ret.status = EXCEPTION_NONE;
70 return ret;
71 case cap_io_page_table_cap:
72 if (cap_io_page_table_cap_get_capIOPTIsMapped(cap)) {
73 ret.cap = cap;
74 ret.status = EXCEPTION_NONE;
75 } else {
76 current_syscall_error.type = seL4_IllegalOperation;
77 ret.cap = cap_null_cap_new();
78 ret.status = EXCEPTION_SYSCALL_ERROR;
79 }
80 return ret;
81 #endif
82
83 #ifdef CONFIG_VTX
84 case cap_vcpu_cap:
85 ret.cap = cap;
86 ret.status = EXCEPTION_NONE;
87 return ret;
88 case cap_ept_pml4_cap:
89 if (cap_ept_pml4_cap_get_capPML4IsMapped(cap)) {
90 ret.cap = cap;
91 ret.status = EXCEPTION_NONE;
92 } else {
93 userError("Deriving a EPT PML4 cap without an assigned ASID.");
94 current_syscall_error.type = seL4_IllegalOperation;
95 ret.cap = cap_null_cap_new();
96 ret.status = EXCEPTION_SYSCALL_ERROR;
97 }
98 return ret;
99 case cap_ept_pdpt_cap:
100 if (cap_ept_pdpt_cap_get_capPDPTIsMapped(cap)) {
101 ret.cap = cap;
102 ret.status = EXCEPTION_NONE;
103 } else {
104 userError("Deriving an unmapped EPT PDPT cap.");
105 current_syscall_error.type = seL4_IllegalOperation;
106 ret.cap = cap_null_cap_new();
107 ret.status = EXCEPTION_SYSCALL_ERROR;
108 }
109 return ret;
110
111 case cap_ept_pd_cap:
112 if (cap_ept_pd_cap_get_capPDIsMapped(cap)) {
113 ret.cap = cap;
114 ret.status = EXCEPTION_NONE;
115 } else {
116 userError("Deriving an unmapped EPT PD cap.");
117 current_syscall_error.type = seL4_IllegalOperation;
118 ret.cap = cap_null_cap_new();
119 ret.status = EXCEPTION_SYSCALL_ERROR;
120 }
121 return ret;
122
123 case cap_ept_pt_cap:
124 if (cap_ept_pt_cap_get_capPTIsMapped(cap)) {
125 ret.cap = cap;
126 ret.status = EXCEPTION_NONE;
127 } else {
128 userError("Deriving an unmapped EPT PT cap.");
129 current_syscall_error.type = seL4_IllegalOperation;
130 ret.cap = cap_null_cap_new();
131 ret.status = EXCEPTION_SYSCALL_ERROR;
132 }
133 return ret;
134 #endif
135
136 default:
137 return Mode_deriveCap(slot, cap);
138 }
139 }
140
Arch_updateCapData(bool_t preserve,word_t data,cap_t cap)141 cap_t CONST Arch_updateCapData(bool_t preserve, word_t data, cap_t cap)
142 {
143 /* Avoid a switch statement with just a 'default' case as the C parser does not like this */
144 #ifdef CONFIG_IOMMU
145 switch (cap_get_capType(cap)) {
146 case cap_io_space_cap: {
147 io_space_capdata_t w = { { data } };
148 uint16_t PCIDevice = io_space_capdata_get_PCIDevice(w);
149 uint16_t domainID = io_space_capdata_get_domainID(w);
150 if (!preserve && cap_io_space_cap_get_capPCIDevice(cap) == 0 &&
151 domainID >= x86KSFirstValidIODomain &&
152 domainID != 0 &&
153 domainID <= MASK(x86KSnumIODomainIDBits)) {
154 return cap_io_space_cap_new(domainID, PCIDevice);
155 } else {
156 return cap_null_cap_new();
157 }
158 }
159
160 default:
161 return cap;
162 }
163 #endif
164 return cap;
165 }
166
Arch_maskCapRights(seL4_CapRights_t cap_rights_mask,cap_t cap)167 cap_t CONST Arch_maskCapRights(seL4_CapRights_t cap_rights_mask, cap_t cap)
168 {
169 if (cap_get_capType(cap) == cap_frame_cap) {
170 vm_rights_t vm_rights;
171
172 vm_rights = vmRightsFromWord(cap_frame_cap_get_capFVMRights(cap));
173 vm_rights = maskVMRights(vm_rights, cap_rights_mask);
174 return cap_frame_cap_set_capFVMRights(cap, wordFromVMRights(vm_rights));
175 } else {
176 return cap;
177 }
178 }
179
Arch_finaliseCap(cap_t cap,bool_t final)180 finaliseCap_ret_t Arch_finaliseCap(cap_t cap, bool_t final)
181 {
182 finaliseCap_ret_t fc_ret;
183
184 switch (cap_get_capType(cap)) {
185 case cap_page_directory_cap:
186 if (final && cap_page_directory_cap_get_capPDIsMapped(cap)) {
187 unmapPageDirectory(
188 cap_page_directory_cap_get_capPDMappedASID(cap),
189 cap_page_directory_cap_get_capPDMappedAddress(cap),
190 PDE_PTR(cap_page_directory_cap_get_capPDBasePtr(cap))
191 );
192 }
193 break;
194
195 case cap_page_table_cap:
196 if (final && cap_page_table_cap_get_capPTIsMapped(cap)) {
197 unmapPageTable(
198 cap_page_table_cap_get_capPTMappedASID(cap),
199 cap_page_table_cap_get_capPTMappedAddress(cap),
200 PT_PTR(cap_page_table_cap_get_capPTBasePtr(cap))
201 );
202 }
203 break;
204
205 case cap_asid_pool_cap:
206 if (final) {
207 deleteASIDPool(
208 cap_asid_pool_cap_get_capASIDBase(cap),
209 ASID_POOL_PTR(cap_asid_pool_cap_get_capASIDPool(cap))
210 );
211 }
212 break;
213 case cap_asid_control_cap:
214 case cap_io_port_control_cap:
215 break;
216 case cap_io_port_cap:
217 #ifdef CONFIG_VTX
218 clearVPIDIOPortMappings(cap_io_port_cap_get_capIOPortVPID(cap),
219 cap_io_port_cap_get_capIOPortFirstPort(cap),
220 cap_io_port_cap_get_capIOPortLastPort(cap));
221 #endif
222 if (final) {
223 fc_ret.remainder = cap_null_cap_new();
224 fc_ret.cleanupInfo = cap;
225 return fc_ret;
226 }
227 break;
228 #ifdef CONFIG_IOMMU
229 case cap_io_space_cap:
230 if (final) {
231 unmapVTDContextEntry(cap);
232 }
233 break;
234
235 case cap_io_page_table_cap:
236 if (final && cap_io_page_table_cap_get_capIOPTIsMapped(cap)) {
237 deleteIOPageTable(cap);
238 }
239 break;
240 #endif
241
242 #ifdef CONFIG_VTX
243 case cap_vcpu_cap:
244 if (final) {
245 vcpu_finalise(VCPU_PTR(cap_vcpu_cap_get_capVCPUPtr(cap)));
246 }
247 break;
248 case cap_ept_pml4_cap:
249 if (final && cap_ept_pml4_cap_get_capPML4IsMapped(cap)) {
250 deleteEPTASID(cap_ept_pml4_cap_get_capPML4MappedASID(cap),
251 (ept_pml4e_t *)cap_ept_pml4_cap_get_capPML4BasePtr(cap));
252 }
253 break;
254
255 case cap_ept_pdpt_cap:
256 if (final && cap_ept_pdpt_cap_get_capPDPTIsMapped(cap)) {
257 unmapEPTPDPT(
258 cap_ept_pdpt_cap_get_capPDPTMappedASID(cap),
259 cap_ept_pdpt_cap_get_capPDPTMappedAddress(cap),
260 (ept_pdpte_t *)cap_ept_pdpt_cap_get_capPDPTBasePtr(cap));
261 }
262 break;
263
264 case cap_ept_pd_cap:
265 if (final && cap_ept_pd_cap_get_capPDIsMapped(cap)) {
266 unmapEPTPageDirectory(
267 cap_ept_pd_cap_get_capPDMappedASID(cap),
268 cap_ept_pd_cap_get_capPDMappedAddress(cap),
269 (ept_pde_t *)cap_ept_pd_cap_get_capPDBasePtr(cap));
270 }
271 break;
272
273 case cap_ept_pt_cap:
274 if (final && cap_ept_pt_cap_get_capPTIsMapped(cap)) {
275 unmapEPTPageTable(
276 cap_ept_pt_cap_get_capPTMappedASID(cap),
277 cap_ept_pt_cap_get_capPTMappedAddress(cap),
278 (ept_pte_t *)cap_ept_pt_cap_get_capPTBasePtr(cap));
279 }
280 break;
281 #endif
282
283 default:
284 return Mode_finaliseCap(cap, final);
285 }
286
287 fc_ret.remainder = cap_null_cap_new();
288 fc_ret.cleanupInfo = cap_null_cap_new();
289 return fc_ret;
290 }
291
Arch_sameRegionAs(cap_t cap_a,cap_t cap_b)292 bool_t CONST Arch_sameRegionAs(cap_t cap_a, cap_t cap_b)
293 {
294 switch (cap_get_capType(cap_a)) {
295 case cap_frame_cap:
296 if (cap_get_capType(cap_b) == cap_frame_cap) {
297 word_t botA, botB, topA, topB;
298 botA = cap_frame_cap_get_capFBasePtr(cap_a);
299 botB = cap_frame_cap_get_capFBasePtr(cap_b);
300 topA = botA + MASK(pageBitsForSize(cap_frame_cap_get_capFSize(cap_a)));
301 topB = botB + MASK(pageBitsForSize(cap_frame_cap_get_capFSize(cap_b)));
302 return ((botA <= botB) && (topA >= topB) && (botB <= topB));
303 }
304 break;
305
306 case cap_page_table_cap:
307 if (cap_get_capType(cap_b) == cap_page_table_cap) {
308 return cap_page_table_cap_get_capPTBasePtr(cap_a) ==
309 cap_page_table_cap_get_capPTBasePtr(cap_b);
310 }
311 break;
312
313 case cap_page_directory_cap:
314 if (cap_get_capType(cap_b) == cap_page_directory_cap) {
315 return cap_page_directory_cap_get_capPDBasePtr(cap_a) ==
316 cap_page_directory_cap_get_capPDBasePtr(cap_b);
317 }
318 break;
319
320 case cap_asid_control_cap:
321 if (cap_get_capType(cap_b) == cap_asid_control_cap) {
322 return true;
323 }
324 break;
325
326 case cap_asid_pool_cap:
327 if (cap_get_capType(cap_b) == cap_asid_pool_cap) {
328 return cap_asid_pool_cap_get_capASIDPool(cap_a) ==
329 cap_asid_pool_cap_get_capASIDPool(cap_b);
330 }
331 break;
332
333 case cap_io_port_control_cap:
334 if (cap_get_capType(cap_b) == cap_io_port_control_cap ||
335 cap_get_capType(cap_b) == cap_io_port_cap) {
336 return true;
337 }
338 break;
339
340 case cap_io_port_cap:
341 if (cap_get_capType(cap_b) == cap_io_port_cap) {
342 return cap_io_port_cap_get_capIOPortFirstPort(cap_a) ==
343 cap_io_port_cap_get_capIOPortFirstPort(cap_b) &&
344 cap_io_port_cap_get_capIOPortLastPort(cap_a) ==
345 cap_io_port_cap_get_capIOPortLastPort(cap_b);
346 }
347 break;
348
349 #ifdef CONFIG_IOMMU
350 case cap_io_space_cap:
351 if (cap_get_capType(cap_b) == cap_io_space_cap) {
352 return cap_io_space_cap_get_capPCIDevice(cap_a) ==
353 cap_io_space_cap_get_capPCIDevice(cap_b);
354 }
355 break;
356
357 case cap_io_page_table_cap:
358 if (cap_get_capType(cap_b) == cap_io_page_table_cap) {
359 return cap_io_page_table_cap_get_capIOPTBasePtr(cap_a) ==
360 cap_io_page_table_cap_get_capIOPTBasePtr(cap_b);
361 }
362 break;
363 #endif
364
365 #ifdef CONFIG_VTX
366 case cap_vcpu_cap:
367 if (cap_get_capType(cap_b) == cap_vcpu_cap) {
368 return cap_vcpu_cap_get_capVCPUPtr(cap_a) ==
369 cap_vcpu_cap_get_capVCPUPtr(cap_b);
370 }
371 break;
372
373 case cap_ept_pml4_cap:
374 if (cap_get_capType(cap_b) == cap_ept_pml4_cap) {
375 return cap_ept_pml4_cap_get_capPML4BasePtr(cap_a) ==
376 cap_ept_pml4_cap_get_capPML4BasePtr(cap_b);
377 }
378 break;
379
380 case cap_ept_pdpt_cap:
381 if (cap_get_capType(cap_b) == cap_ept_pdpt_cap) {
382 return cap_ept_pdpt_cap_get_capPDPTBasePtr(cap_a) ==
383 cap_ept_pdpt_cap_get_capPDPTBasePtr(cap_b);
384 }
385 break;
386
387 case cap_ept_pd_cap:
388 if (cap_get_capType(cap_b) == cap_ept_pd_cap) {
389 return cap_ept_pd_cap_get_capPDBasePtr(cap_a) ==
390 cap_ept_pd_cap_get_capPDBasePtr(cap_b);
391 }
392 break;
393
394 case cap_ept_pt_cap:
395 if (cap_get_capType(cap_b) == cap_ept_pt_cap) {
396 return cap_ept_pt_cap_get_capPTBasePtr(cap_a) ==
397 cap_ept_pt_cap_get_capPTBasePtr(cap_b);
398 }
399 break;
400
401 #endif
402
403 }
404
405 return Mode_sameRegionAs(cap_a, cap_b);
406 }
407
Arch_sameObjectAs(cap_t cap_a,cap_t cap_b)408 bool_t CONST Arch_sameObjectAs(cap_t cap_a, cap_t cap_b)
409 {
410 if (cap_get_capType(cap_a) == cap_io_port_control_cap &&
411 cap_get_capType(cap_b) == cap_io_port_cap) {
412 return false;
413 }
414 if (cap_get_capType(cap_a) == cap_frame_cap) {
415 if (cap_get_capType(cap_b) == cap_frame_cap) {
416 return ((cap_frame_cap_get_capFBasePtr(cap_a) ==
417 cap_frame_cap_get_capFBasePtr(cap_b)) &&
418 (cap_frame_cap_get_capFSize(cap_a) ==
419 cap_frame_cap_get_capFSize(cap_b)) &&
420 ((cap_frame_cap_get_capFIsDevice(cap_a) == 0) ==
421 (cap_frame_cap_get_capFIsDevice(cap_b) == 0)));
422 }
423 }
424 return Arch_sameRegionAs(cap_a, cap_b);
425 }
426
Arch_getObjectSize(word_t t)427 word_t Arch_getObjectSize(word_t t)
428 {
429 switch (t) {
430 case seL4_X86_4K:
431 return pageBitsForSize(X86_SmallPage);
432 case seL4_X86_LargePageObject:
433 return pageBitsForSize(X86_LargePage);
434 case seL4_X86_PageTableObject:
435 return seL4_PageTableBits;
436 case seL4_X86_PageDirectoryObject:
437 return seL4_PageDirBits;
438 case seL4_IA32_PDPTObject:
439 return seL4_PDPTBits;
440 case seL4_X86_IOPageTableObject:
441 return seL4_IOPageTableBits;
442 #ifdef CONFIG_VTX
443 case seL4_X86_VCPUObject:
444 return seL4_X86_VCPUBits;
445 case seL4_X86_EPTPML4Object:
446 return seL4_X86_EPTPML4Bits;
447 case seL4_X86_EPTPDPTObject:
448 return seL4_X86_EPTPDPTBits;
449 case seL4_X86_EPTPDObject:
450 return seL4_X86_EPTPDBits;
451 case seL4_X86_EPTPTObject:
452 return seL4_X86_EPTPTBits;
453 #endif
454 default:
455 return Mode_getObjectSize(t);
456 }
457 }
458
Arch_createObject(object_t t,void * regionBase,word_t userSize,bool_t deviceMemory)459 cap_t Arch_createObject(object_t t, void *regionBase, word_t userSize, bool_t deviceMemory)
460 {
461 #ifdef CONFIG_VTX
462 switch (t) {
463 case seL4_X86_VCPUObject: {
464 vcpu_t *vcpu;
465 vcpu = VCPU_PTR((word_t)regionBase);
466 vcpu_init(vcpu);
467 return cap_vcpu_cap_new(VCPU_REF(vcpu));
468 }
469 case seL4_X86_EPTPML4Object:
470 return cap_ept_pml4_cap_new(
471 0, /* capPML4IsMapped */
472 VPID_INVALID, /* capPML4MappedASID */
473 (word_t)regionBase /* capPML4BasePtr */
474 );
475 case seL4_X86_EPTPDPTObject:
476 return cap_ept_pdpt_cap_new(
477 0, /* capPDPTMappedAddress */
478 0, /* capPDPTIsMapped */
479 VPID_INVALID, /* capPDPTMappedASID */
480 (word_t)regionBase /* capPDPTBasePtr */
481 );
482 case seL4_X86_EPTPDObject:
483 return cap_ept_pd_cap_new(
484 0, /* capPDMappedAddress */
485 0, /* capPDIsMapped */
486 VPID_INVALID, /* capPDMappedASID */
487 (word_t)regionBase /* capPDBasePtr */
488 );
489 case seL4_X86_EPTPTObject:
490 return cap_ept_pt_cap_new(
491 0, /* capPTMappedAddress */
492 0, /* capPTIsMapped */
493 VPID_INVALID, /* capPTMappedASID */
494 (word_t)regionBase /* capPTBasePtr */
495 );
496 default:
497 #endif
498 return Mode_createObject(t, regionBase, userSize, deviceMemory);
499 #ifdef CONFIG_VTX
500 }
501 #endif
502 }
503
Arch_decodeInvocation(word_t invLabel,word_t length,cptr_t cptr,cte_t * slot,cap_t cap,bool_t call,word_t * buffer)504 exception_t Arch_decodeInvocation(
505 word_t invLabel,
506 word_t length,
507 cptr_t cptr,
508 cte_t *slot,
509 cap_t cap,
510 bool_t call,
511 word_t *buffer
512 )
513 {
514 switch (cap_get_capType(cap)) {
515 case cap_asid_control_cap:
516 case cap_asid_pool_cap:
517 return decodeX86MMUInvocation(invLabel, length, cptr, slot, cap, buffer);
518 case cap_io_port_control_cap:
519 return decodeX86PortControlInvocation(invLabel, length, cptr, slot, cap, buffer);
520 case cap_io_port_cap:
521 return decodeX86PortInvocation(invLabel, length, cptr, slot, cap, call, buffer);
522 #ifdef CONFIG_IOMMU
523 case cap_io_space_cap:
524 return decodeX86IOSpaceInvocation(invLabel, cap);
525 case cap_io_page_table_cap:
526 return decodeX86IOPTInvocation(invLabel, length, slot, cap, buffer);
527 #endif
528 #ifdef CONFIG_VTX
529 case cap_vcpu_cap:
530 return decodeX86VCPUInvocation(invLabel, length, cptr, slot, cap, buffer);
531 case cap_ept_pml4_cap:
532 case cap_ept_pdpt_cap:
533 case cap_ept_pd_cap:
534 case cap_ept_pt_cap:
535 return decodeX86EPTInvocation(invLabel, length, cptr, slot, cap, buffer);
536 #endif
537 default:
538 return Mode_decodeInvocation(invLabel, length, cptr, slot, cap, buffer);
539 }
540 }
541
Arch_prepareThreadDelete(tcb_t * thread)542 void Arch_prepareThreadDelete(tcb_t *thread)
543 {
544 /* Notify the lazy FPU module about this thread's deletion. */
545 fpuThreadDelete(thread);
546 }
547
Arch_postCapDeletion(cap_t cap)548 void Arch_postCapDeletion(cap_t cap)
549 {
550 if (cap_get_capType(cap) == cap_io_port_cap) {
551 uint16_t first_port = cap_io_port_cap_get_capIOPortFirstPort(cap);
552 uint16_t last_port = cap_io_port_cap_get_capIOPortLastPort(cap);
553
554 freeIOPortRange(first_port, last_port);
555 }
556 }
557