1/** 2 * \file 3 * \brief vspace management 4 * 5 * A vspace consists of a set of vregions and one pmap. 6 * The current vspace is setup by the (domain/dispatcher?) spawning it. 7 * 8 * Warning: slot_alloc_init calls vregion_map which calls vspace_add_vregion. 9 * vspace_add_vregion uses malloc to increase it's slab. 10 * Since malloc depends upon slot_alloc_init being called successfully, 11 * vspace_add_vregion should have enough initial slab space to not use malloc. 12 */ 13 14/* 15 * Copyright (c) 2009, 2010, 2011, ETH Zurich. 16 * All rights reserved. 17 * 18 * This file is distributed under the terms in the attached LICENSE file. 19 * If you do not find this file, copies can be found by writing to: 20 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 21 */ 22 23#include <barrelfish/barrelfish.h> 24#include <barrelfish/core_state.h> 25#include "vspace_internal.h" 26#include <stdio.h> 27 28/** 29 * \brief Initialize the current vspace structure 30 * 31 * This code is coupled with #pmap_current_init() 32 */ 33errval_t vspace_current_init(bool init_domain) 34{ 35 errval_t err; 36 struct vspace *vspace = get_current_vspace(); 37 struct pmap *pmap = get_current_pmap(); 38 39 vspace->pmap = pmap; 40 vspace->head = NULL; 41 42 // Setup the layout 43 err = vspace_layout_init(&vspace->layout); 44 if (err_is_fail(err)) { 45 return err_push(err, LIB_ERR_VSPACE_LAYOUT_INIT); 46 } 47 48 // Initialize current pmap 49 struct capref cap = { 50 .cnode = cnode_page, 51 .slot = 0, 52 }; 53 err = pmap_init(pmap, vspace, cap, NULL); 54 if (err_is_fail(err)) { 55 return err_push(err, LIB_ERR_PMAP_INIT); 56 } 57 err = pmap_current_init(init_domain); 58 if (err_is_fail(err)) { 59 return err_push(err, LIB_ERR_PMAP_CURRENT_INIT); 60 } 61 62 // Initialize pinned memory 63 err = vspace_pinned_init(); 64 if (err_is_fail(err)) { 65 return err_push(err, LIB_ERR_VSPACE_PINNED_INIT); 66 } 67 68 return SYS_ERR_OK; 69} 70 71/** 72 * \brief Add a new region into the vspace 73 * 74 * \param point The vspace struct 75 * \param region The region to add 76 * 77 * pmap implementation rely on vspace maintaining an ordered list of vregions 78 */ 79errval_t vspace_add_vregion(struct vspace *vspace, struct vregion *region) 80{ 81 // Sanity-check region (TODO: return error?) 82 assert(region->size > 0); 83 assert(region->base + region->size > region->base); 84 85 if (vspace->head == NULL) { 86 vspace->head = region; 87 region->next = NULL; 88 return SYS_ERR_OK; 89 } 90 91 // Insert in order 92 struct vregion *walk = vspace->head; 93 struct vregion *prev = NULL; 94 while (walk != NULL) { 95 if (region->base <= walk->base) { 96 /* check for overlaps! */ 97 if (region->base + region->size > walk->base 98 || (prev != NULL && prev->base + prev->size > region->base)) { 99 return LIB_ERR_VSPACE_REGION_OVERLAP; 100 } 101 102 /* add here */ 103 if (prev == NULL) { 104 region->next = vspace->head; 105 vspace->head = region; 106 } else { 107 prev->next = region; 108 region->next = walk; 109 } 110 return SYS_ERR_OK; 111 } 112 113 prev = walk; 114 walk = walk->next; 115 } 116 117 /* add to end of list, checking for overlap with last item */ 118 assert(prev != NULL); 119 if (prev->base + prev->size > region->base) { 120 return LIB_ERR_VSPACE_REGION_OVERLAP; 121 } 122 prev->next = region; 123 region->next = NULL; 124 return SYS_ERR_OK; 125} 126 127/** 128 * \brief remove a region from the vspace 129 * 130 * \param point The vspace struct 131 * \param region The region to remove 132 * 133 * Library internal function 134 */ 135errval_t vspace_remove_vregion(struct vspace *vspace, struct vregion* region) 136{ 137 assert(vspace != NULL); 138 struct vregion *walk = vspace->head; 139 struct vregion *prev = NULL; 140 141 while (walk) { 142 if (walk == region) { 143 if (prev) { 144 assert(prev->next == walk); 145 prev->next = walk->next; 146 } else { 147 assert(walk == vspace->head); 148 vspace->head = walk->next; 149 } 150 return SYS_ERR_OK; 151 } 152 prev = walk; 153 walk = walk->next; 154 } 155 156 return LIB_ERR_VREGION_NOT_FOUND; 157} 158 159/** 160 * \brief Initialize a vspace 161 * 162 * \param vspace The vspace to initialize 163 * \param pmap The pmap to associate with the vspace 164 * 165 * Initializes a vspace, associating it with a pmap 166 */ 167errval_t vspace_init(struct vspace *vspace, struct pmap *pmap) 168{ 169 errval_t err; 170 171 vspace->pmap = pmap; 172 vspace->head = NULL; 173 174 // Setup the layout 175 err = vspace_layout_init(&vspace->layout); 176 if (err_is_fail(err)) { 177 return err_push(err, LIB_ERR_VSPACE_LAYOUT_INIT); 178 } 179 180 return SYS_ERR_OK; 181} 182 183/** 184 * \brief Destroy a vspace 185 */ 186errval_t vspace_destroy(struct vspace *vspace) 187{ 188 USER_PANIC("NYI"); 189} 190 191/** 192 * \brief Get the region corresponding to the given virtual address 193 * 194 * \param addr The virtual address 195 */ 196struct vregion* vspace_get_region(struct vspace *vspace, const void *addr) 197{ 198 lvaddr_t lvaddr = (lvaddr_t)addr; 199 genvaddr_t genvaddr = vspace_lvaddr_to_genvaddr(lvaddr); 200 201 struct vregion *walk = vspace->head; 202 while (walk) { 203 if (walk->base <= genvaddr && 204 walk->base + walk->size > genvaddr) { 205 return walk; 206 } 207 walk = walk->next; 208 } 209 210 return NULL; 211} 212 213/** 214 * \brief Page fault handler 215 * 216 * \param point The vspace page fault occured in 217 * \param addr The faulting address 218 * \param type The fault type 219 * 220 * Lookup the appropriate vregion and forward the fault to it 221 */ 222errval_t vspace_pagefault_handler(struct vspace *vspace, lvaddr_t lvaddr, 223 vm_fault_type_t type) 224{ 225 errval_t err; 226 227 genvaddr_t genvaddr = 228 vspace_layout_lvaddr_to_genvaddr(&vspace->layout, lvaddr); 229 230 struct vregion *walk = vspace->head; 231 while(walk != NULL) { 232 genvaddr_t base = vregion_get_base_addr(walk); 233 genvaddr_t size = vregion_get_size(walk); 234 if (genvaddr >= base && genvaddr < base + size) { 235 err = vregion_pagefault_handler(walk, genvaddr, type); 236 if (err_is_fail(err)) { 237 return err_push(err, LIB_ERR_VREGION_PAGEFAULT_HANDLER); 238 } 239 return SYS_ERR_OK; 240 } 241 walk = walk->next; 242 } 243 244 return LIB_ERR_VSPACE_PAGEFAULT_ADDR_NOT_FOUND; 245} 246