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