1/**
2 * \file
3 * \brief memory object of type single frame
4 */
5
6/*
7 * Copyright (c) 2009, 2010, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <barrelfish/barrelfish.h>
16#include "vspace_internal.h"
17
18/**
19 * \brief Map the memory object into a region
20 *
21 * \param memobj  The memory object
22 * \param region  The region to add
23 */
24static errval_t map_region(struct memobj *memobj, struct vregion *vregion)
25{
26    struct memobj_one_frame *one_frame = (struct memobj_one_frame*)memobj;
27
28    // Allocate and insert
29    struct vregion_list *data = malloc(sizeof(struct vregion_list));
30    if (!data) {
31        return LIB_ERR_MALLOC_FAIL;
32    }
33    data->region = vregion;
34    struct vregion_list *walk = one_frame->vregion_list;
35    one_frame->vregion_list = data;
36    data->next = walk;
37
38    return SYS_ERR_OK;
39}
40
41/**
42 * \brief Unmap the memory object from a region
43 *
44 * \param memobj   The memory object
45 * \param region  The region to remove
46 *
47 * Will delete self using free if no more vregions are mapped in
48 */
49static errval_t unmap_region(struct memobj *memobj, struct vregion *vregion)
50{
51    errval_t err;
52    struct memobj_one_frame *one_frame = (struct memobj_one_frame*)memobj;
53
54    /* Unmap the affected area in the pmap */
55    // XXX: assuming that area is mapped in pmap, i.e. pagefault was called
56    struct vspace *vspace = vregion_get_vspace(vregion);
57    struct pmap *pmap     = vspace_get_pmap(vspace);
58    genvaddr_t vregion_base  = vregion_get_base_addr(vregion);
59    genvaddr_t vregion_off   = vregion_get_offset(vregion);
60
61    err = pmap->f.unmap(pmap, vregion_base + vregion_off, memobj->size, NULL);
62    if (err_is_fail(err)) {
63        return err_push(err, LIB_ERR_PMAP_UNMAP);
64    }
65
66    /* Remove the vregion from the list */
67    struct vregion_list *walk = one_frame->vregion_list;
68    struct vregion_list *prev = NULL;
69    while (walk) {
70        if (walk->region == vregion) {
71            if (prev) {
72                prev->next = walk->next;
73                free(walk);
74                return SYS_ERR_OK;
75            } else {
76                one_frame->vregion_list = walk->next;
77                free(walk);
78                free(memobj);
79                return SYS_ERR_OK;
80            }
81        }
82        prev = walk;
83        walk = walk->next;
84    }
85
86    return LIB_ERR_VREGION_NOT_FOUND;
87}
88
89/**
90 * \brief Set the protection on a range
91 *
92 * \param memobj  The memory object
93 * \param region  The vregion to modify the mappings on
94 * \param offset  Offset into the memory object
95 * \param range   The range of space to set the protection for
96 * \param flags   The protection flags
97 */
98static errval_t protect(struct memobj *memobj, struct vregion *vregion,
99                        genvaddr_t offset, size_t range, vs_prot_flags_t flags)
100{
101    struct vspace *vspace = vregion_get_vspace(vregion);
102    struct pmap *pmap = vspace_get_pmap(vspace);
103    genvaddr_t base = vregion_get_base_addr(vregion);
104    genvaddr_t vregion_offset = vregion_get_offset(vregion);
105    errval_t err;
106    size_t ret_size;
107    err = pmap->f.modify_flags(pmap, base + offset + vregion_offset, range,
108                               flags, &ret_size);
109    if (err_is_fail(err)) {
110        return err_push(err, LIB_ERR_PMAP_MODIFY_FLAGS);
111    }
112
113    return SYS_ERR_OK;
114}
115
116/**
117 * \brief Pin a range
118 *
119 * \param memobj  The memory object
120 * \param region  The vregion to modify the state on
121 * \param offset  Offset into the memory object
122 * \param range   The range of space to pin
123 */
124static errval_t pin(struct memobj *memobj, struct vregion *vregion,
125                    genvaddr_t offset, size_t range)
126{
127    USER_PANIC("NYI");
128}
129
130/**
131 * \brief Unpin a range
132 *
133 * \param memobj  The memory object
134 * \param region  The vregion to modify the state on
135 * \param offset  Offset into the memory object
136 * \param range   The range of space to unpin
137 */
138static errval_t unpin(struct memobj *memobj, struct vregion *vregion,
139                      genvaddr_t offset, size_t range)
140{
141    USER_PANIC("NYI");
142}
143
144/**
145 * \brief Set a frame for an offset into the memobj
146 *
147 * \param memobj  The memory object
148 * \param offset  Offset into the memory object
149 * \param frame   The frame cap for the offset
150 * \param size    The size of frame cap
151 */
152static errval_t fill(struct memobj *memobj, genvaddr_t offset, struct capref frame,
153                     size_t size)
154{
155    struct memobj_one_frame *one_frame = (struct memobj_one_frame*)memobj;
156
157    assert(size == memobj->size);
158    one_frame->frame  = frame;
159    one_frame->offset = offset;
160
161    return SYS_ERR_OK;
162}
163
164/**
165 * \brief Page fault handler
166 *
167 * \param memobj  The memory object
168 * \param region  The associated vregion
169 * \param offset  Offset into memory object of the page fault
170 * \param type    The fault type
171 */
172static errval_t pagefault(struct memobj *memobj, struct vregion *vregion,
173                          genvaddr_t offset, vm_fault_type_t type)
174{
175    errval_t err;
176    struct memobj_one_frame *one_frame = (struct memobj_one_frame*)memobj;
177    if (offset < one_frame->offset ||
178        offset > one_frame->offset + memobj->size) {
179        return LIB_ERR_MEMOBJ_WRONG_OFFSET;
180    }
181
182    // Map the single frame
183    struct vspace *vspace = vregion_get_vspace(vregion);
184    struct pmap *pmap     = vspace_get_pmap(vspace);
185    genvaddr_t vregion_base  = vregion_get_base_addr(vregion);
186    genvaddr_t vregion_off   = vregion_get_offset(vregion);
187    vregion_flags_t flags = vregion_get_flags(vregion);
188
189    err = pmap->f.map(pmap, vregion_base + vregion_off, one_frame->frame,
190                      one_frame->offset, memobj->size, flags, NULL, NULL);
191    if (err_is_fail(err)) {
192        return err_push(err, LIB_ERR_PMAP_MAP);
193    }
194
195    return SYS_ERR_OK;
196}
197
198/**
199 * \brief Free up some pages by placing them in the backing storage
200 *
201 * \param memobj      The memory object
202 * \param size        The amount of space to free up
203 * \param frames      An array of capref frames to return the freed pages
204 * \param num_frames  The number of frames returned
205 *
206 * This will affect all the vregions that are associated with the object
207 */
208static errval_t pager_free(struct memobj *memobj, size_t size,
209                                  struct capref *frames, size_t num_frames)
210{
211    USER_PANIC("NYI");
212}
213
214/**
215 * \brief Initialize a memory object of type one frame
216 *
217 * \param memobj  The memory object
218 * \param size    Size of the memory region
219 * \param flags   Memory object specific flags
220 * \param frame   The frame to use
221 * \param offset  Offset into the frame
222 */
223errval_t memobj_create_one_frame(struct memobj_one_frame *one_frame,
224                                 size_t size, memobj_flags_t flags)
225{
226    struct memobj *memobj = &one_frame->m;
227
228    /* Generic portion */
229    memobj->f.map_region   = map_region;
230    memobj->f.unmap_region = unmap_region;
231    memobj->f.protect = protect;
232    memobj->f.pin   = pin;
233    memobj->f.unpin = unpin;
234    memobj->f.fill  = fill;
235    memobj->f.pagefault  = pagefault;
236    memobj->f.pager_free = pager_free;
237
238    memobj->size  = size;
239    memobj->flags = flags;
240
241    memobj->type = ONE_FRAME;
242
243    /* one_frame specific portion */
244    one_frame->vregion_list = NULL;
245    return SYS_ERR_OK;
246}
247
248/**
249 * \brief Destroy the object
250 *
251 * \bug NYI
252 */
253errval_t memobj_destroy_one_frame(struct memobj *memobj)
254{
255    return SYS_ERR_OK;
256}
257