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