1/*
2 * Copyright 2016, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(D61_BSD)
11 */
12
13#include <autoconf.h>
14#include <stdio.h>
15#include <stdint.h>
16#include <stdarg.h>
17#include <assert.h>
18#include <sys/mman.h>
19#include <utils/arith.h>
20
21#include <refos/vmlayout.h>
22#include <refos-io/internal_state.h>
23#include <refos-io/ipc_state.h>
24#include <refos-util/dprintf.h>
25#include <refos-util/init.h>
26
27#define _ENOMEM 12
28
29/*! How many pages of memory to expand the heap every increment.
30    Too small and this leads to many many expensive resizing operations, too large and we allocate
31    all this uneccessary memory and never use it.
32*/
33#define REFOSIO_HEAP_EXPAND_INCREMENT_NPAGES 2
34
35int refosio_morecore_expand(sl_dataspace_t *region, size_t sizeAdd);
36
37long
38sys_brk(va_list ap)
39{
40    uintptr_t newbrk = va_arg(ap, uintptr_t);
41
42    /* Static more-core override mode. */
43    if (refosIOState.staticMoreCoreOverride != NULL) {
44        uintptr_t ret = (uintptr_t) 0;
45        if (!newbrk) {
46            /* If the newbrk is 0, we return the bottom of the static heap */
47    		ret = refosIOState.staticMoreCoreOverrideBase;
48        } else if (newbrk < refosIOState.staticMoreCoreOverrideTop &&
49                newbrk > (uintptr_t)&refosIOState.staticMoreCoreOverride[0]) {
50    		ret = refosIOState.staticMoreCoreOverrideBase = newbrk;
51        } else {
52            seL4_DebugPrintf("ERROR: refos static sbrk out of memory.\n");
53            assert(!"ERROR: refos static sbrk out of memory.");
54    		ret = -_ENOMEM;
55        }
56
57        return ret;
58    }
59
60    /* Dynamic more-core sbrk mode. */
61    if (!refosIOState.dynamicHeap) {
62        seL4_DebugPrintf("Morecore not available. Please call refosio_setup_morecore_override.\n");
63        assert(!"Morecore not available. Please call refosio_setup_morecore_override.");
64        return -_ENOMEM;
65    }
66    assert(refosIOState.procInfo);
67    assert(refosIOState.procInfo->magic == SELFLOADER_PROCINFO_MAGIC);
68
69    if (!newbrk) {
70        /* Assign to bottom of dynamic heap address. */
71        assert(refosIOState.procInfo->heapRegion.vaddr);
72        return refosIOState.procInfo->heapRegion.vaddr;
73    } else if (newbrk < refosIOState.procInfo->heapRegion.vaddr) {
74        /* Invalid brk location. */
75        return -ENOMEM;
76    } else if (newbrk < refosIOState.procInfo->heapRegion.vaddr +
77            refosIOState.procInfo->heapRegion.size) {
78        /* Our current heap region is large enough. */
79        return newbrk;
80    }
81
82    /* Our current heap region is too small expand the window and dataspace. */
83    /* First work out the increase in size. */
84    uint32_t increaseSize = (newbrk + 1) -
85            (refosIOState.procInfo->heapRegion.vaddr + refosIOState.procInfo->heapRegion.size);
86    assert(increaseSize > 0);
87    uint32_t increaseSizePages = refos_round_up_npages(increaseSize);
88    increaseSizePages = MAX(increaseSizePages, REFOSIO_HEAP_EXPAND_INCREMENT_NPAGES);
89
90    /* Then expand the region and dataspace. */
91    refosio_internal_save_IPC_buffer();
92    int error = refosio_morecore_expand(&refosIOState.procInfo->heapRegion,
93            increaseSizePages * REFOS_PAGE_SIZE);
94    if (error != ESUCCESS) {
95        seL4_DebugPrintf("ERROR: refos dynamic sbrk out of memory.\n");
96        assert(!"ERROR: refos dynamic sbrk out of memory.");
97        return -_ENOMEM;
98    }
99    refosio_internal_restore_IPC_buffer();
100
101    /* New size should now be lower. */
102    if (newbrk < refosIOState.procInfo->heapRegion.vaddr + refosIOState.procInfo->heapRegion.size) {
103        return newbrk;
104    }
105
106    seL4_DebugPrintf("ERROR: corruption detected, this should never happen.\n");
107    assert(!"ERROR: corruption detected, this should never happen.");
108    return -_ENOMEM;
109}
110
111long
112sys_mmap2(va_list ap)
113{
114    char *addr =  va_arg(ap, char*);
115    unsigned int length = va_arg(ap, unsigned int);
116    int prot = va_arg(ap, int);
117    int flags = va_arg(ap, int);
118    int fd = va_arg(ap, int);
119    off_t offset = va_arg(ap, int);
120
121    (void) prot;
122    (void) offset;
123    (void) fd;
124    (void) addr;
125
126    /* Static more-core override mode. */
127    if (refosIOState.staticMoreCoreOverride != NULL) {
128        if (flags & MAP_ANONYMOUS) {
129            /* Steal from the top of the static region. */
130            uintptr_t base = refosIOState.staticMoreCoreOverrideTop - length;
131            if (base < refosIOState.staticMoreCoreOverrideBase) {
132                assert(!"ERROR: refos static mmap out of memory.");
133                return -_ENOMEM;
134            }
135            refosIOState.staticMoreCoreOverrideTop = base;
136            return base;
137        }
138        assert(!"File mapping not implemented.");
139        return -_ENOMEM;
140    }
141
142    if (!refosIOState.dynamicMMap) {
143        seL4_DebugPrintf("MMap not available. Please call refosio_setup_morecore_override.\n");
144        assert(!"MMap not available. Please call refosio_setup_morecore_override.");
145        return -_ENOMEM;
146    }
147
148    /* Dynamic more-core mmap mode. */
149    if (flags & MAP_ANONYMOUS) {
150        uint32_t vaddr = 0;
151        uint32_t sizeNPages = refos_round_up_npages(length);
152
153        /* Allocate pages and map window. */
154        refosio_internal_save_IPC_buffer();
155        int error = refosio_mmap_anon(&refosIOState.mmapState, sizeNPages, &vaddr);
156        if (error != ESUCCESS || !vaddr) {
157            seL4_DebugPrintf("refosio_mmap_anon mapping failed.\n");
158            return -_ENOMEM;
159        }
160        refosio_internal_restore_IPC_buffer();
161
162        return vaddr;
163    }
164
165    seL4_DebugPrintf("File mapping not implemented.\n");
166    assert(!"File mapping not implemented.");
167    return -_ENOMEM;
168}
169
170long
171sys_munmap(va_list ap)
172{
173    char *addr =  va_arg(ap, char*);
174    unsigned int length = va_arg(ap, unsigned int);
175
176    if (!length) {
177        return 0;
178    }
179
180    /* Static more-core override mode. */
181    if (refosIOState.staticMoreCoreOverride != NULL) {
182        /* Do nothing here. Don't unmap static morecore. */
183        return 0;
184    }
185
186    if (!refosIOState.dynamicMMap) {
187        /* No mmap. How can we possibly have munmap? This is madness. */
188        return -1;
189    }
190
191    if ((uint32_t)addr >= PROCESS_MMAP_BOT && (uint32_t)addr < PROCESS_MMAP_TOP) {
192        uint32_t sizeNPages = refos_round_up_npages(length);
193        int error = refosio_munmap_anon(&refosIOState.mmapState, (uint32_t) addr, sizeNPages);
194        if (error  != ESUCCESS) {
195            seL4_DebugPrintf("refosio_munmap_anon mapping failed. Ignoring unmap.\n");
196            return -1;
197        }
198        return 0;
199    }
200
201    return 0;
202}
203