Rename struct slab_alloc to struct slab_allocator.
[barrelfish] / lib / barrelfish / vspace / pinned.c
1 /**
2  * \file
3  * \brief Managing the pinned memory for vspace metadata
4  *
5  * Warning: This code is coupled with code in slot_alloc/. and pmap_*.
6  *
7  * Slabs required for various lists in vspace
8  * and memobj are backed by this memobj.
9  * This memory is pinned since the frames are not tracked
10  * and cannot be mapped into multiple vregions.
11  *
12  * If the slabs maintained in the state are out of memory, it needs to be grown.
13  * This file will require 1 slot for frame capability
14  * and additional to create the mappings.
15  * The amount required can be calculated by refering to the pmap_*.
16  *
17  * Growing requires 1 slot from this file.
18  */
19
20 /*
21  * Copyright (c) 2010, ETH Zurich.
22  * All rights reserved.
23  *
24  * This file is distributed under the terms in the attached LICENSE file.
25  * If you do not find this file, copies can be found by writing to:
26  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
27  */
28
29 #include <barrelfish/barrelfish.h>
30 #include <barrelfish/core_state_arch.h>
31 #include "vspace_internal.h"
32
33
34 /**
35  * \brief Initialize the pinned region
36  *
37  * Allocates a region of virtual address space and initializes its state.
38  */
39 errval_t vspace_pinned_init(void)
40 {
41     errval_t err;
42
43     struct pinned_state *state = get_current_pinned_state();
44     struct vspace *vspace = get_current_vspace();
45
46     err = memobj_create_pinned(&state->memobj,
47                                VSPACE_PINNED_SIZE, 0);
48     if (err_is_fail(err)) {
49         return err_push(err, LIB_ERR_MEMOBJ_CREATE_PINNED);
50     }
51
52     err = vregion_map(&state->vregion, vspace,
53                       (struct memobj*)&state->memobj, 0, VSPACE_PINNED_SIZE,
54                       VREGION_FLAGS_READ_WRITE);
55     if (err_is_fail(err)) {
56         return err_push(err, LIB_ERR_VREGION_MAP);
57     }
58
59     state->offset = 0;
60     thread_mutex_init(&state->mutex);
61     slab_init(&state->vregion_list_slab, VSPACE_PINNED_UNIT *
62               sizeof(struct vregion_list), NULL);
63     slab_init(&state->frame_list_slab, VSPACE_PINNED_UNIT *
64               sizeof(struct memobj_frame_list), NULL);
65
66     return SYS_ERR_OK;
67 }
68
69 /**
70  * \brief Allocate some slabs
71  *
72  * \param retbuf     Pointer to return the allocated memory
73  * \param slab_type  Type of slab the memory is allocated for
74  *
75  * Since this region is used for backing specific slabs,
76  * only those types of slabs can be allocated.
77  */
78 errval_t vspace_pinned_alloc(void **retbuf, enum slab_type slab_type)
79 {
80     errval_t err;
81     struct pinned_state *state = get_current_pinned_state();
82
83     // Select slab type
84     struct slab_allocator *slab;
85     switch(slab_type) {
86     case VREGION_LIST:
87         slab = &state->vregion_list_slab;
88         break;
89     case FRAME_LIST:
90         slab = &state->frame_list_slab;
91         break;
92     default:
93         return LIB_ERR_VSPACE_PINNED_INVALID_TYPE;
94     }
95
96     thread_mutex_lock(&state->mutex);
97
98     // Try allocating
99     void *buf = slab_alloc(slab);
100     if (buf == NULL) {
101         // Out of memory, grow
102         struct capref frame;
103         err = frame_alloc(&frame, BASE_PAGE_SIZE, NULL);
104         if (err_is_fail(err)) {
105             thread_mutex_unlock(&state->mutex);
106             return err_push(err, LIB_ERR_FRAME_ALLOC);
107         }
108         err = state->memobj.m.f.fill((struct memobj*)&state->memobj,
109                                      state->offset, frame,
110                                      BASE_PAGE_SIZE);
111         if (err_is_fail(err)) {
112             thread_mutex_unlock(&state->mutex);
113             return err_push(err, LIB_ERR_MEMOBJ_FILL);
114         }
115
116         genvaddr_t gvaddr = vregion_get_base_addr(&state->vregion) +
117             state->offset;
118         void *slab_buf = (void*)vspace_genvaddr_to_lvaddr(gvaddr);
119         slab_grow(slab, slab_buf, BASE_PAGE_SIZE);
120         state->offset += BASE_PAGE_SIZE;
121
122         // Try again
123         buf = slab_alloc(slab);
124     }
125
126     thread_mutex_unlock(&state->mutex);
127
128     if (buf == NULL) {
129         return LIB_ERR_SLAB_ALLOC_FAIL;
130     } else {
131         *retbuf = buf;
132         return SYS_ERR_OK;
133     }
134 }