summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/import/chips/p9/utils/imageProcs/p9_dd_container.c262
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;
+}
OpenPOWER on IntegriCloud