diff options
-rw-r--r-- | src/import/chips/p9/utils/imageProcs/p9_dd_container.c | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/src/import/chips/p9/utils/imageProcs/p9_dd_container.c b/src/import/chips/p9/utils/imageProcs/p9_dd_container.c new file mode 100644 index 00000000..7e1e2726 --- /dev/null +++ b/src/import/chips/p9/utils/imageProcs/p9_dd_container.c @@ -0,0 +1,262 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/import/chips/p9/utils/imageProcs/p9_dd_container.c $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017,2018 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#include <stdint.h> +#include <stddef.h> +#include <stdlib.h> +#include <endian.h> +#include <string.h> +#include <stdio.h> + +#include "p9_dd_container.h" + +int p9_dd_validate(struct p9_dd_cont* i_cont) +{ + if (!i_cont) + { + return P9_DD_FAILURE_DOES_NOT_EXIST; + } + + if (be32toh(i_cont->iv_magic) != P9_DD_CONTAINER_MAGIC) + { + return P9_DD_FAILURE_BROKEN; + } + + // may want to check here for holes or overlap as to stored blocks + + return P9_DD_SUCCESS; +} + +// iterates through all dd level blocks +struct p9_dd_block* p9_dd_next(struct p9_dd_iter* io_iter) +{ + struct p9_dd_block* block; + + if (!io_iter || + !io_iter->iv_cont || + io_iter->iv_idx >= io_iter->iv_cont->iv_num) + { + return NULL; + } + + block = &(io_iter->iv_cont->iv_blocks)[io_iter->iv_idx]; + io_iter->iv_idx++; + + return block; +} + +uint8_t* p9_dd_addr(struct p9_dd_cont* i_cont, uint32_t i_offset) +{ + return (uint8_t*)i_cont + i_offset; +} + +void p9_dd_betoh(struct p9_dd_block* i_block_be, + struct p9_dd_block* io_block_he) +{ + io_block_he->iv_offset = be32toh(i_block_be->iv_offset); + io_block_he->iv_size = be32toh(i_block_be->iv_size); + io_block_he->iv_dd = i_block_be->iv_dd; +} + +// returns address of dd level content (without meta data) +int p9_dd_get(uint8_t* i_cont, uint8_t i_dd, uint8_t** o_buf, uint32_t* o_size) +{ + struct p9_dd_cont* cont = (struct p9_dd_cont*)i_cont; + struct p9_dd_iter iter = P9_DD_ITER_INIT(cont); + struct p9_dd_block* block; + struct p9_dd_block block_he; + int rc; + + rc = p9_dd_validate(cont); + + if (rc != P9_DD_SUCCESS) + { + return rc; + } + + while ((block = p9_dd_next(&iter))) + { + if (block->iv_dd == i_dd) + { + p9_dd_betoh(block, &block_he); + *o_buf = p9_dd_addr(cont, block_he.iv_offset); + *o_size = block_he.iv_size; + return P9_DD_SUCCESS; + } + } + + return P9_DD_FAILURE_NOT_FOUND; +} + +uint32_t p9_dd_size_meta(struct p9_dd_cont* i_cont) +{ + return (i_cont ? + (sizeof(struct p9_dd_cont) + + sizeof(struct p9_dd_block) * i_cont->iv_num) : + 0); +} + +// assumes only API (p9_dd_add()) used to create container, +// that is, last block header points to block with biggest offset +uint32_t p9_dd_size(struct p9_dd_cont* i_cont) +{ + struct p9_dd_block* last; + + if (!i_cont) + { + return 0; + } + + if (!i_cont->iv_num) + { + return p9_dd_size_meta(i_cont); + } + + last = &(i_cont->iv_blocks)[i_cont->iv_num - 1]; + + return be32toh(last->iv_offset) + be32toh(last->iv_size); +} + +struct p9_dd_cont* p9_dd_create(void) +{ + struct p9_dd_cont* cont; + + cont = malloc(sizeof(struct p9_dd_cont)); + + if (!cont) + { + return cont; + } + + cont->iv_magic = htobe32(P9_DD_CONTAINER_MAGIC); + cont->iv_num = 0; + + return cont; +} + +// enlarges (reallocates) container and copies dd level block into container +int p9_dd_add( + uint8_t** io_cont, uint32_t* o_cont_size, uint8_t i_dd, + uint8_t* i_buf, uint32_t i_buf_size) +{ + struct p9_dd_cont* cont = (struct p9_dd_cont*)*io_cont; + + uint8_t* dupl_buf; + uint32_t dupl_size; + + uint32_t enlarged; + + int rc; + + uint8_t* others_addr_new; + uint8_t* others_addr_old; + uint32_t others_size; + struct p9_dd_block* others_block; + + uint8_t* this_addr; + uint32_t this_offs; + struct p9_dd_block* this_block; + + struct p9_dd_iter iter = P9_DD_ITER_INIT(NULL); + + // handle duplicates and initial setup of empty container + rc = p9_dd_get(*io_cont, i_dd, &dupl_buf, &dupl_size); + + switch (rc) + { + case P9_DD_FAILURE_NOT_FOUND : + break; + + case P9_DD_FAILURE_DOES_NOT_EXIST : + cont = p9_dd_create(); + + if (!cont) + { + return P9_DD_FAILURE_NOMEM; + } + + break; + + case P9_DD_SUCCESS : + return P9_DD_FAILURE_DUPLICATE; + + default : + return rc; + } + + // size of enlarged container + enlarged = p9_dd_size(cont) + sizeof(struct p9_dd_block) + i_buf_size; + + // re-allocate to enlarge container (content is retained and consistent) + cont = realloc(cont, enlarged); + + if (!cont) + { + return P9_DD_FAILURE_NOMEM; + } + + // offsets and size of existing bufs + others_addr_old = p9_dd_addr(cont, p9_dd_size_meta(cont)); + others_addr_new = others_addr_old + sizeof(struct p9_dd_block); + others_size = p9_dd_size(cont) - p9_dd_size_meta(cont); + + // meta data, offset and address of new buf + this_block = (struct p9_dd_block*)others_addr_old; + this_offs = p9_dd_size(cont) + sizeof(struct p9_dd_block); + this_addr = p9_dd_addr(cont, this_offs); + + // fix offsets of existing bufs + iter.iv_cont = cont; + + while ((others_block = p9_dd_next(&iter))) + { + others_block->iv_offset = + htobe32(be32toh(others_block->iv_offset) + + sizeof(struct p9_dd_block)); + } + + // move existing bufs + memmove(others_addr_new, others_addr_old, others_size); + + // copy new buf into container + memcpy(this_addr, i_buf, i_buf_size); + + // fill in meta data for new buf + memset(this_block, sizeof(struct p9_dd_block), 0); + this_block->iv_offset = htobe32(this_offs); + this_block->iv_size = htobe32(i_buf_size); + this_block->iv_dd = i_dd; + this_block->iv_reserved[0] = 0; + this_block->iv_reserved[1] = 0; + this_block->iv_reserved[2] = 0; + + // increase number off DD level blocks in container + (cont)->iv_num++; + + *io_cont = (uint8_t*)cont; + *o_cont_size = enlarged; + + return P9_DD_SUCCESS; +} |