diff --git a/mm/mm_gran/CMakeLists.txt b/mm/mm_gran/CMakeLists.txt index 50e8dbbd8c..4de3860fda 100644 --- a/mm/mm_gran/CMakeLists.txt +++ b/mm/mm_gran/CMakeLists.txt @@ -22,15 +22,9 @@ if(CONFIG_GRAN) - set(SRCS - mm_graninit.c - mm_granrelease.c - mm_granreserve.c - mm_granalloc.c - mm_granmark.c - mm_granfree.c - mm_graninfo.c - mm_grancritical.c) + set(SRCS mm_graninit.c mm_granrelease.c mm_graninfo.c mm_grancritical.c) + list(APPEND SRCS mm_grantable.c mm_granfree.c mm_granalloc.c) + list(APPEND SRCS mm_granreserve.c) # A page allocator based on the granule allocator diff --git a/mm/mm_gran/Make.defs b/mm/mm_gran/Make.defs index ef7f12ba67..7ec0c63153 100644 --- a/mm/mm_gran/Make.defs +++ b/mm/mm_gran/Make.defs @@ -21,8 +21,9 @@ # An optional granule allocator ifeq ($(CONFIG_GRAN),y) -CSRCS += mm_graninit.c mm_granrelease.c mm_granreserve.c mm_granalloc.c -CSRCS += mm_granmark.c mm_granfree.c mm_graninfo.c mm_grancritical.c + +CSRCS += mm_graninit.c mm_granrelease.c mm_graninfo.c mm_grancritical.c +CSRCS += mm_grantable.c mm_granfree.c mm_granalloc.c mm_granreserve.c # A page allocator based on the granule allocator diff --git a/mm/mm_gran/mm_gran.h b/mm/mm_gran/mm_gran.h index 5840d9682f..9c64e987b1 100644 --- a/mm/mm_gran/mm_gran.h +++ b/mm/mm_gran/mm_gran.h @@ -47,7 +47,7 @@ /* Debug */ -#ifdef CONFIG_DEBUG_GRAM +#ifdef CONFIG_DEBUG_GRAN # define granerr _err # define granwarn _warn # define graninfo _info diff --git a/mm/mm_gran/mm_granalloc.c b/mm/mm_gran/mm_granalloc.c index 88264311a2..7727e2120a 100644 --- a/mm/mm_gran/mm_granalloc.c +++ b/mm/mm_gran/mm_granalloc.c @@ -25,10 +25,12 @@ #include #include +#include #include #include "mm_gran/mm_gran.h" +#include "mm_gran/mm_grantable.h" #ifdef CONFIG_GRAN @@ -36,215 +38,45 @@ * Public Functions ****************************************************************************/ -/**************************************************************************** - * Name: gran_alloc - * - * Description: - * Allocate memory from the granule heap. - * - * NOTE: The current implementation also restricts the maximum allocation - * size to 32 granules. That restriction could be eliminated with some - * additional coding effort. - * - * Input Parameters: - * handle - The handle previously returned by gran_initialize - * size - The size of the memory region to allocate. - * - * Returned Value: - * On success, a non-NULL pointer to the allocated memory is returned; - * NULL is returned on failure. - * - ****************************************************************************/ - FAR void *gran_alloc(GRAN_HANDLE handle, size_t size) { - FAR struct gran_s *priv = (FAR struct gran_s *)handle; - unsigned int ngranules; - size_t tmpmask; - uintptr_t alloc; - uint32_t curr; - uint32_t next; - uint32_t mask; - int granidx; - int gatidx; - int bitidx; - int shift; - int ret; + FAR gran_t *gran = (FAR gran_t *)handle; + size_t ngran; + int posi; + int ret; + uintptr_t retp; - DEBUGASSERT(priv != NULL && size <= 32 * (1 << priv->log2gran)); - - if (priv != NULL && size > 0) + DEBUGASSERT(gran); + ngran = NGRANULE(gran, size); + if (!ngran || ngran > gran->ngranules) { - /* Get exclusive access to the GAT */ - - ret = gran_enter_critical(priv); - if (ret < 0) - { - return NULL; - } - - /* How many contiguous granules we we need to find? */ - - tmpmask = (1 << priv->log2gran) - 1; - ngranules = (size + tmpmask) >> priv->log2gran; - - /* Then create mask for that number of granules */ - - DEBUGASSERT(ngranules <= 32); - mask = 0xffffffff >> (32 - ngranules); - - /* Now search the granule allocation table for that number - * of contiguous - */ - - for (granidx = 0; granidx < priv->ngranules; granidx += 32) - { - /* Get the GAT index associated with the granule table entry */ - - gatidx = granidx >> 5; - curr = priv->gat[gatidx]; - - /* Handle the case where there are no free granules in the entry */ - - if (curr == 0xffffffff) - { - continue; - } - - /* Get the next entry from the GAT to support a 64 bit shift */ - - if (granidx + 32 < priv->ngranules) - { - next = priv->gat[gatidx + 1]; - } - - /* Use all ones when are at the last entry in the GAT (meaning - * nothing can be allocated. - */ - - else - { - next = 0xffffffff; - } - - /* Search through the allocations in the 'curr' GAT entry - * to see if we can satisfy the allocation starting in that - * entry. - * - * This loop continues until either all of the bits have been - * examined (bitidx >= 32), or until there are insufficient - * granules left to satisfy the allocation. - */ - - alloc = priv->heapstart + (granidx << priv->log2gran); - - for (bitidx = 0; - bitidx < 32 && - (granidx + bitidx + ngranules) <= priv->ngranules; - ) - { - /* Break out if there are no further free bits in 'curr'. - * All of the zero bits might have gotten shifted out. - */ - - if (curr == 0xffffffff) - { - break; - } - - /* Check for the first zero bit in the lower or upper 16-bits. - * From the test above, we know that at least one of the 32- - * bits in 'curr' is zero. - */ - - else if ((curr & 0x0000ffff) == 0x0000ffff) - { - /* Not in the lower 16 bits. The first free bit must be - * in the upper 16 bits. - */ - - shift = 16; - } - - /* We know that the first free bit is now within the lower 16 - * bits of 'curr'. Is it in the upper or lower byte? - */ - - else if ((curr & 0x0000ff) == 0x000000ff) - { - /* Not in the lower 8 bits. The first free bit must be in - * the upper 8 bits. - */ - - shift = 8; - } - - /* We know that the first free bit is now within the lower 4 - * bits of 'curr'. Is it in the upper or lower nibble? - */ - - else if ((curr & 0x00000f) == 0x0000000f) - { - /* Not in the lower 4 bits. The first free bit must be in - * the upper 4 bits. - */ - - shift = 4; - } - - /* We know that the first free bit is now within the lower 4 - * bits of 'curr'. Is it in the upper or lower pair? - */ - - else if ((curr & 0x000003) == 0x00000003) - { - /* Not in the lower 2 bits. The first free bit must be in - * the upper 2 bits. - */ - - shift = 2; - } - - /* We know that the first free bit is now within the lower 4 - * bits of 'curr'. Check if we have the allocation at this - * bit position. - */ - - else if ((curr & mask) == 0) - { - /* Yes.. mark these granules allocated */ - - gran_mark_allocated(priv, alloc, ngranules); - - /* And return the allocation address */ - - gran_leave_critical(priv); - return (FAR void *)alloc; - } - - /* The free allocation does not start at this position */ - - else - { - shift = 1; - } - - /* Set up for the next time through the loop. Perform a 64 - * bit shift to move to the next gran position and increment - * to the next candidate allocation address. - */ - - alloc += (shift << priv->log2gran); - curr = (curr >> shift) | (next << (32 - shift)); - next >>= shift; - bitidx += shift; - } - } - - gran_leave_critical(priv); + return NULL; } - return NULL; + ret = gran_enter_critical(gran); + if (ret < 0) + { + return NULL; + } + + posi = gran_search(gran, ngran); + if (posi >= 0) + { + gran_set(gran, posi, ngran); + } + + gran_leave_critical(gran); + if (posi < 0) + { + return NULL; + } + + retp = gran->heapstart + (posi << gran->log2gran); + graninfo("heap=%"PRIxPTR" posi=%d retp=%"PRIxPTR" size=%zu n=%zu\n", + gran->heapstart, posi, retp, size, ngran); + DEBUGASSERT(retp >= gran->heapstart); + DEBUGASSERT(retp < gran->heapstart + GRANBYTE(gran)); + return (FAR void *)retp; } #endif /* CONFIG_GRAN */ diff --git a/mm/mm_gran/mm_granfree.c b/mm/mm_gran/mm_granfree.c index 5f2d4b2f4e..e2a667b5d1 100644 --- a/mm/mm_gran/mm_granfree.c +++ b/mm/mm_gran/mm_granfree.c @@ -25,11 +25,12 @@ #include #include -#include +#include #include #include "mm_gran/mm_gran.h" +#include "mm_gran/mm_grantable.h" #ifdef CONFIG_GRAN @@ -37,100 +38,35 @@ * Public Functions ****************************************************************************/ -/**************************************************************************** - * Name: gran_free - * - * Description: - * Return memory to the granule heap. - * - * Input Parameters: - * handle - The handle previously returned by gran_initialize - * memory - A pointer to memory previoiusly allocated by gran_alloc. - * - * Returned Value: - * None - * - ****************************************************************************/ - void gran_free(GRAN_HANDLE handle, FAR void *memory, size_t size) { - FAR struct gran_s *priv = (FAR struct gran_s *)handle; - unsigned int granno; - unsigned int gatidx; - unsigned int gatbit; - unsigned int granmask; - unsigned int ngranules; - unsigned int avail; - uint32_t gatmask; - int ret; + FAR gran_t *gran = (FAR gran_t *)handle; + uint ngran; + size_t posi; + int ret; - DEBUGASSERT(priv != NULL && memory && size <= 32 * (1 << priv->log2gran)); + DEBUGASSERT(gran && memory && size); + DEBUGASSERT(GRAN_PRODUCT(gran, memory)); + DEBUGASSERT(GRAN_INRANGE(gran, (((uintptr_t)memory) + size - 1))); - /* Get exclusive access to the GAT */ + posi = MEM2GRAN(gran, memory); + ngran = NGRANULE(gran, size); + + graninfo(" heap=%"PRIxPTR" posi=%zu addr=%zx size=%zu n=%d\n", + gran->heapstart, posi, (size_t)memory, size, ngran); do { - ret = gran_enter_critical(priv); - - /* The only error Should happen on task cancellation. We must - * try again in this case to avoid stranding the granule memory. - */ - + ret = gran_enter_critical(gran); DEBUGASSERT(ret == OK || ret == -ECANCELED); } - while (ret < 0); + while (ret < 0); /* Retry upon task cancellation */ - /* Determine the granule number of the first granule in the allocation */ + /* check double free */ - granno = ((uintptr_t)memory - priv->heapstart) >> priv->log2gran; - - /* Determine the GAT table index and bit number associated with the - * allocation. - */ - - gatidx = granno >> 5; - gatbit = granno & 31; - - /* Determine the number of granules in the allocation */ - - granmask = (1 << priv->log2gran) - 1; - ngranules = (size + granmask) >> priv->log2gran; - - /* Clear bits in the GAT entry or entries */ - - avail = 32 - gatbit; - if (ngranules > avail) - { - /* Clear bits in the first GAT entry */ - - gatmask = (0xffffffff << gatbit); - DEBUGASSERT((priv->gat[gatidx] & gatmask) == gatmask); - - priv->gat[gatidx] &= ~gatmask; - ngranules -= avail; - - /* Clear bits in the second GAT entry */ - - gatmask = 0xffffffff >> (32 - ngranules); - DEBUGASSERT((priv->gat[gatidx + 1] & gatmask) == gatmask); - - priv->gat[gatidx + 1] &= ~gatmask; - } - - /* Handle the case where where all of the granules came from one entry */ - - else - { - /* Clear bits in a single GAT entry */ - - gatmask = 0xffffffff >> (32 - ngranules); - gatmask <<= gatbit; - DEBUGASSERT((priv->gat[gatidx] & gatmask) == gatmask); - - priv->gat[gatidx] &= ~gatmask; - } - - gran_leave_critical(priv); + DEBUGASSERT(gran_match(gran, posi, ngran, 1, NULL)); + gran_clear(gran, posi, ngran); + gran_leave_critical(gran); } #endif /* CONFIG_GRAN */ diff --git a/mm/mm_gran/mm_granmark.c b/mm/mm_gran/mm_granmark.c deleted file mode 100644 index 634778b414..0000000000 --- a/mm/mm_gran/mm_granmark.c +++ /dev/null @@ -1,121 +0,0 @@ -/**************************************************************************** - * mm/mm_gran/mm_granmark.c - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include - -#include - -#include "mm_gran/mm_gran.h" - -#ifdef CONFIG_GRAN - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: gran_mark_allocated - * - * Description: - * Mark a range of granules as allocated. - * - * Input Parameters: - * priv - The granule heap state structure. - * alloc - The address of the allocation. - * ngranules - The number of granules allocated - * - * Returned Value: - * On success, a non-NULL pointer to the allocated memory is returned; - * NULL is returned on failure. - * - ****************************************************************************/ - -FAR void *gran_mark_allocated(FAR struct gran_s *priv, uintptr_t alloc, - unsigned int ngranules) -{ - unsigned int granno; - unsigned int gatidx; - unsigned int gatbit; - unsigned int avail; - uint32_t gatmask; - - /* Determine the granule number of the allocation */ - - granno = (alloc - priv->heapstart) >> priv->log2gran; - - /* Determine the GAT table index associated with the allocation */ - - gatidx = granno >> 5; - gatbit = granno & 31; - - /* Mark bits in the GAT entry or entries */ - - avail = 32 - gatbit; - if (ngranules > avail) - { - uint32_t gatmask2; - - gatmask = 0xffffffff << gatbit; - ngranules -= avail; - gatmask2 = 0xffffffff >> (32 - ngranules); - - /* Check that the area is free, from both mask words */ - - if (((priv->gat[gatidx] & gatmask) != 0) || - ((priv->gat[gatidx + 1] & gatmask2) != 0)) - { - return NULL; - } - - /* Mark bits in the first and second GAT entry */ - - priv->gat[gatidx] |= gatmask; - priv->gat[gatidx + 1] |= gatmask2; - } - - /* Handle the case where where all of the granules come from one entry */ - - else - { - gatmask = 0xffffffff >> (32 - ngranules); - gatmask <<= gatbit; - - /* Check that the area is free */ - - if ((priv->gat[gatidx] & gatmask) != 0) - { - return NULL; - } - - /* Mark bits in a single GAT entry */ - - priv->gat[gatidx] |= gatmask; - } - - return (FAR void *)alloc; -} - -#endif /* CONFIG_GRAN */ diff --git a/mm/mm_gran/mm_granreserve.c b/mm/mm_gran/mm_granreserve.c index 4930b02d08..eb6aabfb79 100644 --- a/mm/mm_gran/mm_granreserve.c +++ b/mm/mm_gran/mm_granreserve.c @@ -25,10 +25,12 @@ #include #include +#include #include #include "mm_gran/mm_gran.h" +#include "mm_gran/mm_grantable.h" #ifdef CONFIG_GRAN @@ -36,67 +38,58 @@ * Public Functions ****************************************************************************/ -/**************************************************************************** - * Name: gran_reserve - * - * Description: - * Reserve memory in the granule heap. This will reserve the granules - * that contain the start and end addresses plus all of the granules - * in between. This should be done early in the initialization sequence - * before any other allocations are made. - * - * Reserved memory can never be allocated (it can be freed however which - * essentially unreserves the memory). - * - * Input Parameters: - * handle - The handle previously returned by gran_initialize - * start - The address of the beginning of the region to be reserved. - * size - The size of the region to be reserved - * - * Returned Value: - * On success, a non-NULL pointer to the allocated memory is returned; - * NULL is returned on failure. - * - ****************************************************************************/ - FAR void *gran_reserve(GRAN_HANDLE handle, uintptr_t start, size_t size) { - FAR struct gran_s *priv = (FAR struct gran_s *)handle; - FAR void *ret = NULL; + FAR gran_t *gran = (FAR gran_t *)handle; + uintptr_t end; + size_t ngran; + size_t posi; + bool avail; - DEBUGASSERT(priv != NULL); - - if (size > 0) + DEBUGASSERT(gran); + if (!size || size > GRANBYTE(gran)) { - uintptr_t mask = (1 << priv->log2gran) - 1; - uintptr_t end = start + size - 1; - unsigned int ngranules; - - /* Get the aligned (down) start address and the aligned (up) end - * address - */ - - start &= ~mask; - end = (end + mask) & ~mask; - - /* Calculate the new size in granules */ - - ngranules = ((end - start) >> priv->log2gran) + 1; - - /* Must lock the granule allocator */ - - if (gran_enter_critical(priv) < 0) - { - return NULL; - } - - /* And reserve the granules */ - - ret = gran_mark_allocated(priv, start, ngranules); - gran_leave_critical(priv); + return NULL; } - return ret; + /* align down/up start/ending addresses */ + + end = END_RSRV(gran, start, size); + if (!GRAN_INRANGE(gran, end)) + { + return NULL; + } + + start = MEM_RSRV(gran, start); + if (!GRAN_INRANGE(gran, start)) + { + return NULL; + } + + /* convert unit to granule */ + + posi = MEM2GRAN(gran, start); + ngran = ((end - start) >> gran->log2gran) + 1; + + /* lock the granule allocator */ + + if (gran_enter_critical(gran) < 0) + { + return NULL; + } + + avail = gran_match(gran, posi, ngran, 0, NULL); + if (avail) + { + gran_set(gran, posi, ngran); + } + + gran_leave_critical(gran); + + graninfo("%s posi=%zu retp=%zx size=%zu n=%zu\n", + avail ? " done" : " error", posi, (size_t)start, size, ngran); + + return avail ? (FAR void *)start : NULL; } #endif /* CONFIG_GRAN */ diff --git a/mm/mm_gran/mm_grantable.c b/mm/mm_gran/mm_grantable.c new file mode 100644 index 0000000000..93c027db4c --- /dev/null +++ b/mm/mm_gran/mm_grantable.c @@ -0,0 +1,291 @@ +/**************************************************************************** + * mm/mm_gran/mm_grantable.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include + +#include "mm_gran/mm_gran.h" +#include "mm_gran/mm_grantable.h" + +#ifdef CONFIG_GRAN + +/**************************************************************************** + * Preprocessors + ****************************************************************************/ + +#define GATCFULL 0xffffffffu /* a full GAT cell */ +#define DEBRUJIN_NUM 0x077CB531UL /* the de Bruijn Sequence */ + +/**************************************************************************** + * Private data + ****************************************************************************/ + +#if !defined(CONFIG_HAVE_BUILTIN_CLZ) || !defined(CONFIG_HAVE_BUILTIN_CTZ) + +/* The de Bruijn lookup table to get n from BIT(n). */ + +static const uint8_t DEBRUJIN_LUT[32] = +{ + 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* return BIT(MSB(n)) */ + +uint32_t msb_mask(uint32_t n) +{ + /* see https://www.geeksforgeeks.org/find-significant-set-bit-number */ + + DEBUGASSERT(n); + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + + n = ((n + 1) >> 1) | (n & (1 << ((sizeof(n) << 3)-1))); + return n; +} + +/* return BIT(LSB(n)) */ + +uint32_t lsb_mask(uint32_t n) +{ + DEBUGASSERT(n); + return (-n & n) & GATCFULL; +} + +/* set or clear a GAT cell with given bit mask */ + +static void cell_set(gran_t *gran, uint32_t cell, uint32_t mask, bool val) +{ + if (val) + { + gran->gat[cell] |= mask; + } + else + { + gran->gat[cell] &= ~mask; + } +} + +/* set or clear a range of GAT bits */ + +static void gran_set_(gran_t *gran, gatr_t *rang, bool val) +{ + uint32_t c; + + cell_set(gran, rang->sidx, rang->smask, val); + if (rang->sidx != rang->eidx) + { + cell_set(gran, rang->eidx, rang->emask, val); + c = rang->sidx + 1; + for (; c < rang->eidx; c++) + { + cell_set(gran, c, GATCFULL, val); + } + } + + return; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/* prepare given GAT range instance for later use. */ + +int gran_range(const gran_t *gran, size_t posi, size_t size, + gatr_t *rang) +{ + if (!gran || gran->ngranules < posi + size) + { + return -EINVAL; + } + + if (rang == NULL) + { + return -ENOMEM; + } + + rang->width = GATC_BITS(gran); + + rang->sidx = posi / rang->width; + rang->soff = posi % rang->width; + + posi += size - 1; + rang->eidx = posi / GATC_BITS(gran); + rang->eoff = posi % GATC_BITS(gran); + + rang->smask = ~(BIT(rang->soff) - 1); + rang->emask = (BIT(rang->eoff) - 1) | BIT(rang->eoff); + + if (rang->sidx == rang->eidx) + { + rang->smask &= rang->emask; /* combine the masks */ + rang->emask = rang->smask; + } + + return OK; +} + +/* checks if a range of granule matches the expected status */ + +bool gran_match(const gran_t *gran, size_t posi, size_t size, bool used, + size_t *mpos) +{ + uint32_t c; /* cell index */ + uint32_t v; /* masked cell value */ + uint32_t e; /* expected cell value */ + gatr_t r; /* range helper */ + + gran_range(gran, posi, size, &r); + + /* check the ending cell */ + + c = r.eidx; + e = used ? r.emask : 0 ; + v = gran->gat[c] & r.emask; + if (v != e) + { + goto failure; + } + + if (r.sidx == r.eidx) + { + return true; + } + + /* check cells in between */ + + c = r.eidx - 1; + e = used ? GATCFULL : 0; + for (; c > r.sidx; c--) + { + v = gran->gat[c]; + if (v != e) + { + goto failure; + } + } + + /* check the starting cell */ + + c = r.sidx; + e = used ? r.smask : 0 ; + v = gran->gat[c] & r.smask; + if (v != e) + { + goto failure; + } + + return true; + +failure: + + if (mpos && !used) + { + /* offset of last used when matching for free */ + + DEBUGASSERT(v); +#ifdef CONFIG_HAVE_BUILTIN_CLZ + *mpos = 31 - __builtin_clz(v); +#else + *mpos = (uint32_t)((msb_mask(v)) * DEBRUJIN_NUM) >> 27; + DEBUGASSERT(*mpos < sizeof(DEBRUJIN_LUT)); + *mpos = DEBRUJIN_LUT[*mpos]; +#endif + *mpos += c * GATC_BITS(gran); + } + + return false; +} + +/* returns granule number of free range or negative error */ + +int gran_search(const gran_t *gran, size_t size) +{ + int ret = -EINVAL; + + if (gran == NULL || gran->ngranules < size) + { + return ret; + } + + ret = -ENOMEM; + for (size_t i = 0; i <= gran->ngranules - size; i++) + { + if (gran_match(gran, i, size, 0, &i)) + { + ret = i; + break; + } + } + + return ret; +} + +/* set a range of granules */ + +int gran_set(gran_t *gran, size_t posi, size_t size) +{ + gatr_t rang; + int ret = gran_range(gran, posi, size, &rang); + + if (ret == OK) + { + gran_set_(gran, &rang, true); + } + + return ret; +} + +/* clear a range of granules */ + +int gran_clear(gran_t *gran, size_t posi, size_t size) +{ + gatr_t rang; + int ret = gran_range(gran, posi, size, &rang); + + if (ret == OK) + { + gran_set_(gran, &rang, false); + } + + return ret; +} + +#endif /* CONFIG_GRAN */ diff --git a/mm/mm_gran/mm_grantable.h b/mm/mm_gran/mm_grantable.h new file mode 100644 index 0000000000..1a1864bf2c --- /dev/null +++ b/mm/mm_gran/mm_grantable.h @@ -0,0 +1,159 @@ +/**************************************************************************** + * mm/mm_gran/mm_grantable.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __MM_MM_GRAN_MM_GRANTABLE_H +#define __MM_MM_GRAN_MM_GRANTABLE_H + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Granule arithmetics */ + +#define GRANSIZE(g) (1 << g->log2gran) +#define GRANMASK(g) (GRANSIZE(g) - 1) +#define NGRANULE(g, s) ((s + GRANMASK(g)) >> g->log2gran) + +#define GRANBYTE(g) ((size_t)g->ngranules << g->log2gran) +#define GRANENDA(g) (GRANBYTE(g) + g->heapstart) +#define MEM2GRAN(g, m) ((((uintptr_t)m) - g->heapstart) >> g->log2gran) +#define GRAN2MEM(g, x) ((((uintptr_t)x) << g->log2gran) + g->heapstart) + +#define GRAN_ALIGNED(g, m) ((((uintptr_t)(m)) & GRANMASK(g)) == 0) +#define GRAN_INRANGE(g, m) (g->heapstart <= (uintptr_t)(m) && \ + (uintptr_t)(m) < GRANENDA(g)) +#define GRAN_PRODUCT(g, m) (GRAN_ALIGNED(g, m) && GRAN_INRANGE(g, m)) + +#define ALIGNDN(g, m) (((size_t)m) & ~GRANMASK(g)) +#define ALIGNUP(g, m) ((((size_t)m) + GRANMASK(g)) & ~GRANMASK(g)) + +/* gran_reserve related */ + +#define MEM_RSRV(g, m) ALIGNDN(g, m) +#define END_RSRV(g, m, s) ALIGNUP(g, (((size_t)m) + s - 1)) +#define NUM_RSRV(g, m, s) (((END_RSRV(g, m, s) - MEM_RSRV(g, m)) \ + >> g->log2gran) + 1) +#define LEN_RSRV(g, m, s) ((size_t)(NUM_RSRV(g, m, s) << g->log2gran)) + +/* GAT table related */ + +#define GATC_BITS(g) (sizeof(g->gat[0]) << 3) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Structure for a range of granules in GAT */ + +struct gran_range_s +{ + uint16_t sidx; /* index of the starting GAT cell */ + uint16_t eidx; /* index of the ending GAT cell */ + uint8_t soff; /* offset of bit in starting cell */ + uint8_t eoff; /* offset of bit in ending cell */ + uint16_t width; /* width of cell in bits */ + uint32_t smask; /* mask of the starting GAT cell */ + uint32_t emask; /* mask of the ending GAT cell */ +}; + +typedef struct gran_range_s gatr_t; +typedef struct gran_s gran_t; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: gran_range + * + * Description: + * populate a gran_range_s instance for later use + * + * Input Parameters: + * gran - Pointer to the gran state + * posi - Position of starting granule + * size - Length of range + * + * Output Parameters: + * rang - The range instance to be prepared + * + * Return value: + * OK or negative errno + ****************************************************************************/ + +int gran_range(const gran_t *gran, size_t posi, size_t size, gatr_t *rang); + +/**************************************************************************** + * Name: gran_match + * + * Description: + * check if a continuous range of granules all have expected status + * + * Input Parameters: + * gran - Pointer to the gran state + * posi - Position of starting granule + * size - Length of range + * used - Expected state, true for used, false for empty. + * + * Output Parameters: + * mism - Optional last failed position upon free range matching. + * + * Return value: + * true for match, false otherwise. + ****************************************************************************/ + +bool gran_match(const gran_t *gran, size_t posi, size_t size, bool used, + size_t *mism); + +/**************************************************************************** + * Name: gran_search + * + * Description: + * search for continuous range of free granules + * + * Input Parameters: + * gran - Pointer to the gran state + * size - Length of range + * + * Return value: + * position of negative error number. + ****************************************************************************/ + +int gran_search(const gran_t *gran, size_t size); + +/**************************************************************************** + * Name: gran_set, gran_clear + * + * Description: + * Set or clear a range of granule in the GAT + * + * Input Parameters: + * gran - Pointer to the gran state + * posi - Range starting bit index + * size - Range size + * + * Return value: + * OK on success or negative value on error + ****************************************************************************/ + +int gran_set(gran_t *gran, size_t posi, size_t size); +int gran_clear(gran_t *gran, size_t posi, size_t size); + +#endif /* __MM_MM_GRAN_MM_GRANTABLE_H */