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 <linux/string.h> 14 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 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 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 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 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 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 97 void abuf_uninit(struct abuf *abuf) 98 { 99 if (abuf->alloced) 100 free(abuf->data); 101 abuf_init(abuf); 102 } 103 104 void abuf_init(struct abuf *abuf) 105 { 106 abuf->data = NULL; 107 abuf->size = 0; 108 abuf->alloced = false; 109 } 110