1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13#include <autoconf.h> 14#include <allocman/utspace/twinkle.h> 15#include <allocman/allocman.h> 16#include <allocman/util.h> 17#include <sel4/sel4.h> 18#include <vka/object.h> 19#include <string.h> 20 21static inline size_t _round_up(size_t v, size_t bits) 22{ 23 size_t mask = MASK(bits); 24 if ((v & mask) != 0) { 25 v = (v & ~mask) + BIT(bits); 26 } 27 return v; 28} 29 30void utspace_twinkle_create(utspace_twinkle_t *twinkle) 31{ 32 twinkle->num_uts = 0; 33 twinkle->uts = NULL; 34} 35 36int _utspace_twinkle_add_uts(allocman_t *alloc, void *_twinkle, size_t num, const cspacepath_t *uts, size_t *size_bits, 37 uintptr_t *paddr, int utType) 38{ 39 utspace_twinkle_t *twinkle = (utspace_twinkle_t *) _twinkle; 40 struct utspace_twinkle_ut *new_uts; 41 int error; 42 size_t i; 43 if (utType != ALLOCMAN_UT_KERNEL) { 44 ZF_LOGE("Twinkle does not support device untypeds"); 45 return -1; 46 } 47 new_uts = allocman_mspace_alloc(alloc, sizeof(struct utspace_twinkle_ut) * (num + twinkle->num_uts), &error); 48 if (error) { 49 return error; 50 } 51 if (twinkle->uts) { 52 memcpy(new_uts, twinkle->uts, sizeof(struct utspace_twinkle_ut) * twinkle->num_uts); 53 allocman_mspace_free(alloc, twinkle->uts, sizeof(struct utspace_twinkle_ut) * twinkle->num_uts); 54 } 55 for (i = 0; i < num; i++, twinkle->num_uts++) { 56 new_uts[twinkle->num_uts] = (struct utspace_twinkle_ut) { 57 uts[i], 0, size_bits[i] 58 }; 59 } 60 twinkle->uts = new_uts; 61 return 0; 62} 63 64seL4_Word _utspace_twinkle_alloc(allocman_t *alloc, void *_twinkle, size_t size_bits, seL4_Word type, 65 const cspacepath_t *slot, uintptr_t paddr, bool canBeDev, int *error) 66{ 67 utspace_twinkle_t *twinkle = (utspace_twinkle_t *)_twinkle; 68 size_t sel4_size_bits; 69 int sel4_error; 70 size_t i, j; 71 if (paddr != ALLOCMAN_NO_PADDR) { 72 ZF_LOGE("Twinkle does not support allocating explicit physical addresses"); 73 return -1; 74 } 75 /* get size of untyped call */ 76 sel4_size_bits = get_sel4_object_size(type, size_bits); 77 if (size_bits != vka_get_object_size(type, sel4_size_bits) || size_bits == 0) { 78 SET_ERROR(error, 1); 79 return 0; 80 } 81 /* Search for the first thing that will support us */ 82 for (i = 0; i < twinkle->num_uts; i++) { 83 if (_round_up(twinkle->uts[i].offset, size_bits) + BIT(size_bits) <= BIT(twinkle->uts[i].size_bits)) { 84 break; 85 } 86 } 87 if (i == twinkle->num_uts) { 88 SET_ERROR(error, 1); 89 return 0; 90 } 91 /* Check all untypeds of this size, and pick the one that will waste the least space */ 92 for (j = i; j < twinkle->num_uts && twinkle->uts[i].size_bits == twinkle->uts[j].size_bits; j++) { 93 if ((_round_up(twinkle->uts[j].offset, size_bits) + BIT(size_bits) <= BIT(twinkle->uts[j].size_bits)) && 94 (_round_up(twinkle->uts[j].offset, size_bits) - twinkle->uts[j].offset < 95 _round_up(twinkle->uts[i].offset, size_bits) - twinkle->uts[i].offset)) { 96 i = j; 97 } 98 } 99 /* if using inc retype then our offset calculation is effectively emulating the kernels calculations. This 100 * means we track the free space of the untyped correctly, and since we are not going to try and free then 101 * allocate again, this allocator can be used with either allocation scheme */ 102 sel4_error = seL4_Untyped_Retype(twinkle->uts[i].path.capPtr, type, sel4_size_bits, slot->root, slot->dest, 103 slot->destDepth, slot->offset, 1); 104 if (sel4_error != seL4_NoError) { 105 /* Well this shouldn't happen */ 106 SET_ERROR(error, 1); 107 return 0; 108 } 109 110 /* Update allocation information */ 111 twinkle->uts[i].offset = _round_up(twinkle->uts[i].offset, size_bits) + BIT(size_bits); 112 113 /* We do not support free so we return an empty cookie */ 114 SET_ERROR(error, 0); 115 return 0; 116} 117 118void _utspace_twinkle_free(allocman_t *alloc, void *_twinkle, seL4_Word cookie, size_t size_bits) 119{ 120 /* Do nothing */ 121} 122