1/**
2 * \file
3 * \brief vregion management
4 *
5 * A vregion is backed by a memory object and a vspace.
6 * A vregion manages a range of virtual address space.
7 */
8
9/*
10 * Copyright (c) 2009, 2010, ETH Zurich.
11 * Copyright (c) 2014, HP Labs.
12 * All rights reserved.
13 *
14 * This file is distributed under the terms in the attached LICENSE file.
15 * If you do not find this file, copies can be found by writing to:
16 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
17 */
18
19#include <barrelfish/barrelfish.h>
20#include "vspace_internal.h"
21
22/**
23 * \brief Setup a new vregion with alignment constraints in an address space
24 *
25 * \param vregion  The vregion
26 * \param vspace   The vspace to associate with the vregion
27 * \param memobj   The memory object to associate with the region
28 * \param offset   Offset into the memory object
29 * \param size     Size of the memory object to use
30 * \param flags    Vregion specific flags
31 * \param alignment Minimum required alignment of mapping (may be increased)
32 */
33errval_t vregion_map_aligned(struct vregion *vregion, struct vspace* vspace,
34                             struct memobj *memobj, size_t offset, size_t size,
35                             vregion_flags_t flags, size_t alignment)
36{
37    errval_t err;
38    struct pmap *pmap = vspace_get_pmap(vspace);
39
40    // Allocate some virtual address space
41    genvaddr_t address;
42    err = pmap->f.determine_addr(pmap, memobj, alignment, &address);
43    if (err_is_fail(err)) {
44        return err_push(err, LIB_ERR_PMAP_DETERMINE_ADDR);
45    }
46
47    // Initialize
48    vregion->vspace = vspace;
49    vregion->memobj = memobj;
50    vregion->base   = address;
51    vregion->offset = offset;
52    vregion->size   = size;
53    vregion->flags  = flags;
54
55    // Add to the vspace
56    err = vspace_add_vregion(vspace, vregion);
57    if (err_is_fail(err)) {
58        return err_push(err, LIB_ERR_VSPACE_ADD_REGION);
59    }
60
61    // Add to memobj
62    err = memobj->f.map_region(memobj, vregion);
63    if (err_is_fail(err)) {
64        // remove memobj from region if map fails, otherwise we'll get a
65        // follow up error if client code call vregion_destroy() on the
66        // region.
67        vregion->memobj = NULL;
68        return err_push(err, LIB_ERR_MEMOBJ_MAP_REGION);
69    }
70
71    return SYS_ERR_OK;
72}
73
74/**
75 * \brief Setup a new vregion anywhere in the address space
76 *
77 * \param vregion  The vregion
78 * \param vspace   The vspace to associate with the vregion
79 * \param memobj   The memory object to associate with the region
80 * \param offset   Offset into the memory object
81 * \param size     Size of the memory object to use
82 * \param flags    Vregion specific flags
83 */
84errval_t vregion_map(struct vregion *vregion, struct vspace *vspace,
85                     struct memobj *memobj, size_t offset, size_t size,
86                     vregion_flags_t flags)
87{
88    return vregion_map_aligned(vregion, vspace, memobj, offset, size, flags, 0);
89}
90
91/**
92 * \brief Setup a new vregion at a specified location
93 *
94 * \param vregion  The region
95 * \param vspace   The vspace to associate with the region
96 * \param memobj   The memory object to associate with the region
97 * \param offset   Offset into the memory object
98 * \param size     Size of the memory object to use
99 * \param addr     Address to create the vregion for
100 * \param flags    Vregion specific flags
101 */
102errval_t vregion_map_fixed(struct vregion *vregion, struct vspace *vspace,
103                           struct memobj *memobj, size_t offset, size_t size,
104                           genvaddr_t addr, vregion_flags_t flags)
105{
106    errval_t err;
107
108    // FIXME: this check is arch-specific and should involve a call on the pmap
109    if (addr % BASE_PAGE_SIZE != 0) {
110        return LIB_ERR_VREGION_BAD_ALIGNMENT;
111    }
112
113    // Initialize
114    vregion->vspace = vspace;
115    vregion->memobj = memobj;
116    vregion->base   = addr;
117    vregion->offset = offset;
118    vregion->size   = size;
119    vregion->flags  = flags;
120
121    // Add to vspace
122    err = vspace_add_vregion(vspace, vregion);
123    if (err_is_fail(err)) {
124        return err_push(err, LIB_ERR_VSPACE_ADD_REGION);
125    }
126
127    // Add to memobj
128    err = memobj->f.map_region(memobj, vregion);
129    if (err_is_fail(err)) {
130        return err_push(err, LIB_ERR_MEMOBJ_MAP_REGION);
131    }
132
133    return SYS_ERR_OK;
134}
135
136/**
137 * \brief Destroy the given region
138 *
139 * \return SYS_ERR_OK on success, error code on failure
140 *
141 * \bug This only works if the memobj type is memobj_one_frame.
142 */
143errval_t vregion_destroy(struct vregion *vregion)
144{
145    errval_t err;
146
147    if (!vregion) {
148        return SYS_ERR_OK;
149    }
150
151    struct vspace *vspace = vregion_get_vspace(vregion);
152    if (vspace != NULL) {
153        err = vspace_remove_vregion(vspace, vregion);
154        if (err_is_fail(err)) {
155            return err_push(err, LIB_ERR_VSPACE_REMOVE_REGION);
156        }
157    }
158
159    struct memobj *memobj = vregion_get_memobj(vregion);
160    if (memobj != NULL) {
161        err = memobj->f.unmap_region(memobj, vregion);
162        if (err_is_fail(err)) {
163            return err_push(err, LIB_ERR_MEMOBJ_UNMAP_REGION);
164        }
165    }
166
167    return SYS_ERR_OK;
168}
169
170/**
171 * \brief Page fault handler
172 *
173 * \param vregion  The vregion the fault occured in
174 * \param addr   The faulting address
175 * \param type   The fault type
176 *
177 * Look up the appropriate memory object and forward the fault to it
178 */
179errval_t vregion_pagefault_handler(struct vregion *vregion, genvaddr_t addr,
180                                   vm_fault_type_t type)
181{
182    struct memobj *memobj = vregion->memobj;
183    genvaddr_t offset = addr - vregion->base;
184
185    return memobj->f.pagefault(memobj, vregion, offset, type);
186}
187