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