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 <arch/machine/fpu.h>
15#include <arch/object/objecttype.h>
16#include <arch/object/ioport.h>
17#include <arch/kernel/ept.h>
18
19#include <arch/object/iospace.h>
20#include <plat/machine/intel-vtd.h>
21
22
23bool_t Arch_isFrameType(word_t type)
24{
25    switch (type) {
26    case seL4_X86_4K:
27        return true;
28    case seL4_X86_LargePageObject:
29        return true;
30    default:
31        return false;
32    }
33}
34
35deriveCap_ret_t Mode_deriveCap(cte_t *slot, cap_t cap)
36{
37    deriveCap_ret_t ret;
38
39    switch (cap_get_capType(cap)) {
40    case cap_frame_cap:
41        cap = cap_frame_cap_set_capFMapType(cap, X86_MappingNone);
42        ret.cap = cap_frame_cap_set_capFMappedASID(cap, asidInvalid);
43        ret.status = EXCEPTION_NONE;
44        return ret;
45
46    default:
47        /* This assert has no equivalent in haskell,
48         * as the options are restricted by type */
49        fail("Invalid arch cap type");
50    }
51}
52
53finaliseCap_ret_t Mode_finaliseCap(cap_t cap, bool_t final)
54{
55    finaliseCap_ret_t fc_ret;
56
57    switch (cap_get_capType(cap)) {
58
59    case cap_frame_cap:
60        if (cap_frame_cap_get_capFMappedASID(cap)) {
61            switch (cap_frame_cap_get_capFMapType(cap)) {
62#ifdef CONFIG_VTX
63            case X86_MappingEPT:
64                unmapEPTPage(
65                    cap_frame_cap_get_capFSize(cap),
66                    cap_frame_cap_get_capFMappedASID(cap),
67                    cap_frame_cap_get_capFMappedAddress(cap),
68                    (void *)cap_frame_cap_get_capFBasePtr(cap)
69                );
70                break;
71#endif
72            case X86_MappingVSpace:
73
74#ifdef CONFIG_KERNEL_LOG_BUFFER
75                /* If the last cap to the user-level log buffer frame is being revoked,
76                 * reset the ksLog so that the kernel doesn't log anymore
77                 */
78                if (unlikely(cap_frame_cap_get_capFSize(cap) == X86_LargePage)) {
79                    if (pptr_to_paddr((void *)cap_frame_cap_get_capFBasePtr(cap)) == ksUserLogBuffer) {
80                        ksUserLogBuffer = 0;
81
82                        /* Invalidate log page table entries */
83                        clearMemory(ia32KSGlobalLogPT, BIT(seL4_PageTableBits));
84
85                        for (int idx = 0; idx < BIT(PT_INDEX_BITS); idx++) {
86                            invalidateTLBEntry(KS_LOG_PPTR + (idx << seL4_PageBits), MASK(ksNumCPUs));
87                        }
88
89                        userError("Log buffer frame is invalidated, kernel can't benchmark anymore\n");
90                    }
91                }
92#endif /* CONFIG_KERNEL_LOG_BUFFER */
93
94                unmapPage(
95                    cap_frame_cap_get_capFSize(cap),
96                    cap_frame_cap_get_capFMappedASID(cap),
97                    cap_frame_cap_get_capFMappedAddress(cap),
98                    (void *)cap_frame_cap_get_capFBasePtr(cap)
99                );
100                break;
101#ifdef CONFIG_IOMMU
102            case X86_MappingIOSpace:
103                unmapIOPage(cap);
104                break;
105#endif
106            default:
107                fail("No mapping type for mapped cap");
108                break;
109            }
110        }
111        break;
112
113    default:
114        fail("Invalid arch cap type");
115    }
116
117    fc_ret.remainder = cap_null_cap_new();
118    fc_ret.cleanupInfo = cap_null_cap_new();
119    return fc_ret;
120}
121
122bool_t CONST Mode_sameRegionAs(cap_t cap_a, cap_t cap_b)
123{
124    return false;
125}
126
127word_t Mode_getObjectSize(word_t t)
128{
129    fail("Invalid object type");
130    return 0;
131}
132
133cap_t Mode_createObject(object_t t, void *regionBase, word_t userSize, bool_t deviceMemory)
134{
135    switch (t) {
136    case seL4_X86_4K:
137        return cap_frame_cap_new(
138                   X86_SmallPage,          /* capFSize             */
139                   ASID_LOW(asidInvalid),  /* capFMappedASIDLow    */
140                   false,                  /* capFMappedAddress    */
141                   X86_MappingNone,        /* capFMapType          */
142                   deviceMemory,           /* capFIsDevice         */
143                   ASID_HIGH(asidInvalid), /* capFMappedASIDHigh   */
144                   VMReadWrite,            /* capFVMRights         */
145                   (word_t)regionBase      /* capFBasePtr          */
146               );
147
148    case seL4_X86_LargePageObject:
149        return cap_frame_cap_new(
150                   X86_LargePage,          /* capFSize             */
151                   ASID_LOW(asidInvalid),  /* capFMappedASIDLow    */
152                   false,                  /* capFMappedAddress    */
153                   X86_MappingNone,        /* capFMapType          */
154                   deviceMemory,           /* capFIsDevice         */
155                   ASID_HIGH(asidInvalid), /* capFMappedASIDHigh   */
156                   VMReadWrite,            /* capFVMRights         */
157                   (word_t)regionBase      /* capFBasePtr          */
158               );
159
160    case seL4_X86_PageTableObject:
161        return cap_page_table_cap_new(
162                   0,                  /* capPTIsMapped        */
163                   asidInvalid,        /* capPTMappedASID      */
164                   0,                  /* capPTMappedAddress   */
165                   (word_t)regionBase  /* capPTBasePtr         */
166               );
167
168    case seL4_X86_PageDirectoryObject:
169        copyGlobalMappings(regionBase);
170        return cap_page_directory_cap_new(
171                   0,                  /* capPDIsMapped      */
172                   asidInvalid,        /* capPDMappedASID    */
173                   0,                  /* capPDMappedAddress */
174                   (word_t)regionBase  /* capPDBasePtr       */
175               );
176
177#ifdef CONFIG_IOMMU
178    case seL4_X86_IOPageTableObject:
179        return cap_io_page_table_cap_new(
180                   0,  /* capIOPTIsMapped      */
181                   0,  /* capIOPTLevel         */
182                   0,  /* capIOPTMappedAddress */
183                   0,  /* capIOPTIOASID        */
184                   (word_t)regionBase  /* capIOPTBasePtr */
185               );
186#endif
187
188    default:
189        fail("Mode_createObject got an API type or invalid object type");
190    }
191}
192
193exception_t Mode_decodeInvocation(
194    word_t invLabel,
195    word_t length,
196    cptr_t cptr,
197    cte_t *slot,
198    cap_t cap,
199    extra_caps_t excaps,
200    word_t *buffer
201)
202{
203    switch (cap_get_capType(cap)) {
204    case cap_page_directory_cap:
205    case cap_page_table_cap:
206    case cap_frame_cap:
207        return decodeX86MMUInvocation(invLabel, length, cptr, slot, cap, excaps, buffer);
208    default:
209        current_syscall_error.type = seL4_InvalidCapability;
210        current_syscall_error.invalidCapNumber = 0;
211        return EXCEPTION_SYSCALL_ERROR;
212    }
213}
214