blob: 3a2fd1782e93b9ab41f9a4fd76d1113c0fe37820 [file] [log] [blame]
Simon Glass143fa862021-09-25 07:03:07 -06001// 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
Simon Glass3c356312023-01-15 14:15:45 -07009#ifndef USE_HOSTCC
Simon Glass143fa862021-09-25 07:03:07 -060010#include <malloc.h>
11#include <mapmem.h>
12#include <string.h>
Simon Glassb776e252025-05-02 08:46:04 -060013#include <vsprintf.h>
Simon Glass3c356312023-01-15 14:15:45 -070014#endif
15
Simon Glassb776e252025-05-02 08:46:04 -060016#include <errno.h>
17#include <stdarg.h>
Simon Glass3c356312023-01-15 14:15:45 -070018#include <abuf.h>
Simon Glass143fa862021-09-25 07:03:07 -060019
20void abuf_set(struct abuf *abuf, void *data, size_t size)
21{
22 abuf_uninit(abuf);
23 abuf->data = data;
24 abuf->size = size;
25}
26
Simon Glass3c356312023-01-15 14:15:45 -070027#ifndef USE_HOSTCC
Simon Glass143fa862021-09-25 07:03:07 -060028void abuf_map_sysmem(struct abuf *abuf, ulong addr, size_t size)
29{
30 abuf_set(abuf, map_sysmem(addr, size), size);
31}
Simon Glassb63269b2025-01-10 17:00:01 -070032
33ulong abuf_addr(const struct abuf *abuf)
34{
35 return map_to_sysmem(abuf->data);
36}
37
Simon Glass3c356312023-01-15 14:15:45 -070038#else
39/* copied from lib/string.c for convenience */
40static char *memdup(const void *src, size_t len)
41{
42 char *p;
43
44 p = malloc(len);
45 if (!p)
46 return NULL;
47
48 memcpy(p, src, len);
49
50 return p;
51}
52#endif
Simon Glass143fa862021-09-25 07:03:07 -060053
54bool abuf_realloc(struct abuf *abuf, size_t new_size)
55{
56 void *ptr;
57
58 if (!new_size) {
59 /* easy case, just need to uninit, freeing any allocation */
60 abuf_uninit(abuf);
61 return true;
62 } else if (abuf->alloced) {
63 /* currently allocated, so need to reallocate */
64 ptr = realloc(abuf->data, new_size);
65 if (!ptr)
66 return false;
67 abuf->data = ptr;
68 abuf->size = new_size;
69 return true;
70 } else if (new_size <= abuf->size) {
71 /*
72 * not currently alloced and new size is no larger. Just update
73 * it. Data is lost off the end if new_size < abuf->size
74 */
75 abuf->size = new_size;
76 return true;
77 } else {
78 /* not currently allocated and new size is larger. Alloc and
79 * copy in data. The new space is not inited.
80 */
Simon Glass00a05e22022-02-28 12:08:22 -070081 ptr = malloc(new_size);
Simon Glass143fa862021-09-25 07:03:07 -060082 if (!ptr)
83 return false;
Simon Glass00a05e22022-02-28 12:08:22 -070084 if (abuf->size)
85 memcpy(ptr, abuf->data, abuf->size);
Simon Glass143fa862021-09-25 07:03:07 -060086 abuf->data = ptr;
87 abuf->size = new_size;
88 abuf->alloced = true;
89 return true;
90 }
91}
92
Simon Glass733c2622023-08-14 16:40:22 -060093bool abuf_realloc_inc(struct abuf *abuf, size_t inc)
94{
95 return abuf_realloc(abuf, abuf->size + inc);
96}
97
Simon Glass143fa862021-09-25 07:03:07 -060098void *abuf_uninit_move(struct abuf *abuf, size_t *sizep)
99{
100 void *ptr;
101
102 if (sizep)
103 *sizep = abuf->size;
104 if (!abuf->size)
105 return NULL;
106 if (abuf->alloced) {
107 ptr = abuf->data;
108 } else {
109 ptr = memdup(abuf->data, abuf->size);
110 if (!ptr)
111 return NULL;
112 }
113 /* Clear everything out so there is no record of the data */
114 abuf_init(abuf);
115
116 return ptr;
117}
118
119void abuf_init_set(struct abuf *abuf, void *data, size_t size)
120{
121 abuf_init(abuf);
122 abuf_set(abuf, data, size);
123}
124
Simon Glass6651e942025-05-01 07:37:01 -0600125bool abuf_init_size(struct abuf *buf, size_t size)
126{
127 abuf_init(buf);
128 if (!abuf_realloc(buf, size))
129 return false;
130
131 return true;
132}
133
Simon Glass38890132025-05-02 08:46:03 -0600134bool abuf_copy(const struct abuf *old, struct abuf *copy)
135{
136 char *data;
137
138 data = malloc(old->size);
139 if (!data)
140 return false;
141 memcpy(data, old->data, old->size);
142 abuf_init_set(copy, data, old->size);
143 copy->alloced = true;
144
145 return true;
146}
147
Simon Glassb776e252025-05-02 08:46:04 -0600148int abuf_printf(struct abuf *buf, const char *fmt, ...)
149{
150 int maxlen = buf->size;
151 va_list args;
152 int len;
153
154 va_start(args, fmt);
155 len = vsnprintf(buf->data, buf->size, fmt, args);
156 va_end(args);
157
158 /* add the terminator */
159 len++;
160
161 if (len > 4096)
162 return -E2BIG;
163 if (len > maxlen) {
164 /* make more space and try again */
165 maxlen = len;
166 if (!abuf_realloc(buf, maxlen))
167 return -ENOMEM;
168 va_start(args, fmt);
169 len = vsnprintf(buf->data, maxlen, fmt, args);
170 va_end(args);
171
172 /* check there isn't anything strange going on */
173 if (len > maxlen)
174 return -EFAULT;
175 }
176
177 return len;
178}
179
Simon Glasse3a938e2025-01-10 17:00:03 -0700180void abuf_init_const(struct abuf *abuf, const void *data, size_t size)
181{
182 /* for now there is no flag indicating that the abuf data is constant */
183 abuf_init_set(abuf, (void *)data, size);
184}
185
Simon Glass143fa862021-09-25 07:03:07 -0600186void abuf_init_move(struct abuf *abuf, void *data, size_t size)
187{
188 abuf_init_set(abuf, data, size);
189 abuf->alloced = true;
190}
191
192void abuf_uninit(struct abuf *abuf)
193{
194 if (abuf->alloced)
195 free(abuf->data);
196 abuf_init(abuf);
197}
198
199void abuf_init(struct abuf *abuf)
200{
201 abuf->data = NULL;
202 abuf->size = 0;
203 abuf->alloced = false;
204}