1/**
2 * \file
3 * \brief memory object that maintains a single frame and can be mapped once
4 */
5
6/*
7 * Copyright (c) 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_map *state =
27        (struct memobj_one_frame_one_map*)memobj;
28
29    if (state->vregion) {
30        return LIB_ERR_MEMOBJ_VREGION_ALREADY_MAPPED;
31    }
32
33    state->vregion = vregion;
34    return SYS_ERR_OK;
35}
36
37/**
38 * \brief Unmap the memory object from a region
39 *
40 * \param memobj   The memory object
41 * \param region  The region to remove
42 */
43static errval_t unmap_region(struct memobj *memobj, struct vregion *vregion)
44{
45    errval_t err;
46    struct memobj_one_frame_one_map *one_frame = (struct memobj_one_frame_one_map*)memobj;
47
48    if (one_frame->vregion != vregion) {
49        return LIB_ERR_VREGION_NOT_FOUND;
50    }
51
52    struct vspace *vspace = vregion_get_vspace(vregion);
53    struct pmap *pmap     = vspace_get_pmap(vspace);
54    genvaddr_t vregion_base  = vregion_get_base_addr(vregion);
55    genvaddr_t vregion_off   = vregion_get_offset(vregion);
56
57    err = pmap->f.unmap(pmap, vregion_base + vregion_off, memobj->size, NULL);
58    if (err_is_fail(err)) {
59        return err_push(err, LIB_ERR_PMAP_UNMAP);
60    }
61
62    one_frame->vregion = NULL;
63
64    return SYS_ERR_OK;
65}
66
67
68static errval_t protect(struct memobj *memobj, struct vregion *vregion,
69                        genvaddr_t offset, size_t range, vs_prot_flags_t flags)
70{
71    struct vspace *vspace = vregion_get_vspace(vregion);
72    struct pmap *pmap = vspace_get_pmap(vspace);
73    genvaddr_t base = vregion_get_base_addr(vregion);
74    genvaddr_t vregion_offset = vregion_get_offset(vregion);
75    errval_t err;
76    size_t ret_size;
77    err = pmap->f.modify_flags(pmap, base + offset + vregion_offset, range,
78                               flags, &ret_size);
79    if (err_is_fail(err)) {
80        return err_push(err, LIB_ERR_PMAP_MODIFY_FLAGS);
81    }
82
83    return SYS_ERR_OK;
84}
85
86/**
87 * \brief Pin a range
88 *
89 * \param memobj  The memory object
90 * \param region  The vregion to modify the state on
91 * \param offset  Offset into the memory object
92 * \param range   The range of space to pin
93 */
94static errval_t pin(struct memobj *memobj, struct vregion *vregion,
95                    genvaddr_t offset, size_t range)
96{
97    USER_PANIC("NYI");
98    return SYS_ERR_OK;
99}
100
101/**
102 * \brief Unpin a range
103 *
104 * \param memobj  The memory object
105 * \param region  The vregion to modify the state on
106 * \param offset  Offset into the memory object
107 * \param range   The range of space to unpin
108 */
109static errval_t unpin(struct memobj *memobj, struct vregion *vregion,
110                      genvaddr_t offset, size_t range)
111{
112    USER_PANIC("NYI");
113    return SYS_ERR_OK;
114}
115
116/**
117 * \brief Set a frame for an offset into the memobj
118 *
119 * \param memobj  The memory object
120 * \param offset  Offset into the memory object
121 * \param frame   The frame cap for the offset
122 * \param size    The size of frame cap
123 */
124static errval_t fill(struct memobj *memobj, genvaddr_t offset, struct capref frame,
125                     size_t size)
126{
127    struct memobj_one_frame_one_map *state =
128        (struct memobj_one_frame_one_map*)memobj;
129
130    assert(size == memobj->size);
131    state->frame  = frame;
132    state->offset = offset;
133
134    return SYS_ERR_OK;
135}
136
137/**
138 * \brief Page fault handler
139 *
140 * \param memobj  The memory object
141 * \param region  The associated vregion
142 * \param offset  Offset into memory object of the page fault
143 * \param type    The fault type
144 */
145static errval_t pagefault(struct memobj *memobj, struct vregion *vregion,
146                          genvaddr_t offset, vm_fault_type_t type)
147{
148    errval_t err;
149    struct memobj_one_frame_one_map *state =
150        (struct memobj_one_frame_one_map*)memobj;
151    if (offset < state->offset ||
152        offset > state->offset + memobj->size) {
153        return LIB_ERR_MEMOBJ_WRONG_OFFSET;
154    }
155
156    // Map the single frame
157    struct vspace *vspace = vregion_get_vspace(vregion);
158    struct pmap *pmap     = vspace_get_pmap(vspace);
159    genvaddr_t vregion_base  = vregion_get_base_addr(vregion);
160    genvaddr_t vregion_off   = vregion_get_offset(vregion);
161    vregion_flags_t flags = vregion_get_flags(vregion);
162
163    err = pmap->f.map(pmap, vregion_base + vregion_off, state->frame,
164                      state->offset, memobj->size, flags, NULL, NULL);
165    if (err_is_fail(err)) {
166        return err_push(err, LIB_ERR_PMAP_MAP);
167    }
168
169    return SYS_ERR_OK;
170}
171
172/**
173 * \brief Free up some pages by placing them in the backing storage
174 *
175 * \param memobj      The memory object
176 * \param size        The amount of space to free up
177 * \param frames      An array of capref frames to return the freed pages
178 * \param num_frames  The number of frames returned
179 *
180 * This will affect all the vregions that are associated with the object
181 */
182static errval_t pager_free(struct memobj *memobj, size_t size,
183                                  struct capref *frames, size_t num_frames)
184{
185    USER_PANIC("NYI");
186    return SYS_ERR_OK;
187}
188
189/**
190 * \brief Initialize a memory object of type one frame
191 *
192 * \param memobj  The memory object
193 * \param size    Size of the memory region
194 * \param flags   Memory object specific flags
195 * \param frame   The frame to use
196 * \param offset  Offset into the frame
197 */
198errval_t memobj_create_one_frame_one_map(struct memobj_one_frame_one_map *state,
199                                         size_t size, memobj_flags_t flags)
200{
201    struct memobj *memobj = &state->m;
202
203    /* Generic portion */
204    memobj->f.map_region   = map_region;
205    memobj->f.unmap_region = unmap_region;
206    memobj->f.protect = protect;
207    memobj->f.pin   = pin;
208    memobj->f.unpin = unpin;
209    memobj->f.fill  = fill;
210    memobj->f.pagefault  = pagefault;
211    memobj->f.pager_free = pager_free;
212
213    memobj->size  = size;
214    memobj->flags = flags;
215
216    memobj->type = ONE_FRAME_ONE_MAP;
217
218    /* one_frame_one_map specific portion */
219    state->vregion = NULL;
220    return SYS_ERR_OK;
221}
222