1/**
2 * \file
3 * \brief Helpful utility functions
4 */
5
6/*
7 * Copyright (c) 2009, 2010, 2011, ETH Zurich.
8 * Copyright (c) 2014, HP Labs.
9 * All rights reserved.
10 *
11 * This file is distributed under the terms in the attached LICENSE file.
12 * If you do not find this file, copies can be found by writing to:
13 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
14 */
15
16#include <barrelfish/barrelfish.h>
17
18/**
19 * \brief Translate a lvaddr_t to genvaddr_t
20 */
21genvaddr_t vspace_lvaddr_to_genvaddr(lvaddr_t lvaddr)
22{
23    struct vspace *vspace = get_current_vspace();
24    return vspace_layout_lvaddr_to_genvaddr(&vspace->layout, lvaddr);
25}
26
27/**
28 * \brief Translate a genvaddr_t to lvaddr_t
29 */
30lvaddr_t vspace_genvaddr_to_lvaddr(genvaddr_t genvaddr)
31{
32    struct vspace *vspace = get_current_vspace();
33    return vspace_layout_genvaddr_to_lvaddr(&vspace->layout, genvaddr);
34}
35
36errval_t vspace_unmap(const void *buf)
37{
38    errval_t err;
39
40    struct vregion *vregion = vspace_get_region(get_current_vspace(), buf);
41    assert(vregion);
42
43    err = vregion_destroy(vregion);
44    if (err_is_fail(err)) {
45        return err_push(err, LIB_ERR_VREGION_DESTROY);
46    }
47
48    return SYS_ERR_OK;
49}
50
51/// Map with an alignment constraint
52errval_t vspace_map_anon_nomalloc(void **retaddr, struct memobj_anon *memobj,
53                                  struct vregion *vregion, size_t size,
54                                  size_t *retsize, vregion_flags_t flags,
55                                  size_t alignment)
56{
57    errval_t err1, err2;
58    size = ROUND_UP(size, BASE_PAGE_SIZE);
59    if (retsize) {
60        *retsize = size;
61    }
62
63    // Create a memobj and vregion
64    err1 = memobj_create_anon(memobj, size, 0);
65    if (err_is_fail(err1)) {
66        err1 = err_push(err1, LIB_ERR_MEMOBJ_CREATE_ANON);
67        goto error;
68    }
69    err1 = vregion_map_aligned(vregion, get_current_vspace(),
70                               (struct memobj *)memobj, 0, size,
71                               flags, alignment);
72    if (err_is_fail(err1)) {
73        err1 = err_push(err1, LIB_ERR_VREGION_MAP);
74        goto error;
75    }
76
77    *retaddr = (void*)vspace_genvaddr_to_lvaddr(vregion_get_base_addr(vregion));
78
79    return SYS_ERR_OK;
80
81 error:
82    if (err_no(err1) !=  LIB_ERR_MEMOBJ_CREATE_ANON) {
83        err2 = memobj_destroy_anon((struct memobj *)memobj, true);
84        if (err_is_fail(err2)) {
85            DEBUG_ERR(err2, "memobj_destroy_anon failed");
86        }
87    }
88    return err1;
89}
90
91/**
92 * \brief Wrapper for creating and mapping a memory object of type anonymous.
93 *
94 * The memory object and vregion are returned so the user can call fill and
95 * pagefault on it to create actual mappings.
96 */
97errval_t vspace_map_anon_aligned(void **retaddr, struct memobj **ret_memobj,
98                                 struct vregion **ret_vregion, size_t size,
99                                 size_t *retsize, vregion_flags_t flags,
100                                 size_t alignment)
101{
102    errval_t err;
103    struct memobj_anon *memobj = NULL;
104    struct vregion *vregion = NULL;
105
106    // Allocate space
107    memobj = malloc(sizeof(struct memobj_anon));
108    assert(memobj != NULL);
109
110    vregion = malloc(sizeof(struct vregion));
111    assert(vregion != NULL);
112
113    err = vspace_map_anon_nomalloc(retaddr, memobj, vregion, size,
114                                   retsize, flags, alignment);
115    if (err_is_fail(err)) {
116        free(memobj);
117        free(vregion);
118    } else {
119        *ret_memobj = (struct memobj *)memobj;
120        *ret_vregion = vregion;
121    }
122
123    return err;
124}
125
126/**
127 * \brief Wrapper for creating and mapping a memory object of type anonymous.
128 *
129 * The memory object and vregion are returned so the user can call fill and
130 * pagefault on it to create actual mappings.
131 */
132errval_t vspace_map_anon_attr(void **retaddr, struct memobj **ret_memobj,
133                              struct vregion **ret_vregion, size_t size,
134                              size_t *retsize, vregion_flags_t flags)
135{
136    errval_t err;
137
138    struct memobj_anon *memobj = NULL;
139    struct vregion *vregion = NULL;
140
141    // Allocate space
142    memobj = malloc(sizeof(struct memobj_anon));
143    assert(memobj != NULL);
144
145    vregion = malloc(sizeof(struct vregion));
146    assert(vregion != NULL);
147
148    err = vspace_map_anon_nomalloc(retaddr, memobj, vregion, size,
149                                   retsize, flags, 0);
150    if (err_is_fail(err)) {
151      free(memobj);
152      free(vregion);
153    } else {
154        *ret_memobj = (struct memobj *)memobj;
155        *ret_vregion = vregion;
156    }
157
158    return err;
159}
160
161/**
162 * \brief Wrapper to create and map an anonymous memory object at a fixed address.
163 *
164 * The memory object and vregion are returned so the user can call fill and
165 * pagefault on it to create actual mappings.
166 */
167errval_t vspace_map_anon_fixed(genvaddr_t base, size_t size,
168                               vregion_flags_t flags,
169                               struct vregion **ret_vregion,
170                               struct memobj **ret_memobj)
171{
172    errval_t err1, err2;
173    struct memobj *memobj = NULL;
174    struct vregion *vregion = NULL;
175
176    // Allocate space
177    memobj = malloc(sizeof(struct memobj_anon));
178    if (!memobj) {
179        err1 = LIB_ERR_MALLOC_FAIL;
180        goto error;
181    }
182    vregion = malloc(sizeof(struct vregion));
183    if (!vregion) {
184        err1 = LIB_ERR_MALLOC_FAIL;
185        goto error;
186    }
187
188    // Create a memobj and vregion
189    err1 = memobj_create_anon((struct memobj_anon*)memobj, size, 0);
190    if (err_is_fail(err1)) {
191        err1 = err_push(err1, LIB_ERR_MEMOBJ_CREATE_ANON);
192        goto error;
193    }
194    err1 = vregion_map_fixed(vregion, get_current_vspace(), memobj, 0, size,
195                             base, flags);
196    if (err_is_fail(err1)) {
197        err1 = err_push(err1, LIB_ERR_VREGION_MAP);
198        goto error;
199    }
200
201    *ret_vregion = vregion;
202    *ret_memobj = memobj;
203
204    return SYS_ERR_OK;
205
206error:
207    if (memobj) {
208        err2 = memobj_destroy_anon(memobj, true);
209        if (err_is_fail(err2)) {
210            DEBUG_ERR(err2, "memobj_destroy_anon failed");
211        }
212        free(memobj);
213    }
214    if (vregion) {
215        err2 = vregion_destroy(vregion);
216        if (err_is_fail(err2)) {
217            DEBUG_ERR(err2, "vregion_destroy failed");
218        }
219        free(vregion);
220    }
221    return err1;
222}
223
224/**
225 * \brief Wrapper for creating and mapping a memory object of type one frame
226 */
227errval_t vspace_map_one_frame(void **retaddr, size_t size, struct capref frame,
228                              struct memobj **retmemobj,
229                              struct vregion **retvregion)
230{
231    return vspace_map_one_frame_attr(retaddr, size, frame,
232                                     VREGION_FLAGS_READ_WRITE, retmemobj,
233                                     retvregion);
234}
235
236errval_t vspace_map_one_frame_fixed(lvaddr_t addr, size_t size,
237                                    struct capref frame,
238                                    struct memobj **retmemobj,
239                                    struct vregion **retvregion)
240{
241    return vspace_map_one_frame_fixed_attr(addr, size, frame,
242                                           VREGION_FLAGS_READ_WRITE, retmemobj,
243                                           retvregion);
244}
245
246errval_t vspace_map_one_frame_fixed_attr(lvaddr_t addr, size_t size,
247                                    struct capref frame, vregion_flags_t flags,
248                                    struct memobj **retmemobj,
249                                    struct vregion **retvregion)
250{
251    errval_t err1, err2;
252    struct memobj *memobj   = NULL;
253    struct vregion *vregion = NULL;
254
255    size = ROUND_UP(size, BASE_PAGE_SIZE);
256
257    // Allocate space
258    memobj = malloc(sizeof(struct memobj_one_frame));
259    if (!memobj) {
260        err1 = LIB_ERR_MALLOC_FAIL;
261        goto error;
262    }
263    vregion = malloc(sizeof(struct vregion));
264    if (!vregion) {
265        err1 = LIB_ERR_MALLOC_FAIL;
266        goto error;
267    }
268
269    // Create mappings
270    err1 = memobj_create_one_frame((struct memobj_one_frame*)memobj, size, 0);
271    if (err_is_fail(err1)) {
272        err1 = err_push(err1, LIB_ERR_MEMOBJ_CREATE_ONE_FRAME);
273        goto error;
274    }
275
276    err1 = memobj->f.fill(memobj, 0, frame, size);
277    if (err_is_fail(err1)) {
278        err1 = err_push(err1, LIB_ERR_MEMOBJ_FILL);
279        goto error;
280    }
281
282    err1 = vregion_map_fixed(vregion, get_current_vspace(), memobj, 0, size, addr, flags);
283    if (err_is_fail(err1)) {
284        err1 = err_push(err1, LIB_ERR_VREGION_MAP);
285        goto error;
286    }
287
288    err1 = memobj->f.pagefault(memobj, vregion, 0, 0);
289    if (err_is_fail(err1)) {
290        err1 = err_push(err1, LIB_ERR_MEMOBJ_PAGEFAULT_HANDLER);
291        goto error;
292    }
293
294    if (retmemobj) {
295        *retmemobj = memobj;
296    }
297    if (retvregion) {
298        *retvregion = vregion;
299    }
300    return SYS_ERR_OK;
301
302 error:
303    if (memobj) {
304        err2 = memobj_destroy_one_frame(memobj);
305        if (err_is_fail(err2)) {
306            DEBUG_ERR(err2, "memobj_destroy_anon failed");
307        }
308    }
309    if (vregion) {
310        err2 = vregion_destroy(vregion);
311        if (err_is_fail(err2)) {
312            DEBUG_ERR(err2, "vregion_destroy failed");
313        }
314    }
315    return err1;
316}
317
318/**
319 * \brief Wrapper for creating and mapping a memory object
320 * of type one frame with specific flags
321 */
322errval_t vspace_map_one_frame_attr(void **retaddr, size_t size,
323                                   struct capref frame, vregion_flags_t flags,
324                                   struct memobj **retmemobj,
325                                   struct vregion **retvregion)
326{
327    return vspace_map_one_frame_attr_aligned(retaddr, size,
328            frame, flags, 0, retmemobj, retvregion);
329}
330
331/**
332 * \brief Wrapper for creating and mapping a memory object
333 * of type one frame with specific flags and a specific alignment
334 */
335errval_t vspace_map_one_frame_attr_aligned(void **retaddr, size_t size,
336                                   struct capref frame, vregion_flags_t flags,
337                                   size_t alignment,
338                                   struct memobj **retmemobj,
339                                   struct vregion **retvregion)
340{
341    errval_t err1, err2;
342    struct memobj *memobj   = NULL;
343    struct vregion *vregion = NULL;
344
345    size = ROUND_UP(size, BASE_PAGE_SIZE);
346
347    // Allocate space
348    memobj = calloc(1, sizeof(struct memobj_one_frame));
349    if (!memobj) {
350        err1 = LIB_ERR_MALLOC_FAIL;
351        goto error;
352    }
353    vregion = calloc(1, sizeof(struct vregion));
354    if (!vregion) {
355        err1 = LIB_ERR_MALLOC_FAIL;
356        goto error;
357    }
358
359    // Create mappings
360    err1 = memobj_create_one_frame((struct memobj_one_frame*)memobj, size, 0);
361    if (err_is_fail(err1)) {
362        err1 = err_push(err1, LIB_ERR_MEMOBJ_CREATE_ONE_FRAME);
363        goto error;
364    }
365
366    err1 = memobj->f.fill(memobj, 0, frame, size);
367    if (err_is_fail(err1)) {
368        err1 = err_push(err1, LIB_ERR_MEMOBJ_FILL);
369        goto error;
370    }
371
372    err1 = vregion_map_aligned(vregion, get_current_vspace(), memobj, 0, size,
373            flags, alignment);
374    if (err_is_fail(err1)) {
375        err1 = err_push(err1, LIB_ERR_VREGION_MAP);
376        goto error;
377    }
378
379    err1 = memobj->f.pagefault(memobj, vregion, 0, 0);
380    if (err_is_fail(err1)) {
381        err1 = err_push(err1, LIB_ERR_MEMOBJ_PAGEFAULT_HANDLER);
382        goto error;
383    }
384
385    *retaddr = (void*)vspace_genvaddr_to_lvaddr(vregion_get_base_addr(vregion));
386    if (retmemobj) {
387        *retmemobj = memobj;
388    }
389    if (retvregion) {
390        *retvregion = vregion;
391    }
392    return SYS_ERR_OK;
393
394 error:
395    if (memobj) {
396        err2 = memobj_destroy_one_frame(memobj);
397        if (err_is_fail(err2)) {
398            DEBUG_ERR(err2, "memobj_destroy_anon failed");
399        }
400    }
401    if (vregion) {
402        err2 = vregion_destroy(vregion);
403        if (err_is_fail(err2)) {
404            DEBUG_ERR(err2, "vregion_destroy failed");
405        }
406    }
407    return err1;
408}
409
410errval_t vspace_map_one_frame_one_map(struct memobj_one_frame_one_map *memobj,
411                                      struct vregion *vregion, size_t size,
412                                      struct capref frame)
413{
414    errval_t err;
415
416    err = memobj_create_one_frame_one_map(memobj, size, 0);
417    if (err_is_fail(err)) {
418        return err_push(err, LIB_ERR_MEMOBJ_CREATE_ONE_FRAME_ONE_MAP);
419    }
420    err = memobj->m.f.fill(&memobj->m, 0, frame, size);
421    if (err_is_fail(err)) {
422        return err_push(err, LIB_ERR_MEMOBJ_FILL);
423    }
424    err = vregion_map(vregion, get_current_vspace(), &memobj->m, 0, size,
425                      VREGION_FLAGS_READ_WRITE);
426    if (err_is_fail(err)) {
427        return err_push(err, LIB_ERR_VREGION_MAP);
428    }
429    err = memobj->m.f.pagefault(&memobj->m, vregion, 0, 0);
430    if (err_is_fail(err)) {
431        return err_push(err, LIB_ERR_MEMOBJ_PAGEFAULT_HANDLER);
432    }
433
434    return SYS_ERR_OK;
435}
436