| /* |
| * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) |
| * |
| * SPDX-License-Identifier: BSD-2-Clause |
| */ |
| |
| #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 */ |
| } |