/* * COPYRIGHT (c) 2019 Chris Johns * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.org/license/LICENSE. */ /** * @file * * @ingroup rtems_rtld * * @brief RTEMS Run-Time Link Editor Bit Allocator * * A configurable allocator for small peices of memory where embedding * control blocks into the memory are not viable. The amount of memory * should be small and the minimum allocator a 32bit work or higher. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include "rtl-bit-alloc.h" #include "rtl-error.h" #include #define BITS_PER_WORD (sizeof (uint32_t) * 8) static size_t bit_blocks (rtems_rtl_bit_alloc* balloc, size_t size) { if (size == 0) return 0; return ((size - 1) / balloc->block_size) + 1; } static size_t bit_word (size_t bit) { return bit / BITS_PER_WORD; } static size_t bit_offset (size_t bit) { return bit % (sizeof (uint32_t) * 8); } static uint32_t bit_mask (size_t bit) { return 1 << bit_offset (bit); } static void bit_set (rtems_rtl_bit_alloc* balloc, size_t start, size_t bits) { size_t b; for (b = start; b < (start + bits); ++b) balloc->bits[bit_word (b)] |= bit_mask (b); } static void bit_clear (rtems_rtl_bit_alloc* balloc, size_t start, size_t bits) { size_t b; for (b = start; b < (start + bits); ++b) balloc->bits[bit_word (b)] &= ~bit_mask (b); } static ssize_t bit_find_clear (rtems_rtl_bit_alloc* balloc, size_t blocks) { size_t base = 0; size_t clear = 0; size_t b; for (b = 0; b < balloc->blocks; ++b) { if (balloc->bits[b] != 0xffffffff) { uint32_t word = balloc->bits[b]; size_t o; for (o = 0; o < BITS_PER_WORD; ++o, word >>= 1) { if ((word & 1) == 0) { if (clear == 0) base = (b * BITS_PER_WORD) + o; ++clear; if (clear == blocks) return base; } else { clear = 0; base = 0; } } } else { clear = 0; base = 0; } } return -1; } rtems_rtl_bit_alloc* rtems_rtl_bit_alloc_open (void* base, size_t size, size_t block_size, size_t used) { rtems_rtl_bit_alloc* balloc; const size_t base_size = base == NULL ? size : 0;; const size_t blocks = (size / block_size) / BITS_PER_WORD; const size_t bit_bytes = blocks * sizeof(uint32_t); if (rtems_rtl_trace (RTEMS_RTL_TRACE_BIT_ALLOC)) printf ("rtl: balloc: open: base=%p size=%zu" \ " block-size=%zu blocks=%zu used=%zu\n", base, size, block_size, blocks, used); if (size == 0) { rtems_rtl_set_error (ENOMEM, "bit allocator size is 0"); return false; } if (used > size) { rtems_rtl_set_error (ENOMEM, "bad bit allocator used value"); return false; } balloc = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, sizeof (rtems_rtl_bit_alloc) + bit_bytes + base_size, true); if (balloc == NULL) { rtems_rtl_set_error (ENOMEM, "not bit allocator memory"); return NULL; } balloc->base = base == NULL ? ((void*) balloc) + sizeof (rtems_rtl_bit_alloc) + bit_bytes: base; balloc->size = size; balloc->bits = ((void*) balloc) + sizeof (rtems_rtl_bit_alloc); balloc->block_size = block_size; balloc->blocks = blocks; bit_set (balloc, 0, bit_blocks (balloc, used)); return balloc; } void rtems_rtl_bit_alloc_close (rtems_rtl_bit_alloc* balloc) { if (rtems_rtl_trace (RTEMS_RTL_TRACE_BIT_ALLOC)) printf ("rtl: balloc: close: base=%p size=%zu\n", balloc->base, balloc->size); rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, balloc); } void* rtems_rtl_bit_alloc_balloc (rtems_rtl_bit_alloc* balloc, size_t size) { size_t blocks = bit_blocks (balloc, size); ssize_t block = bit_find_clear (balloc, blocks); if (block < 0) return NULL; if (rtems_rtl_trace (RTEMS_RTL_TRACE_BIT_ALLOC)) printf ("rtl: balloc: balloc: size=%zu blocks=%zu block=%zi\n", size, blocks, block); bit_set (balloc, block, blocks); return (void*) (balloc->base + (block * balloc->block_size)); } void rtems_rtl_bit_alloc_bfree (rtems_rtl_bit_alloc* balloc, void* addr, size_t size) { const uint8_t* a = (const uint8_t*) addr; if (addr != NULL && a >= balloc->base && a < balloc->base + balloc->size) { size_t block = bit_blocks (balloc, a - balloc->base); size_t blocks = bit_blocks (balloc, size); bit_clear (balloc, block, blocks); } }