| // SPDX-License-Identifier: GPL-2.0+ | |
| /* | |
| * Handles a buffer that can be allocated and freed | |
| * | |
| * Copyright 2021 Google LLC | |
| * Written by Simon Glass <sjg@chromium.org> | |
| */ | |
| #include <common.h> | |
| #include <abuf.h> | |
| #include <malloc.h> | |
| #include <mapmem.h> | |
| #include <string.h> | |
| void abuf_set(struct abuf *abuf, void *data, size_t size) | |
| { | |
| abuf_uninit(abuf); | |
| abuf->data = data; | |
| abuf->size = size; | |
| } | |
| void abuf_map_sysmem(struct abuf *abuf, ulong addr, size_t size) | |
| { | |
| abuf_set(abuf, map_sysmem(addr, size), size); | |
| } | |
| bool abuf_realloc(struct abuf *abuf, size_t new_size) | |
| { | |
| void *ptr; | |
| if (!new_size) { | |
| /* easy case, just need to uninit, freeing any allocation */ | |
| abuf_uninit(abuf); | |
| return true; | |
| } else if (abuf->alloced) { | |
| /* currently allocated, so need to reallocate */ | |
| ptr = realloc(abuf->data, new_size); | |
| if (!ptr) | |
| return false; | |
| abuf->data = ptr; | |
| abuf->size = new_size; | |
| return true; | |
| } else if (new_size <= abuf->size) { | |
| /* | |
| * not currently alloced and new size is no larger. Just update | |
| * it. Data is lost off the end if new_size < abuf->size | |
| */ | |
| abuf->size = new_size; | |
| return true; | |
| } else { | |
| /* not currently allocated and new size is larger. Alloc and | |
| * copy in data. The new space is not inited. | |
| */ | |
| ptr = malloc(new_size); | |
| if (!ptr) | |
| return false; | |
| if (abuf->size) | |
| memcpy(ptr, abuf->data, abuf->size); | |
| abuf->data = ptr; | |
| abuf->size = new_size; | |
| abuf->alloced = true; | |
| return true; | |
| } | |
| } | |
| void *abuf_uninit_move(struct abuf *abuf, size_t *sizep) | |
| { | |
| void *ptr; | |
| if (sizep) | |
| *sizep = abuf->size; | |
| if (!abuf->size) | |
| return NULL; | |
| if (abuf->alloced) { | |
| ptr = abuf->data; | |
| } else { | |
| ptr = memdup(abuf->data, abuf->size); | |
| if (!ptr) | |
| return NULL; | |
| } | |
| /* Clear everything out so there is no record of the data */ | |
| abuf_init(abuf); | |
| return ptr; | |
| } | |
| void abuf_init_set(struct abuf *abuf, void *data, size_t size) | |
| { | |
| abuf_init(abuf); | |
| abuf_set(abuf, data, size); | |
| } | |
| void abuf_init_move(struct abuf *abuf, void *data, size_t size) | |
| { | |
| abuf_init_set(abuf, data, size); | |
| abuf->alloced = true; | |
| } | |
| void abuf_uninit(struct abuf *abuf) | |
| { | |
| if (abuf->alloced) | |
| free(abuf->data); | |
| abuf_init(abuf); | |
| } | |
| void abuf_init(struct abuf *abuf) | |
| { | |
| abuf->data = NULL; | |
| abuf->size = 0; | |
| abuf->alloced = false; | |
| } |