| /* | |
| * Copyright 2017, Data61 | |
| * Commonwealth Scientific and Industrial Research Organisation (CSIRO) | |
| * ABN 41 687 119 230. | |
| * | |
| * This software may be distributed and modified according to the terms of | |
| * the BSD 2-Clause license. Note that NO WARRANTY is provided. | |
| * See "LICENSE_BSD2.txt" for details. | |
| * | |
| * @TAG(DATA61_BSD) | |
| */ | |
| #include <autoconf.h> | |
| #include <allocman/utspace/twinkle.h> | |
| #include <allocman/allocman.h> | |
| #include <allocman/util.h> | |
| #include <sel4/sel4.h> | |
| #include <vka/object.h> | |
| #include <string.h> | |
| static inline size_t _round_up(size_t v, size_t bits) | |
| { | |
| size_t mask = MASK(bits); | |
| if ((v & mask) != 0) { | |
| v = (v & ~mask) + BIT(bits); | |
| } | |
| return v; | |
| } | |
| void utspace_twinkle_create(utspace_twinkle_t *twinkle) | |
| { | |
| twinkle->num_uts = 0; | |
| twinkle->uts = NULL; | |
| } | |
| int _utspace_twinkle_add_uts(allocman_t *alloc, void *_twinkle, size_t num, const cspacepath_t *uts, size_t *size_bits, | |
| uintptr_t *paddr, int utType) | |
| { | |
| utspace_twinkle_t *twinkle = (utspace_twinkle_t *) _twinkle; | |
| struct utspace_twinkle_ut *new_uts; | |
| int error; | |
| size_t i; | |
| if (utType != ALLOCMAN_UT_KERNEL) { | |
| ZF_LOGE("Twinkle does not support device untypeds"); | |
| return -1; | |
| } | |
| new_uts = allocman_mspace_alloc(alloc, sizeof(struct utspace_twinkle_ut) * (num + twinkle->num_uts), &error); | |
| if (error) { | |
| return error; | |
| } | |
| if (twinkle->uts) { | |
| memcpy(new_uts, twinkle->uts, sizeof(struct utspace_twinkle_ut) * twinkle->num_uts); | |
| allocman_mspace_free(alloc, twinkle->uts, sizeof(struct utspace_twinkle_ut) * twinkle->num_uts); | |
| } | |
| for (i = 0; i < num; i++, twinkle->num_uts++) { | |
| new_uts[twinkle->num_uts] = (struct utspace_twinkle_ut) { | |
| uts[i], 0, size_bits[i] | |
| }; | |
| } | |
| twinkle->uts = new_uts; | |
| return 0; | |
| } | |
| seL4_Word _utspace_twinkle_alloc(allocman_t *alloc, void *_twinkle, size_t size_bits, seL4_Word type, | |
| const cspacepath_t *slot, uintptr_t paddr, bool canBeDev, int *error) | |
| { | |
| utspace_twinkle_t *twinkle = (utspace_twinkle_t *)_twinkle; | |
| size_t sel4_size_bits; | |
| int sel4_error; | |
| size_t i, j; | |
| if (paddr != ALLOCMAN_NO_PADDR) { | |
| ZF_LOGE("Twinkle does not support allocating explicit physical addresses"); | |
| return -1; | |
| } | |
| /* get size of untyped call */ | |
| sel4_size_bits = get_sel4_object_size(type, size_bits); | |
| if (size_bits != vka_get_object_size(type, sel4_size_bits) || size_bits == 0) { | |
| SET_ERROR(error, 1); | |
| return 0; | |
| } | |
| /* Search for the first thing that will support us */ | |
| for (i = 0; i < twinkle->num_uts; i++) { | |
| if (_round_up(twinkle->uts[i].offset, size_bits) + BIT(size_bits) <= BIT(twinkle->uts[i].size_bits)) { | |
| break; | |
| } | |
| } | |
| if (i == twinkle->num_uts) { | |
| SET_ERROR(error, 1); | |
| return 0; | |
| } | |
| /* Check all untypeds of this size, and pick the one that will waste the least space */ | |
| for (j = i; j < twinkle->num_uts && twinkle->uts[i].size_bits == twinkle->uts[j].size_bits; j++) { | |
| if ((_round_up(twinkle->uts[j].offset, size_bits) + BIT(size_bits) <= BIT(twinkle->uts[j].size_bits)) && | |
| (_round_up(twinkle->uts[j].offset, size_bits) - twinkle->uts[j].offset < | |
| _round_up(twinkle->uts[i].offset, size_bits) - twinkle->uts[i].offset)) { | |
| i = j; | |
| } | |
| } | |
| /* if using inc retype then our offset calculation is effectively emulating the kernels calculations. This | |
| * means we track the free space of the untyped correctly, and since we are not going to try and free then | |
| * allocate again, this allocator can be used with either allocation scheme */ | |
| sel4_error = seL4_Untyped_Retype(twinkle->uts[i].path.capPtr, type, sel4_size_bits, slot->root, slot->dest, | |
| slot->destDepth, slot->offset, 1); | |
| if (sel4_error != seL4_NoError) { | |
| /* Well this shouldn't happen */ | |
| SET_ERROR(error, 1); | |
| return 0; | |
| } | |
| /* Update allocation information */ | |
| twinkle->uts[i].offset = _round_up(twinkle->uts[i].offset, size_bits) + BIT(size_bits); | |
| /* We do not support free so we return an empty cookie */ | |
| SET_ERROR(error, 0); | |
| return 0; | |
| } | |
| void _utspace_twinkle_free(allocman_t *alloc, void *_twinkle, seL4_Word cookie, size_t size_bits) | |
| { | |
| /* Do nothing */ | |
| } |