xref: /kvm-unit-tests/lib/alloc.c (revision be704aff683c54fc108deaafacc7cb89ad0648d9)
1 #include "alloc.h"
2 #include "bitops.h"
3 #include "asm/page.h"
4 #include "bitops.h"
5 
6 void *malloc(size_t size)
7 {
8 	return memalign(sizeof(long), size);
9 }
10 
11 static bool mult_overflow(size_t a, size_t b)
12 {
13 #if BITS_PER_LONG == 32
14 	/* 32 bit system, easy case: just use u64 */
15 	return (u64)a * (u64)b >= (1ULL << 32);
16 #else
17 #ifdef __SIZEOF_INT128__
18 	/* if __int128 is available use it (like the u64 case above) */
19 	unsigned __int128 res = a;
20 	res *= b;
21 	res >>= 64;
22 	return res != 0;
23 #else
24 	u64 tmp;
25 
26 	if ((a >> 32) && (b >> 32))
27 		return true;
28 	if (!(a >> 32) && !(b >> 32))
29 		return false;
30 	tmp = (u32)a;
31 	tmp *= (u32)b;
32 	tmp >>= 32;
33 	if (a < b)
34 		tmp += a * (b >> 32);
35 	else
36 		tmp += b * (a >> 32);
37 	return tmp >> 32;
38 #endif /* __SIZEOF_INT128__ */
39 #endif /* BITS_PER_LONG == 32 */
40 }
41 
42 void *calloc(size_t nmemb, size_t size)
43 {
44 	void *ptr;
45 
46 	assert(!mult_overflow(nmemb, size));
47 	ptr = malloc(nmemb * size);
48 	if (ptr)
49 		memset(ptr, 0, nmemb * size);
50 	return ptr;
51 }
52 
53 #define METADATA_EXTRA	(2 * sizeof(uintptr_t))
54 #define OFS_SLACK	(-2 * sizeof(uintptr_t))
55 #define OFS_SIZE	(-sizeof(uintptr_t))
56 
57 static inline void *block_begin(void *mem)
58 {
59 	uintptr_t slack = *(uintptr_t *)(mem + OFS_SLACK);
60 	return mem - slack;
61 }
62 
63 static inline uintptr_t block_size(void *mem)
64 {
65 	return *(uintptr_t *)(mem + OFS_SIZE);
66 }
67 
68 void free(void *ptr)
69 {
70 	if (!alloc_ops->free)
71 		return;
72 
73 	void *base = block_begin(ptr);
74 	uintptr_t sz = block_size(ptr);
75 
76 	alloc_ops->free(base, sz);
77 }
78 
79 void *memalign(size_t alignment, size_t size)
80 {
81 	void *p;
82 	uintptr_t blkalign;
83 	uintptr_t mem;
84 
85 	if (!size)
86 		return NULL;
87 
88 	assert(alignment >= sizeof(void *) && is_power_of_2(alignment));
89 	assert(alloc_ops && alloc_ops->memalign);
90 
91 	size += alignment - 1;
92 	blkalign = MAX(alignment, alloc_ops->align_min);
93 	size = ALIGN(size + METADATA_EXTRA, alloc_ops->align_min);
94 	p = alloc_ops->memalign(blkalign, size);
95 	assert(p);
96 
97 	/* Leave room for metadata before aligning the result.  */
98 	mem = (uintptr_t)p + METADATA_EXTRA;
99 	mem = ALIGN(mem, alignment);
100 
101 	/* Write the metadata */
102 	*(uintptr_t *)(mem + OFS_SLACK) = mem - (uintptr_t)p;
103 	*(uintptr_t *)(mem + OFS_SIZE) = size;
104 	return (void *)mem;
105 }
106