forked from Mirrors/opensbi
lib: sbi: Implement aligned memory allocators
This change adds a simple implementation of sbi_aligned_alloc(), for future use in allocating aligned memory for SMMTT tables. Signed-off-by: Gregor Haas <gregorhaas1997@gmail.com> Reviewed-by: Anup Patel <anup@brainfault.org>
This commit is contained in:
@@ -31,6 +31,15 @@ static inline void *sbi_malloc(size_t size)
|
|||||||
return sbi_malloc_from(&global_hpctrl, size);
|
return sbi_malloc_from(&global_hpctrl, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Allocate aligned from heap area */
|
||||||
|
void *sbi_aligned_alloc_from(struct sbi_heap_control *hpctrl,
|
||||||
|
size_t alignment,size_t size);
|
||||||
|
|
||||||
|
static inline void *sbi_aligned_alloc(size_t alignment, size_t size)
|
||||||
|
{
|
||||||
|
return sbi_aligned_alloc_from(&global_hpctrl, alignment, size);
|
||||||
|
}
|
||||||
|
|
||||||
/** Zero allocate from heap area */
|
/** Zero allocate from heap area */
|
||||||
void *sbi_zalloc_from(struct sbi_heap_control *hpctrl, size_t size);
|
void *sbi_zalloc_from(struct sbi_heap_control *hpctrl, size_t size);
|
||||||
|
|
||||||
|
@@ -37,27 +37,67 @@ struct sbi_heap_control {
|
|||||||
|
|
||||||
struct sbi_heap_control global_hpctrl;
|
struct sbi_heap_control global_hpctrl;
|
||||||
|
|
||||||
void *sbi_malloc_from(struct sbi_heap_control *hpctrl, size_t size)
|
static void *alloc_with_align(struct sbi_heap_control *hpctrl,
|
||||||
|
size_t align, size_t size)
|
||||||
{
|
{
|
||||||
void *ret = NULL;
|
void *ret = NULL;
|
||||||
struct heap_node *n, *np;
|
struct heap_node *n, *np, *rem;
|
||||||
|
unsigned long lowest_aligned;
|
||||||
|
size_t pad;
|
||||||
|
|
||||||
if (!size)
|
if (!size)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
size += HEAP_ALLOC_ALIGN - 1;
|
size += align - 1;
|
||||||
size &= ~((unsigned long)HEAP_ALLOC_ALIGN - 1);
|
size &= ~((unsigned long)align - 1);
|
||||||
|
|
||||||
spin_lock(&hpctrl->lock);
|
spin_lock(&hpctrl->lock);
|
||||||
|
|
||||||
np = NULL;
|
np = NULL;
|
||||||
sbi_list_for_each_entry(n, &hpctrl->free_space_list, head) {
|
sbi_list_for_each_entry(n, &hpctrl->free_space_list, head) {
|
||||||
if (size <= n->size) {
|
lowest_aligned = ROUNDUP(n->addr, align);
|
||||||
|
pad = lowest_aligned - n->addr;
|
||||||
|
|
||||||
|
if (size + pad <= n->size) {
|
||||||
np = n;
|
np = n;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (np) {
|
if (!np)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (pad) {
|
||||||
|
if (sbi_list_empty(&hpctrl->free_node_list)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = sbi_list_first_entry(&hpctrl->free_node_list,
|
||||||
|
struct heap_node, head);
|
||||||
|
sbi_list_del(&n->head);
|
||||||
|
|
||||||
|
if ((size + pad < np->size) &&
|
||||||
|
!sbi_list_empty(&hpctrl->free_node_list)) {
|
||||||
|
rem = sbi_list_first_entry(&hpctrl->free_node_list,
|
||||||
|
struct heap_node, head);
|
||||||
|
sbi_list_del(&rem->head);
|
||||||
|
rem->addr = np->addr + (size + pad);
|
||||||
|
rem->size = np->size - (size + pad);
|
||||||
|
sbi_list_add_tail(&rem->head,
|
||||||
|
&hpctrl->free_space_list);
|
||||||
|
} else if (size + pad != np->size) {
|
||||||
|
/* Can't allocate, return n */
|
||||||
|
sbi_list_add(&n->head, &hpctrl->free_node_list);
|
||||||
|
ret = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
n->addr = lowest_aligned;
|
||||||
|
n->size = size;
|
||||||
|
sbi_list_add_tail(&n->head, &hpctrl->used_space_list);
|
||||||
|
|
||||||
|
np->size = pad;
|
||||||
|
ret = (void *)n->addr;
|
||||||
|
} else {
|
||||||
if ((size < np->size) &&
|
if ((size < np->size) &&
|
||||||
!sbi_list_empty(&hpctrl->free_node_list)) {
|
!sbi_list_empty(&hpctrl->free_node_list)) {
|
||||||
n = sbi_list_first_entry(&hpctrl->free_node_list,
|
n = sbi_list_first_entry(&hpctrl->free_node_list,
|
||||||
@@ -76,11 +116,34 @@ void *sbi_malloc_from(struct sbi_heap_control *hpctrl, size_t size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
spin_unlock(&hpctrl->lock);
|
spin_unlock(&hpctrl->lock);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *sbi_malloc_from(struct sbi_heap_control *hpctrl, size_t size)
|
||||||
|
{
|
||||||
|
return alloc_with_align(hpctrl, HEAP_ALLOC_ALIGN, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *sbi_aligned_alloc_from(struct sbi_heap_control *hpctrl,
|
||||||
|
size_t alignment, size_t size)
|
||||||
|
{
|
||||||
|
if (alignment < HEAP_ALLOC_ALIGN)
|
||||||
|
alignment = HEAP_ALLOC_ALIGN;
|
||||||
|
|
||||||
|
/* Make sure alignment is power of two */
|
||||||
|
if ((alignment & (alignment - 1)) != 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Make sure size is multiple of alignment */
|
||||||
|
if (size % alignment != 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return alloc_with_align(hpctrl, alignment, size);
|
||||||
|
}
|
||||||
|
|
||||||
void *sbi_zalloc_from(struct sbi_heap_control *hpctrl, size_t size)
|
void *sbi_zalloc_from(struct sbi_heap_control *hpctrl, size_t size)
|
||||||
{
|
{
|
||||||
void *ret = sbi_malloc_from(hpctrl, size);
|
void *ret = sbi_malloc_from(hpctrl, size);
|
||||||
|
Reference in New Issue
Block a user