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