1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Handles a buffer that can be allocated and freed
4  *
5  * Copyright 2021 Google LLC
6  * Written by Simon Glass <sjg@chromium.org>
7  */
8 
9 #ifndef USE_HOSTCC
10 #include <common.h>
11 #include <malloc.h>
12 #include <mapmem.h>
13 #include <string.h>
14 #endif
15 
16 #include <abuf.h>
17 
abuf_set(struct abuf * abuf,void * data,size_t size)18 void abuf_set(struct abuf *abuf, void *data, size_t size)
19 {
20 	abuf_uninit(abuf);
21 	abuf->data = data;
22 	abuf->size = size;
23 }
24 
25 #ifndef USE_HOSTCC
abuf_map_sysmem(struct abuf * abuf,ulong addr,size_t size)26 void abuf_map_sysmem(struct abuf *abuf, ulong addr, size_t size)
27 {
28 	abuf_set(abuf, map_sysmem(addr, size), size);
29 }
30 #else
31 /* copied from lib/string.c for convenience */
memdup(const void * src,size_t len)32 static char *memdup(const void *src, size_t len)
33 {
34 	char *p;
35 
36 	p = malloc(len);
37 	if (!p)
38 		return NULL;
39 
40 	memcpy(p, src, len);
41 
42 	return p;
43 }
44 #endif
45 
abuf_realloc(struct abuf * abuf,size_t new_size)46 bool abuf_realloc(struct abuf *abuf, size_t new_size)
47 {
48 	void *ptr;
49 
50 	if (!new_size) {
51 		/* easy case, just need to uninit, freeing any allocation */
52 		abuf_uninit(abuf);
53 		return true;
54 	} else if (abuf->alloced) {
55 		/* currently allocated, so need to reallocate */
56 		ptr = realloc(abuf->data, new_size);
57 		if (!ptr)
58 			return false;
59 		abuf->data = ptr;
60 		abuf->size = new_size;
61 		return true;
62 	} else if (new_size <= abuf->size) {
63 		/*
64 		 * not currently alloced and new size is no larger. Just update
65 		 * it. Data is lost off the end if new_size < abuf->size
66 		 */
67 		abuf->size = new_size;
68 		return true;
69 	} else {
70 		/* not currently allocated and new size is larger. Alloc and
71 		 * copy in data. The new space is not inited.
72 		 */
73 		ptr = malloc(new_size);
74 		if (!ptr)
75 			return false;
76 		if (abuf->size)
77 			memcpy(ptr, abuf->data, abuf->size);
78 		abuf->data = ptr;
79 		abuf->size = new_size;
80 		abuf->alloced = true;
81 		return true;
82 	}
83 }
84 
abuf_uninit_move(struct abuf * abuf,size_t * sizep)85 void *abuf_uninit_move(struct abuf *abuf, size_t *sizep)
86 {
87 	void *ptr;
88 
89 	if (sizep)
90 		*sizep = abuf->size;
91 	if (!abuf->size)
92 		return NULL;
93 	if (abuf->alloced) {
94 		ptr = abuf->data;
95 	} else {
96 		ptr = memdup(abuf->data, abuf->size);
97 		if (!ptr)
98 			return NULL;
99 	}
100 	/* Clear everything out so there is no record of the data */
101 	abuf_init(abuf);
102 
103 	return ptr;
104 }
105 
abuf_init_set(struct abuf * abuf,void * data,size_t size)106 void abuf_init_set(struct abuf *abuf, void *data, size_t size)
107 {
108 	abuf_init(abuf);
109 	abuf_set(abuf, data, size);
110 }
111 
abuf_init_move(struct abuf * abuf,void * data,size_t size)112 void abuf_init_move(struct abuf *abuf, void *data, size_t size)
113 {
114 	abuf_init_set(abuf, data, size);
115 	abuf->alloced = true;
116 }
117 
abuf_uninit(struct abuf * abuf)118 void abuf_uninit(struct abuf *abuf)
119 {
120 	if (abuf->alloced)
121 		free(abuf->data);
122 	abuf_init(abuf);
123 }
124 
abuf_init(struct abuf * abuf)125 void abuf_init(struct abuf *abuf)
126 {
127 	abuf->data = NULL;
128 	abuf->size = 0;
129 	abuf->alloced = false;
130 }
131