Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2)  * Implement primitive realloc(3) functionality.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  * Author: Mark A. Greer <mgreer@mvista.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  * 2006 (c) MontaVista, Software, Inc.  This file is licensed under
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  * the terms of the GNU General Public License version 2.  This program
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  * is licensed "as is" without any warranty of any kind, whether express
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  * or implied.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <stddef.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include "types.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include "page.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include "string.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include "ops.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #define	ENTRY_BEEN_USED	0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #define	ENTRY_IN_USE	0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) static struct alloc_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) 	unsigned long	flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 	unsigned long	base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 	unsigned long	size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) } *alloc_tbl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) static unsigned long tbl_entries;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) static unsigned long alloc_min;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) static unsigned long next_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) static unsigned long space_left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33)  * First time an entry is used, its base and size are set.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34)  * An entry can be freed and re-malloc'd but its base & size don't change.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35)  * Should be smart enough for needs of bootwrapper.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) static void *simple_malloc(unsigned long size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 	unsigned long i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 	struct alloc_info *p = alloc_tbl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 	if (size == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 		goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 	size = _ALIGN_UP(size, alloc_min);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 	for (i=0; i<tbl_entries; i++, p++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 		if (!(p->flags & ENTRY_BEEN_USED)) { /* never been used */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 			if (size <= space_left) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 				p->base = next_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 				p->size = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 				p->flags = ENTRY_BEEN_USED | ENTRY_IN_USE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 				next_base += size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 				space_left -= size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 				return (void *)p->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 			goto err_out; /* not enough space left */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 		/* reuse an entry keeping same base & size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 		else if (!(p->flags & ENTRY_IN_USE) && (size <= p->size)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 			p->flags |= ENTRY_IN_USE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 			return (void *)p->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) err_out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 	return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) static struct alloc_info *simple_find_entry(void *ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	unsigned long i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	struct alloc_info *p = alloc_tbl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	for (i=0; i<tbl_entries; i++,p++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 		if (!(p->flags & ENTRY_BEEN_USED))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 		if ((p->flags & ENTRY_IN_USE) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 		    (p->base == (unsigned long)ptr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 			return p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 	return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) static void simple_free(void *ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 	struct alloc_info *p = simple_find_entry(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 	if (p != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 		p->flags &= ~ENTRY_IN_USE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92)  * Change size of area pointed to by 'ptr' to 'size'.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93)  * If 'ptr' is NULL, then its a malloc().  If 'size' is 0, then its a free().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94)  * 'ptr' must be NULL or a pointer to a non-freed area previously returned by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95)  * simple_realloc() or simple_malloc().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) static void *simple_realloc(void *ptr, unsigned long size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	struct alloc_info *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 	void *new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	if (size == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 		simple_free(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 	if (ptr == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 		return simple_malloc(size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 	p = simple_find_entry(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	if (p == NULL) /* ptr not from simple_malloc/simple_realloc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	if (size <= p->size) /* fits in current block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 		return ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 	new = simple_malloc(size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	memcpy(new, ptr, p->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 	simple_free(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 	return new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)  * Returns addr of first byte after heap so caller can see if it took
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)  * too much space.  If so, change args & try again.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) void *simple_alloc_init(char *base, unsigned long heap_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 			unsigned long granularity, unsigned long max_allocs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 	unsigned long heap_base, tbl_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	heap_size = _ALIGN_UP(heap_size, granularity);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 	alloc_min = granularity;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 	tbl_entries = max_allocs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 	tbl_size = tbl_entries * sizeof(struct alloc_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 	alloc_tbl = (struct alloc_info *)_ALIGN_UP((unsigned long)base, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 	memset(alloc_tbl, 0, tbl_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	heap_base = _ALIGN_UP((unsigned long)alloc_tbl + tbl_size, alloc_min);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	next_base = heap_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 	space_left = heap_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 	platform_ops.malloc = simple_malloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 	platform_ops.free = simple_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	platform_ops.realloc = simple_realloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	return (void *)(heap_base + heap_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }