1/* 2 * Copyright 2014, General Dynamics C4 Systems 3 * 4 * This software may be distributed and modified according to the terms of 5 * the GNU General Public License version 2. Note that NO WARRANTY is provided. 6 * See "LICENSE_GPLv2.txt" for details. 7 * 8 * @TAG(GD_GPL) 9 */ 10 11#include <config.h> 12#include <types.h> 13#include <api/failures.h> 14#include <api/syscall.h> 15#include <api/invocation.h> 16#include <machine/io.h> 17#include <object/structures.h> 18#include <object/untyped.h> 19#include <object/objecttype.h> 20#include <object/cnode.h> 21#include <kernel/cspace.h> 22#include <kernel/thread.h> 23#include <util.h> 24 25static word_t 26alignUp(word_t baseValue, word_t alignment) 27{ 28 return (baseValue + (BIT(alignment) - 1)) & ~MASK(alignment); 29} 30 31exception_t 32decodeUntypedInvocation(word_t invLabel, word_t length, cte_t *slot, 33 cap_t cap, extra_caps_t excaps, 34 bool_t call, word_t *buffer) 35{ 36 word_t newType, userObjSize, nodeIndex; 37 word_t nodeDepth, nodeOffset, nodeWindow; 38 cte_t *rootSlot UNUSED; 39 exception_t status; 40 cap_t nodeCap; 41 lookupSlot_ret_t lu_ret; 42 word_t nodeSize; 43 word_t i; 44 slot_range_t slots; 45 word_t freeRef, alignedFreeRef, objectSize, untypedFreeBytes; 46 word_t freeIndex; 47 bool_t deviceMemory; 48 bool_t reset; 49 50 /* Ensure operation is valid. */ 51 if (invLabel != UntypedRetype) { 52 userError("Untyped cap: Illegal operation attempted."); 53 current_syscall_error.type = seL4_IllegalOperation; 54 return EXCEPTION_SYSCALL_ERROR; 55 } 56 57 /* Ensure message length valid. */ 58 if (length < 6 || excaps.excaprefs[0] == NULL) { 59 userError("Untyped invocation: Truncated message."); 60 current_syscall_error.type = seL4_TruncatedMessage; 61 return EXCEPTION_SYSCALL_ERROR; 62 } 63 64 /* Fetch arguments. */ 65 newType = getSyscallArg(0, buffer); 66 userObjSize = getSyscallArg(1, buffer); 67 nodeIndex = getSyscallArg(2, buffer); 68 nodeDepth = getSyscallArg(3, buffer); 69 nodeOffset = getSyscallArg(4, buffer); 70 nodeWindow = getSyscallArg(5, buffer); 71 72 rootSlot = excaps.excaprefs[0]; 73 74 /* Is the requested object type valid? */ 75 if (newType >= seL4_ObjectTypeCount) { 76 userError("Untyped Retype: Invalid object type."); 77 current_syscall_error.type = seL4_InvalidArgument; 78 current_syscall_error.invalidArgumentNumber = 0; 79 return EXCEPTION_SYSCALL_ERROR; 80 } 81 82 objectSize = getObjectSize(newType, userObjSize); 83 84 /* Exclude impossibly large object sizes. getObjectSize can overflow if userObjSize 85 is close to 2^wordBits, which is nonsensical in any case, so we check that this 86 did not happen. userObjSize will always need to be less than wordBits. */ 87 if (userObjSize >= wordBits || objectSize > seL4_MaxUntypedBits) { 88 userError("Untyped Retype: Invalid object size."); 89 current_syscall_error.type = seL4_RangeError; 90 current_syscall_error.rangeErrorMin = 0; 91 current_syscall_error.rangeErrorMax = seL4_MaxUntypedBits; 92 return EXCEPTION_SYSCALL_ERROR; 93 } 94 95 /* If the target object is a CNode, is it at least size 1? */ 96 if (newType == seL4_CapTableObject && userObjSize == 0) { 97 userError("Untyped Retype: Requested CapTable size too small."); 98 current_syscall_error.type = seL4_InvalidArgument; 99 current_syscall_error.invalidArgumentNumber = 1; 100 return EXCEPTION_SYSCALL_ERROR; 101 } 102 103 /* If the target object is a Untyped, is it at least size 4? */ 104 if (newType == seL4_UntypedObject && userObjSize < seL4_MinUntypedBits) { 105 userError("Untyped Retype: Requested UntypedItem size too small."); 106 current_syscall_error.type = seL4_InvalidArgument; 107 current_syscall_error.invalidArgumentNumber = 1; 108 return EXCEPTION_SYSCALL_ERROR; 109 } 110 111 /* Lookup the destination CNode (where our caps will be placed in). */ 112 if (nodeDepth == 0) { 113 nodeCap = excaps.excaprefs[0]->cap; 114 } else { 115 cap_t rootCap = excaps.excaprefs[0]->cap; 116 lu_ret = lookupTargetSlot(rootCap, nodeIndex, nodeDepth); 117 if (lu_ret.status != EXCEPTION_NONE) { 118 userError("Untyped Retype: Invalid destination address."); 119 return lu_ret.status; 120 } 121 nodeCap = lu_ret.slot->cap; 122 } 123 124 /* Is the destination actually a CNode? */ 125 if (cap_get_capType(nodeCap) != cap_cnode_cap) { 126 userError("Untyped Retype: Destination cap invalid or read-only."); 127 current_syscall_error.type = seL4_FailedLookup; 128 current_syscall_error.failedLookupWasSource = 0; 129 current_lookup_fault = lookup_fault_missing_capability_new(nodeDepth); 130 return EXCEPTION_SYSCALL_ERROR; 131 } 132 133 /* Is the region where the user wants to put the caps valid? */ 134 nodeSize = 1ul << cap_cnode_cap_get_capCNodeRadix(nodeCap); 135 if (nodeOffset > nodeSize - 1) { 136 userError("Untyped Retype: Destination node offset #%d too large.", 137 (int)nodeOffset); 138 current_syscall_error.type = seL4_RangeError; 139 current_syscall_error.rangeErrorMin = 0; 140 current_syscall_error.rangeErrorMax = nodeSize - 1; 141 return EXCEPTION_SYSCALL_ERROR; 142 } 143 if (nodeWindow < 1 || nodeWindow > CONFIG_RETYPE_FAN_OUT_LIMIT) { 144 userError("Untyped Retype: Number of requested objects (%d) too small or large.", 145 (int)nodeWindow); 146 current_syscall_error.type = seL4_RangeError; 147 current_syscall_error.rangeErrorMin = 1; 148 current_syscall_error.rangeErrorMax = CONFIG_RETYPE_FAN_OUT_LIMIT; 149 return EXCEPTION_SYSCALL_ERROR; 150 } 151 if (nodeWindow > nodeSize - nodeOffset) { 152 userError("Untyped Retype: Requested destination window overruns size of node."); 153 current_syscall_error.type = seL4_RangeError; 154 current_syscall_error.rangeErrorMin = 1; 155 current_syscall_error.rangeErrorMax = nodeSize - nodeOffset; 156 return EXCEPTION_SYSCALL_ERROR; 157 } 158 159 /* Ensure that the destination slots are all empty. */ 160 slots.cnode = CTE_PTR(cap_cnode_cap_get_capCNodePtr(nodeCap)); 161 slots.offset = nodeOffset; 162 slots.length = nodeWindow; 163 for (i = nodeOffset; i < nodeOffset + nodeWindow; i++) { 164 status = ensureEmptySlot(slots.cnode + i); 165 if (status != EXCEPTION_NONE) { 166 userError("Untyped Retype: Slot #%d in destination window non-empty.", 167 (int)i); 168 return status; 169 } 170 } 171 172 /* 173 * Determine where in the Untyped region we should start allocating new 174 * objects. 175 * 176 * If we have no children, we can start allocating from the beginning of 177 * our untyped, regardless of what the "free" value in the cap states. 178 * (This may happen if all of the objects beneath us got deleted). 179 * 180 * If we have children, we just keep allocating from the "free" value 181 * recorded in the cap. 182 */ 183 status = ensureNoChildren(slot); 184 if (status != EXCEPTION_NONE) { 185 freeIndex = cap_untyped_cap_get_capFreeIndex(cap); 186 reset = false; 187 } else { 188 freeIndex = 0; 189 reset = true; 190 } 191 freeRef = GET_FREE_REF(cap_untyped_cap_get_capPtr(cap), freeIndex); 192 193 /* 194 * Determine the maximum number of objects we can create, and return an 195 * error if we don't have enough space. 196 * 197 * We don't need to worry about alignment in this case, because if anything 198 * fits, it will also fit aligned up (by packing it on the right hand side 199 * of the untyped). 200 */ 201 untypedFreeBytes = BIT(cap_untyped_cap_get_capBlockSize(cap)) - 202 FREE_INDEX_TO_OFFSET(freeIndex); 203 204 if ((untypedFreeBytes >> objectSize) < nodeWindow) { 205 userError("Untyped Retype: Insufficient memory " 206 "(%lu * %lu bytes needed, %lu bytes available).", 207 (word_t)nodeWindow, 208 (objectSize >= wordBits ? -1 : (1ul << objectSize)), 209 (word_t)(untypedFreeBytes)); 210 current_syscall_error.type = seL4_NotEnoughMemory; 211 current_syscall_error.memoryLeft = untypedFreeBytes; 212 return EXCEPTION_SYSCALL_ERROR; 213 } 214 215 deviceMemory = cap_untyped_cap_get_capIsDevice(cap); 216 if ((deviceMemory && !Arch_isFrameType(newType)) 217 && newType != seL4_UntypedObject) { 218 userError("Untyped Retype: Creating kernel objects with device untyped"); 219 current_syscall_error.type = seL4_InvalidArgument; 220 current_syscall_error.invalidArgumentNumber = 1; 221 return EXCEPTION_SYSCALL_ERROR; 222 } 223 224 /* Align up the free region so that it is aligned to the target object's 225 * size. */ 226 alignedFreeRef = alignUp(freeRef, objectSize); 227 228 /* Perform the retype. */ 229 setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); 230 return invokeUntyped_Retype(slot, reset, 231 (void*)alignedFreeRef, newType, userObjSize, 232 slots, deviceMemory); 233} 234 235static exception_t 236resetUntypedCap(cte_t *srcSlot) 237{ 238 cap_t prev_cap = srcSlot->cap; 239 word_t block_size = cap_untyped_cap_get_capBlockSize(prev_cap); 240 void *regionBase = WORD_PTR(cap_untyped_cap_get_capPtr(prev_cap)); 241 int chunk = CONFIG_RESET_CHUNK_BITS; 242 word_t offset = FREE_INDEX_TO_OFFSET(cap_untyped_cap_get_capFreeIndex(prev_cap)); 243 exception_t status; 244 bool_t deviceMemory = cap_untyped_cap_get_capIsDevice(prev_cap); 245 246 if (offset == 0) { 247 return EXCEPTION_NONE; 248 } 249 250 /** AUXUPD: "(True, typ_region_bytes (ptr_val \<acute>regionBase) 251 (unat \<acute>block_size))" */ 252 /** GHOSTUPD: "(True, gs_clear_region (ptr_val \<acute>regionBase) 253 (unat \<acute>block_size))" */ 254 255 if (deviceMemory || block_size < chunk) { 256 if (! deviceMemory) { 257 clearMemory(regionBase, block_size); 258 } 259 srcSlot->cap = cap_untyped_cap_set_capFreeIndex(prev_cap, 0); 260 } else { 261 for (offset = ROUND_DOWN(offset - 1, chunk); 262 offset != - BIT (chunk); offset -= BIT (chunk)) { 263 clearMemory(GET_OFFSET_FREE_PTR(regionBase, offset), chunk); 264 srcSlot->cap = cap_untyped_cap_set_capFreeIndex(prev_cap, OFFSET_TO_FREE_INDEX(offset)); 265 status = preemptionPoint(); 266 if (status != EXCEPTION_NONE) { 267 return status; 268 } 269 } 270 } 271 return EXCEPTION_NONE; 272} 273 274exception_t 275invokeUntyped_Retype(cte_t *srcSlot, 276 bool_t reset, void* retypeBase, 277 object_t newType, word_t userSize, 278 slot_range_t destSlots, bool_t deviceMemory) 279{ 280 word_t freeRef; 281 word_t totalObjectSize; 282 void *regionBase = WORD_PTR(cap_untyped_cap_get_capPtr(srcSlot->cap)); 283 exception_t status; 284 285 freeRef = GET_FREE_REF(regionBase, cap_untyped_cap_get_capFreeIndex(srcSlot->cap)); 286 287 if (reset) { 288 status = resetUntypedCap(srcSlot); 289 if (status != EXCEPTION_NONE) { 290 return status; 291 } 292 } 293 294 /* Update the amount of free space left in this untyped cap. */ 295 totalObjectSize = destSlots.length << getObjectSize(newType, userSize); 296 freeRef = (word_t)retypeBase + totalObjectSize; 297 srcSlot->cap = cap_untyped_cap_set_capFreeIndex(srcSlot->cap, 298 GET_FREE_INDEX(regionBase, freeRef)); 299 300 /* Create new objects and caps. */ 301 createNewObjects(newType, srcSlot, destSlots, retypeBase, userSize, 302 deviceMemory); 303 304 return EXCEPTION_NONE; 305} 306