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