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 #include <common.h>
10 #include <abuf.h>
11 #include <malloc.h>
12 #include <mapmem.h>
13 #include <string.h>
14 
abuf_set(struct abuf * abuf,void * data,size_t size)15 void abuf_set(struct abuf *abuf, void *data, size_t size)
16 {
17 	abuf_uninit(abuf);
18 	abuf->data = data;
19 	abuf->size = size;
20 }
21 
abuf_map_sysmem(struct abuf * abuf,ulong addr,size_t size)22 void abuf_map_sysmem(struct abuf *abuf, ulong addr, size_t size)
23 {
24 	abuf_set(abuf, map_sysmem(addr, size), size);
25 }
26 
abuf_realloc(struct abuf * abuf,size_t new_size)27 bool abuf_realloc(struct abuf *abuf, size_t new_size)
28 {
29 	void *ptr;
30 
31 	if (!new_size) {
32 		/* easy case, just need to uninit, freeing any allocation */
33 		abuf_uninit(abuf);
34 		return true;
35 	} else if (abuf->alloced) {
36 		/* currently allocated, so need to reallocate */
37 		ptr = realloc(abuf->data, new_size);
38 		if (!ptr)
39 			return false;
40 		abuf->data = ptr;
41 		abuf->size = new_size;
42 		return true;
43 	} else if (new_size <= abuf->size) {
44 		/*
45 		 * not currently alloced and new size is no larger. Just update
46 		 * it. Data is lost off the end if new_size < abuf->size
47 		 */
48 		abuf->size = new_size;
49 		return true;
50 	} else {
51 		/* not currently allocated and new size is larger. Alloc and
52 		 * copy in data. The new space is not inited.
53 		 */
54 		ptr = memdup(abuf->data, new_size);
55 		if (!ptr)
56 			return false;
57 		abuf->data = ptr;
58 		abuf->size = new_size;
59 		abuf->alloced = true;
60 		return true;
61 	}
62 }
63 
abuf_uninit_move(struct abuf * abuf,size_t * sizep)64 void *abuf_uninit_move(struct abuf *abuf, size_t *sizep)
65 {
66 	void *ptr;
67 
68 	if (sizep)
69 		*sizep = abuf->size;
70 	if (!abuf->size)
71 		return NULL;
72 	if (abuf->alloced) {
73 		ptr = abuf->data;
74 	} else {
75 		ptr = memdup(abuf->data, abuf->size);
76 		if (!ptr)
77 			return NULL;
78 	}
79 	/* Clear everything out so there is no record of the data */
80 	abuf_init(abuf);
81 
82 	return ptr;
83 }
84 
abuf_init_set(struct abuf * abuf,void * data,size_t size)85 void abuf_init_set(struct abuf *abuf, void *data, size_t size)
86 {
87 	abuf_init(abuf);
88 	abuf_set(abuf, data, size);
89 }
90 
abuf_init_move(struct abuf * abuf,void * data,size_t size)91 void abuf_init_move(struct abuf *abuf, void *data, size_t size)
92 {
93 	abuf_init_set(abuf, data, size);
94 	abuf->alloced = true;
95 }
96 
abuf_uninit(struct abuf * abuf)97 void abuf_uninit(struct abuf *abuf)
98 {
99 	if (abuf->alloced)
100 		free(abuf->data);
101 	abuf_init(abuf);
102 }
103 
abuf_init(struct abuf * abuf)104 void abuf_init(struct abuf *abuf)
105 {
106 	abuf->data = NULL;
107 	abuf->size = 0;
108 	abuf->alloced = false;
109 }
110