1130812Smarcel/**
2130812Smarcel * \file
3130812Smarcel * \brief memory object of type single frame
4130812Smarcel */
5130812Smarcel
6130812Smarcel/*
7130812Smarcel * Copyright (c) 2009, 2010, ETH Zurich.
8130812Smarcel * All rights reserved.
9130812Smarcel *
10130812Smarcel * This file is distributed under the terms in the attached LICENSE file.
11130812Smarcel * If you do not find this file, copies can be found by writing to:
12130812Smarcel * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13130812Smarcel */
14130812Smarcel
15130812Smarcel#include <barrelfish/barrelfish.h>
16130812Smarcel#include "vspace_internal.h"
17130812Smarcel
18130812Smarcel/**
19130812Smarcel * \brief Map the memory object into a region
20130812Smarcel *
21130812Smarcel * \param memobj  The memory object
22130812Smarcel * \param region  The region to add
23130812Smarcel */
24130812Smarcelstatic errval_t map_region(struct memobj *memobj, struct vregion *vregion)
25130812Smarcel{
26130812Smarcel    struct memobj_one_frame *one_frame = (struct memobj_one_frame*)memobj;
27130812Smarcel
28130812Smarcel    // Allocate and insert
29130812Smarcel    struct vregion_list *data = malloc(sizeof(struct vregion_list));
30130812Smarcel    if (!data) {
31130812Smarcel        return LIB_ERR_MALLOC_FAIL;
32130812Smarcel    }
33130812Smarcel    data->region = vregion;
34130812Smarcel    struct vregion_list *walk = one_frame->vregion_list;
35130812Smarcel    one_frame->vregion_list = data;
36130812Smarcel    data->next = walk;
37130812Smarcel
38130812Smarcel    return SYS_ERR_OK;
39130812Smarcel}
40130812Smarcel
41130812Smarcel/**
42130812Smarcel * \brief Unmap the memory object from a region
43130812Smarcel *
44130812Smarcel * \param memobj   The memory object
45130812Smarcel * \param region  The region to remove
46130812Smarcel *
47130812Smarcel * Will delete self using free if no more vregions are mapped in
48130812Smarcel */
49130812Smarcelstatic errval_t unmap_region(struct memobj *memobj, struct vregion *vregion)
50130812Smarcel{
51130812Smarcel    errval_t err;
52130812Smarcel    struct memobj_one_frame *one_frame = (struct memobj_one_frame*)memobj;
53130812Smarcel
54130812Smarcel    /* Unmap the affected area in the pmap */
55130812Smarcel    // XXX: assuming that area is mapped in pmap, i.e. pagefault was called
56130812Smarcel    struct vspace *vspace = vregion_get_vspace(vregion);
57130812Smarcel    struct pmap *pmap     = vspace_get_pmap(vspace);
58130812Smarcel    genvaddr_t vregion_base  = vregion_get_base_addr(vregion);
59130812Smarcel    genvaddr_t vregion_off   = vregion_get_offset(vregion);
60130812Smarcel
61130812Smarcel    err = pmap->f.unmap(pmap, vregion_base + vregion_off, memobj->size, NULL);
62130812Smarcel    if (err_is_fail(err)) {
63130812Smarcel        return err_push(err, LIB_ERR_PMAP_UNMAP);
64130812Smarcel    }
65130812Smarcel
66130812Smarcel    /* Remove the vregion from the list */
67130812Smarcel    struct vregion_list *walk = one_frame->vregion_list;
68130812Smarcel    struct vregion_list *prev = NULL;
69130812Smarcel    while (walk) {
70130812Smarcel        if (walk->region == vregion) {
71130812Smarcel            if (prev) {
72130812Smarcel                prev->next = walk->next;
73130812Smarcel                free(walk);
74130812Smarcel                return SYS_ERR_OK;
75130812Smarcel            } else {
76130812Smarcel                one_frame->vregion_list = walk->next;
77130812Smarcel                free(walk);
78130812Smarcel                free(memobj);
79130812Smarcel                return SYS_ERR_OK;
80130812Smarcel            }
81130812Smarcel        }
82130812Smarcel        prev = walk;
83130812Smarcel        walk = walk->next;
84130812Smarcel    }
85130812Smarcel
86130812Smarcel    return LIB_ERR_VREGION_NOT_FOUND;
87130812Smarcel}
88130812Smarcel
89130812Smarcel/**
90130812Smarcel * \brief Set the protection on a range
91130812Smarcel *
92130812Smarcel * \param memobj  The memory object
93130812Smarcel * \param region  The vregion to modify the mappings on
94130812Smarcel * \param offset  Offset into the memory object
95130812Smarcel * \param range   The range of space to set the protection for
96130812Smarcel * \param flags   The protection flags
97130812Smarcel */
98130812Smarcelstatic errval_t protect(struct memobj *memobj, struct vregion *vregion,
99130812Smarcel                        genvaddr_t offset, size_t range, vs_prot_flags_t flags)
100130812Smarcel{
101130812Smarcel    struct vspace *vspace = vregion_get_vspace(vregion);
102130812Smarcel    struct pmap *pmap = vspace_get_pmap(vspace);
103130812Smarcel    genvaddr_t base = vregion_get_base_addr(vregion);
104130812Smarcel    genvaddr_t vregion_offset = vregion_get_offset(vregion);
105130812Smarcel    errval_t err;
106130812Smarcel    size_t ret_size;
107130812Smarcel    err = pmap->f.modify_flags(pmap, base + offset + vregion_offset, range,
108130812Smarcel                               flags, &ret_size);
109130812Smarcel    if (err_is_fail(err)) {
110130812Smarcel        return err_push(err, LIB_ERR_PMAP_MODIFY_FLAGS);
111130812Smarcel    }
112130812Smarcel
113130812Smarcel    return SYS_ERR_OK;
114130812Smarcel}
115130812Smarcel
116130812Smarcel/**
117130812Smarcel * \brief Pin a range
118130812Smarcel *
119130812Smarcel * \param memobj  The memory object
120130812Smarcel * \param region  The vregion to modify the state on
121130812Smarcel * \param offset  Offset into the memory object
122130812Smarcel * \param range   The range of space to pin
123130812Smarcel */
124130812Smarcelstatic errval_t pin(struct memobj *memobj, struct vregion *vregion,
125130812Smarcel                    genvaddr_t offset, size_t range)
126130812Smarcel{
127130812Smarcel    USER_PANIC("NYI");
128130812Smarcel}
129130812Smarcel
130130812Smarcel/**
131130812Smarcel * \brief Unpin a range
132130812Smarcel *
133130812Smarcel * \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