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, Universitaetstrasse 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
91errval_t vspace_map_append_nomalloc(void **retaddr, struct memobj_append *memobj,
92                                    struct vregion *vregion, size_t size,
93                                    size_t *retsize, vregion_flags_t flags,
94                                    size_t alignment)
95{
96    errval_t err1, err2;
97    size = ROUND_UP(size, BASE_PAGE_SIZE);
98    if (retsize) {
99        *retsize = size;
100    }
101
102    // Create a memobj and vregion
103    err1 = memobj_create_append(memobj, size, 0);
104    if (err_is_fail(err1)) {
105        err1 = err_push(err1, LIB_ERR_MEMOBJ_CREATE_ANON);
106        goto error;
107    }
108    err1 = vregion_map_aligned(vregion, get_current_vspace(),
109                               (struct memobj *)memobj, 0, size,
110                               flags, alignment);
111    if (err_is_fail(err1)) {
112        err1 = err_push(err1, LIB_ERR_VREGION_MAP);
113        goto error;
114    }
115
116    *retaddr = (void*)vspace_genvaddr_to_lvaddr(vregion_get_base_addr(vregion));
117
118    return SYS_ERR_OK;
119
120 error:
121    if (err_no(err1) !=  LIB_ERR_MEMOBJ_CREATE_ANON) {
122        err2 = memobj_destroy_append((struct memobj *)memobj);
123        if (err_is_fail(err2)) {
124            DEBUG_ERR(err2, "memobj_destroy_anon failed");
125        }
126    }
127    return err1;
128}
129
130/**
131 * \brief Wrapper for creating and mapping a memory object of type anonymous.
132 *
133 * The memory object and vregion are returned so the user can call fill and
134 * pagefault on it to create actual mappings.
135 */
136errval_t vspace_map_anon_aligned(void **retaddr, struct memobj **ret_memobj,
137                                 struct vregion **ret_vregion, size_t size,
138                                 size_t *retsize, vregion_flags_t flags,
139                                 size_t alignment)
140{
141    errval_t err;
142    struct memobj_anon *memobj = NULL;
143    struct vregion *vregion = NULL;
144
145    // Allocate space
146    memobj = malloc(sizeof(struct memobj_anon));
147    assert(memobj != NULL);
148
149    vregion = malloc(sizeof(struct vregion));
150    assert(vregion != NULL);
151
152    err = vspace_map_anon_nomalloc(retaddr, memobj, vregion, size,
153                                   retsize, flags, alignment);
154    if (err_is_fail(err)) {
155        free(memobj);
156        free(vregion);
157    } else {
158        *ret_memobj = (struct memobj *)memobj;
159        *ret_vregion = vregion;
160    }
161
162    return err;
163}
164
165/**
166 * \brief Wrapper for creating and mapping a memory object of type anonymous.
167 *
168 * The memory object and vregion are returned so the user can call fill and
169 * pagefault on it to create actual mappings.
170 */
171errval_t vspace_map_anon_attr(void **retaddr, struct memobj **ret_memobj,
172                              struct vregion **ret_vregion, size_t size,
173                              size_t *retsize, vregion_flags_t flags)
174{
175    errval_t err;
176
177    struct memobj_anon *memobj = NULL;
178    struct vregion *vregion = NULL;
179
180    // Allocate space
181    memobj = malloc(sizeof(struct memobj_anon));
182    assert(memobj != NULL);
183
184    vregion = malloc(sizeof(struct vregion));
185    assert(vregion != NULL);
186
187    err = vspace_map_anon_nomalloc(retaddr, memobj, vregion, size,
188                                   retsize, flags, 0);
189    if (err_is_fail(err)) {
190      free(memobj);
191      free(vregion);
192    } else {
193        *ret_memobj = (struct memobj *)memobj;
194        *ret_vregion = vregion;
195    }
196
197    return err;
198}
199
200/**
201 * \brief Wrapper to create and map an anonymous memory object at a fixed address.
202 *
203 * The memory object and vregion are returned so the user can call fill and
204 * pagefault on it to create actual mappings.
205 */
206errval_t vspace_map_anon_fixed(genvaddr_t base, size_t size,
207                               vregion_flags_t flags,
208                               struct vregion **ret_vregion,
209                               struct memobj **ret_memobj)
210{
211    errval_t err1, err2;
212    struct memobj *memobj = NULL;
213    struct vregion *vregion = NULL;
214
215    // Allocate space
216    memobj = malloc(sizeof(struct memobj_anon));
217    if (!memobj) {
218        err1 = LIB_ERR_MALLOC_FAIL;
219        goto error;
220    }
221    vregion = malloc(sizeof(struct vregion));
222    if (!vregion) {
223        err1 = LIB_ERR_MALLOC_FAIL;
224        goto error;
225    }
226
227    // Create a memobj and vregion
228    err1 = memobj_create_anon((struct memobj_anon*)memobj, size, 0);
229    if (err_is_fail(err1)) {
230        err1 = err_push(err1, LIB_ERR_MEMOBJ_CREATE_ANON);
231        goto error;
232    }
233    err1 = vregion_map_fixed(vregion, get_current_vspace(), memobj, 0, size,
234                             base, flags);
235    if (err_is_fail(err1)) {
236        err1 = err_push(err1, LIB_ERR_VREGION_MAP);
237        goto error;
238    }
239
240    *ret_vregion = vregion;
241    *ret_memobj = memobj;
242
243    return SYS_ERR_OK;
244
245error:
246    if (memobj) {
247        err2 = memobj_destroy_anon(memobj, true);
248        if (err_is_fail(err2)) {
249            DEBUG_ERR(err2, "memobj_destroy_anon failed");
250        }
251        free(memobj);
252    }
253    if (vregion) {
254        err2 = vregion_destroy(vregion);
255        if (err_is_fail(err2)) {
256            DEBUG_ERR(err2, "vregion_destroy failed");
257        }
258        free(vregion);
259    }
260    return err1;
261}
262
263/**
264 * \brief Wrapper for creating and mapping a memory object of type one frame
265 */
266errval_t vspace_map_one_frame(void **retaddr, size_t size, struct capref frame,
267                              struct memobj **retmemobj,
268                              struct vregion **retvregion)
269{
270    return vspace_map_one_frame_attr(retaddr, size, frame,
271                                     VREGION_FLAGS_READ_WRITE, retmemobj,
272                                     retvregion);
273}
274
275errval_t vspace_map_one_frame_fixed(lvaddr_t addr, size_t size,
276                                    struct capref frame,
277                                    struct memobj **retmemobj,
278                                    struct vregion **retvregion)
279{
280    return vspace_map_one_frame_fixed_attr(addr, size, frame,
281                                           VREGION_FLAGS_READ_WRITE, retmemobj,
282                                           retvregion);
283}
284
285errval_t vspace_map_one_frame_fixed_attr(lvaddr_t addr, size_t size,
286                                    struct capref frame, vregion_flags_t flags,
287                                    struct memobj **retmemobj,
288                                    struct vregion **retvregion)
289{
290    errval_t err1, err2;
291    struct memobj *memobj   = NULL;
292    struct vregion *vregion = NULL;
293
294    size = ROUND_UP(size, BASE_PAGE_SIZE);
295
296    // Allocate space
297    memobj = malloc(sizeof(struct memobj_one_frame));
298    if (!memobj) {
299        err1 = LIB_ERR_MALLOC_FAIL;
300        goto error;
301    }
302    vregion = malloc(sizeof(struct vregion));
303    if (!vregion) {
304        err1 = LIB_ERR_MALLOC_FAIL;
305        goto error;
306    }
307
308    // Create mappings
309    err1 = memobj_create_one_frame((struct memobj_one_frame*)memobj, size, 0);
310    if (err_is_fail(err1)) {
311        err1 = err_push(err1, LIB_ERR_MEMOBJ_CREATE_ONE_FRAME);
312        goto error;
313    }
314
315    err1 = memobj->f.fill(memobj, 0, frame, size);
316    if (err_is_fail(err1)) {
317        err1 = err_push(err1, LIB_ERR_MEMOBJ_FILL);
318        goto error;
319    }
320
321    err1 = vregion_map_fixed(vregion, get_current_vspace(), memobj, 0, size, addr, flags);
322    if (err_is_fail(err1)) {
323        err1 = err_push(err1, LIB_ERR_VREGION_MAP);
324        goto error;
325    }
326
327    err1 = memobj->f.pagefault(memobj, vregion, 0, 0);
328    if (err_is_fail(err1)) {
329        err1 = err_push(err1, LIB_ERR_MEMOBJ_PAGEFAULT_HANDLER);
330        goto error;
331    }
332
333    if (retmemobj) {
334        *retmemobj = memobj;
335    }
336    if (retvregion) {
337        *retvregion = vregion;
338    }
339    return SYS_ERR_OK;
340
341 error:
342    if (memobj) {
343        err2 = memobj_destroy_one_frame(memobj);
344        if (err_is_fail(err2)) {
345            DEBUG_ERR(err2, "memobj_destroy_anon failed");
346        }
347    }
348    if (vregion) {
349        err2 = vregion_destroy(vregion);
350        if (err_is_fail(err2)) {
351            DEBUG_ERR(err2, "vregion_destroy failed");
352        }
353    }
354    return err1;
355}
356
357/**
358 * \brief Wrapper for creating and mapping a memory object
359 * of type one frame with specific flags
360 */
361errval_t vspace_map_one_frame_attr(void **retaddr, size_t size,
362                                   struct capref frame, vregion_flags_t flags,
363                                   struct memobj **retmemobj,
364                                   struct vregion **retvregion)
365{
366    return vspace_map_one_frame_attr_aligned(retaddr, size,
367            frame, flags, 0, retmemobj, retvregion);
368}
369
370/**
371 * \brief Wrapper for creating and mapping a memory object
372 * of type one frame with specific flags and a specific alignment
373 */
374errval_t vspace_map_one_frame_attr_aligned(void **retaddr, size_t size,
375                                   struct capref frame, vregion_flags_t flags,
376                                   size_t alignment,
377                                   struct memobj **retmemobj,
378                                   struct vregion **retvregion)
379{
380    errval_t err1, err2;
381    struct memobj *memobj   = NULL;
382    struct vregion *vregion = NULL;
383
384    size = ROUND_UP(size, BASE_PAGE_SIZE);
385
386    // Allocate space
387    memobj = calloc(1, sizeof(struct memobj_one_frame));
388    if (!memobj) {
389        err1 = LIB_ERR_MALLOC_FAIL;
390        goto error;
391    }
392    vregion = calloc(1, sizeof(struct vregion));
393    if (!vregion) {
394        err1 = LIB_ERR_MALLOC_FAIL;
395        goto error;
396    }
397
398    // Create mappings
399    err1 = memobj_create_one_frame((struct memobj_one_frame*)memobj, size, 0);
400    if (err_is_fail(err1)) {
401        err1 = err_push(err1, LIB_ERR_MEMOBJ_CREATE_ONE_FRAME);
402        goto error;
403    }
404
405    err1 = memobj->f.fill(memobj, 0, frame, size);
406    if (err_is_fail(err1)) {
407        err1 = err_push(err1, LIB_ERR_MEMOBJ_FILL);
408        goto error;
409    }
410
411    err1 = vregion_map_aligned(vregion, get_current_vspace(), memobj, 0, size,
412            flags, alignment);
413    if (err_is_fail(err1)) {
414        err1 = err_push(err1, LIB_ERR_VREGION_MAP);
415        goto error;
416    }
417
418    err1 = memobj->f.pagefault(memobj, vregion, 0, 0);
419    if (err_is_fail(err1)) {
420        err1 = err_push(err1, LIB_ERR_MEMOBJ_PAGEFAULT_HANDLER);
421        goto error;
422    }
423
424    *retaddr = (void*)vspace_genvaddr_to_lvaddr(vregion_get_base_addr(vregion));
425    if (retmemobj) {
426        *retmemobj = memobj;
427    }
428    if (retvregion) {
429        *retvregion = vregion;
430    }
431    return SYS_ERR_OK;
432
433 error:
434    if (memobj) {
435        err2 = memobj_destroy_one_frame(memobj);
436        if (err_is_fail(err2)) {
437            DEBUG_ERR(err2, "memobj_destroy_anon failed");
438        }
439    }
440    if (vregion) {
441        err2 = vregion_destroy(vregion);
442        if (err_is_fail(err2)) {
443            DEBUG_ERR(err2, "vregion_destroy failed");
444        }
445    }
446    return err1;
447}
448
449errval_t vspace_map_one_frame_one_map(struct memobj_one_frame_one_map *memobj,
450                                      struct vregion *vregion, size_t size,
451                                      struct capref frame)
452{
453    errval_t err;
454
455    err = memobj_create_one_frame_one_map(memobj, size, 0);
456    if (err_is_fail(err)) {
457        return err_push(err, LIB_ERR_MEMOBJ_CREATE_ONE_FRAME_ONE_MAP);
458    }
459    err = memobj->m.f.fill(&memobj->m, 0, frame, size);
460    if (err_is_fail(err)) {
461        return err_push(err, LIB_ERR_MEMOBJ_FILL);
462    }
463    err = vregion_map(vregion, get_current_vspace(), &memobj->m, 0, size,
464                      VREGION_FLAGS_READ_WRITE);
465    if (err_is_fail(err)) {
466        return err_push(err, LIB_ERR_VREGION_MAP);
467    }
468    err = memobj->m.f.pagefault(&memobj->m, vregion, 0, 0);
469    if (err_is_fail(err)) {
470        return err_push(err, LIB_ERR_MEMOBJ_PAGEFAULT_HANDLER);
471    }
472
473    return SYS_ERR_OK;
474}
475