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