libbarrelfish: make cap deletion in memobj_destroy_anon() optional
[barrelfish] / lib / barrelfish / vspace / utils.c
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  */
21 genvaddr_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  */
30 lvaddr_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
36 errval_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
52 errval_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  */
97 errval_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     }
119
120     *ret_memobj = (struct memobj *)memobj;
121     *ret_vregion = vregion;
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  */
132 errval_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     {
152       free(memobj);
153       free(vregion);
154     }
155
156     *ret_memobj = (struct memobj *)memobj;
157     *ret_vregion = vregion;
158
159     return err;
160 }
161
162 /**
163  * \brief Wrapper to create and map an anonymous memory object at a fixed address.
164  *
165  * The memory object and vregion are returned so the user can call fill and
166  * pagefault on it to create actual mappings.
167  */
168 errval_t vspace_map_anon_fixed(genvaddr_t base, size_t size,
169                                vregion_flags_t flags,
170                                struct vregion **ret_vregion,
171                                struct memobj **ret_memobj)
172 {
173     errval_t err1, err2;
174     struct memobj *memobj = NULL;
175     struct vregion *vregion = NULL;
176
177     // Allocate space
178     memobj = malloc(sizeof(struct memobj_anon));
179     if (!memobj) {
180         err1 = LIB_ERR_MALLOC_FAIL;
181         goto error;
182     }
183     vregion = malloc(sizeof(struct vregion));
184     if (!vregion) {
185         err1 = LIB_ERR_MALLOC_FAIL;
186         goto error;
187     }
188
189     // Create a memobj and vregion
190     err1 = memobj_create_anon((struct memobj_anon*)memobj, size, 0);
191     if (err_is_fail(err1)) {
192         err1 = err_push(err1, LIB_ERR_MEMOBJ_CREATE_ANON);
193         goto error;
194     }
195     err1 = vregion_map_fixed(vregion, get_current_vspace(), memobj, 0, size,
196                              base, flags);
197     if (err_is_fail(err1)) {
198         err1 = err_push(err1, LIB_ERR_VREGION_MAP);
199         goto error;
200     }
201
202     *ret_vregion = vregion;
203     *ret_memobj = memobj;
204
205     return SYS_ERR_OK;
206
207 error:
208     if (memobj) {
209         err2 = memobj_destroy_anon(memobj, true);
210         if (err_is_fail(err2)) {
211             DEBUG_ERR(err2, "memobj_destroy_anon failed");
212         }
213         free(memobj);
214     }
215     if (vregion) {
216         err2 = vregion_destroy(vregion);
217         if (err_is_fail(err2)) {
218             DEBUG_ERR(err2, "vregion_destroy failed");
219         }
220         free(vregion);
221     }
222     return err1;
223 }
224
225 /**
226  * \brief Wrapper for creating and mapping a memory object of type one frame
227  */
228 errval_t vspace_map_one_frame(void **retaddr, size_t size, struct capref frame,
229                               struct memobj **retmemobj,
230                               struct vregion **retvregion)
231 {
232     return vspace_map_one_frame_attr(retaddr, size, frame,
233                                      VREGION_FLAGS_READ_WRITE, retmemobj,
234                                      retvregion);
235 }
236
237 errval_t vspace_map_one_frame_fixed(lvaddr_t addr, size_t size,
238                                     struct capref frame,
239                                     struct memobj **retmemobj,
240                                     struct vregion **retvregion)
241 {
242     return vspace_map_one_frame_fixed_attr(addr, size, frame,
243                                            VREGION_FLAGS_READ_WRITE, retmemobj,
244                                            retvregion);
245 }
246
247 errval_t vspace_map_one_frame_fixed_attr(lvaddr_t addr, size_t size,
248                                     struct capref frame, vregion_flags_t flags,
249                                     struct memobj **retmemobj,
250                                     struct vregion **retvregion)
251 {
252     errval_t err1, err2;
253     struct memobj *memobj   = NULL;
254     struct vregion *vregion = NULL;
255
256     size = ROUND_UP(size, BASE_PAGE_SIZE);
257
258     // Allocate space
259     memobj = malloc(sizeof(struct memobj_one_frame));
260     if (!memobj) {
261         err1 = LIB_ERR_MALLOC_FAIL;
262         goto error;
263     }
264     vregion = malloc(sizeof(struct vregion));
265     if (!vregion) {
266         err1 = LIB_ERR_MALLOC_FAIL;
267         goto error;
268     }
269
270     // Create mappings
271     err1 = memobj_create_one_frame((struct memobj_one_frame*)memobj, size, 0);
272     if (err_is_fail(err1)) {
273         err1 = err_push(err1, LIB_ERR_MEMOBJ_CREATE_ONE_FRAME);
274         goto error;
275     }
276
277     err1 = memobj->f.fill(memobj, 0, frame, size);
278     if (err_is_fail(err1)) {
279         err1 = err_push(err1, LIB_ERR_MEMOBJ_FILL);
280         goto error;
281     }
282
283     err1 = vregion_map_fixed(vregion, get_current_vspace(), memobj, 0, size, addr, flags);
284     if (err_is_fail(err1)) {
285         err1 = err_push(err1, LIB_ERR_VREGION_MAP);
286         goto error;
287     }
288
289     err1 = memobj->f.pagefault(memobj, vregion, 0, 0);
290     if (err_is_fail(err1)) {
291         err1 = err_push(err1, LIB_ERR_MEMOBJ_PAGEFAULT_HANDLER);
292         goto error;
293     }
294
295     if (retmemobj) {
296         *retmemobj = memobj;
297     }
298     if (retvregion) {
299         *retvregion = vregion;
300     }
301     return SYS_ERR_OK;
302
303  error:
304     if (memobj) {
305         err2 = memobj_destroy_one_frame(memobj);
306         if (err_is_fail(err2)) {
307             DEBUG_ERR(err2, "memobj_destroy_anon failed");
308         }
309     }
310     if (vregion) {
311         err2 = vregion_destroy(vregion);
312         if (err_is_fail(err2)) {
313             DEBUG_ERR(err2, "vregion_destroy failed");
314         }
315     }
316     return err1;
317 }
318
319 /**
320  * \brief Wrapper for creating and mapping a memory object
321  * of type one frame with specific flags
322  */
323 errval_t vspace_map_one_frame_attr(void **retaddr, size_t size,
324                                    struct capref frame, vregion_flags_t flags,
325                                    struct memobj **retmemobj,
326                                    struct vregion **retvregion)
327 {
328     return vspace_map_one_frame_attr_aligned(retaddr, size,
329             frame, flags, 0, retmemobj, retvregion);
330 }
331
332 /**
333  * \brief Wrapper for creating and mapping a memory object
334  * of type one frame with specific flags and a specific alignment
335  */
336 errval_t vspace_map_one_frame_attr_aligned(void **retaddr, size_t size,
337                                    struct capref frame, vregion_flags_t flags,
338                                    size_t alignment,
339                                    struct memobj **retmemobj,
340                                    struct vregion **retvregion)
341 {
342     errval_t err1, err2;
343     struct memobj *memobj   = NULL;
344     struct vregion *vregion = NULL;
345
346     size = ROUND_UP(size, BASE_PAGE_SIZE);
347
348     // Allocate space
349     memobj = calloc(1, sizeof(struct memobj_one_frame));
350     if (!memobj) {
351         err1 = LIB_ERR_MALLOC_FAIL;
352         goto error;
353     }
354     vregion = calloc(1, sizeof(struct vregion));
355     if (!vregion) {
356         err1 = LIB_ERR_MALLOC_FAIL;
357         goto error;
358     }
359
360     // Create mappings
361     err1 = memobj_create_one_frame((struct memobj_one_frame*)memobj, size, 0);
362     if (err_is_fail(err1)) {
363         err1 = err_push(err1, LIB_ERR_MEMOBJ_CREATE_ONE_FRAME);
364         goto error;
365     }
366
367     err1 = memobj->f.fill(memobj, 0, frame, size);
368     if (err_is_fail(err1)) {
369         err1 = err_push(err1, LIB_ERR_MEMOBJ_FILL);
370         goto error;
371     }
372
373     err1 = vregion_map_aligned(vregion, get_current_vspace(), memobj, 0, size,
374             flags, alignment);
375     if (err_is_fail(err1)) {
376         err1 = err_push(err1, LIB_ERR_VREGION_MAP);
377         goto error;
378     }
379
380     err1 = memobj->f.pagefault(memobj, vregion, 0, 0);
381     if (err_is_fail(err1)) {
382         err1 = err_push(err1, LIB_ERR_MEMOBJ_PAGEFAULT_HANDLER);
383         goto error;
384     }
385
386     *retaddr = (void*)vspace_genvaddr_to_lvaddr(vregion_get_base_addr(vregion));
387     if (retmemobj) {
388         *retmemobj = memobj;
389     }
390     if (retvregion) {
391         *retvregion = vregion;
392     }
393     return SYS_ERR_OK;
394
395  error:
396     if (memobj) {
397         err2 = memobj_destroy_one_frame(memobj);
398         if (err_is_fail(err2)) {
399             DEBUG_ERR(err2, "memobj_destroy_anon failed");
400         }
401     }
402     if (vregion) {
403         err2 = vregion_destroy(vregion);
404         if (err_is_fail(err2)) {
405             DEBUG_ERR(err2, "vregion_destroy failed");
406         }
407     }
408     return err1;
409 }
410
411 errval_t vspace_map_one_frame_one_map(struct memobj_one_frame_one_map *memobj,
412                                       struct vregion *vregion, size_t size,
413                                       struct capref frame)
414 {
415     errval_t err;
416
417     err = memobj_create_one_frame_one_map(memobj, size, 0);
418     if (err_is_fail(err)) {
419         return err_push(err, LIB_ERR_MEMOBJ_CREATE_ONE_FRAME_ONE_MAP);
420     }
421     err = memobj->m.f.fill(&memobj->m, 0, frame, size);
422     if (err_is_fail(err)) {
423         return err_push(err, LIB_ERR_MEMOBJ_FILL);
424     }
425     err = vregion_map(vregion, get_current_vspace(), &memobj->m, 0, size,
426                       VREGION_FLAGS_READ_WRITE);
427     if (err_is_fail(err)) {
428         return err_push(err, LIB_ERR_VREGION_MAP);
429     }
430     err = memobj->m.f.pagefault(&memobj->m, vregion, 0, 0);
431     if (err_is_fail(err)) {
432         return err_push(err, LIB_ERR_MEMOBJ_PAGEFAULT_HANDLER);
433     }
434
435     return SYS_ERR_OK;
436 }