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