[Skiboot] [PATCH 10/14] hdata: Add an idata array iterator
Oliver O'Halloran
oohall at gmail.com
Fri Sep 15 15:40:55 AEST 2017
Adds HDIF_get_iarray() which retrieves and validates an internal array
header and HDIF_iarray_for_each() for walking the individual array
entries. This reduces the amount of get-then-check boilerplate that
we have with the existing HDIF_get_iarray_item() method for iterating
internal data arrays.
Signed-off-by: Oliver O'Halloran <oohall at gmail.com>
---
hdata/hdif.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
hdata/hdif.h | 18 ++++++++++++++++
2 files changed, 87 insertions(+)
diff --git a/hdata/hdif.c b/hdata/hdif.c
index b616a331a0bc..6c9febf0bb24 100644
--- a/hdata/hdif.c
+++ b/hdata/hdif.c
@@ -96,6 +96,75 @@ int HDIF_get_iarray_size(const struct HDIF_common_hdr *hdif, unsigned int di)
return be32_to_cpu(ahdr->ecnt);
}
+/*
+ * Returns NULL and sets *items to zero when:
+ *
+ * a) Array extends beyond bounds (hard error)
+ * b) The array is empty (soft error)
+ * c) The item size is zero (soft error)
+ * d) The array is missing (soft error)
+ *
+ * b, c) are bugs in the input data so they generate backtraces.
+ *
+ * If you care about the soft error cases, retrive the array header manually
+ * with HDIF_get_idata().
+ */
+const struct HDIF_array_hdr *HDIF_get_iarray(const struct HDIF_common_hdr *hdif,
+ unsigned int di, unsigned int *items)
+{
+ const struct HDIF_array_hdr *arr;
+ unsigned int req_size, size, elements;
+ unsigned int actual_sz, alloc_sz, offset;
+
+ arr = HDIF_get_idata(hdif, di, &size);
+
+ if(items)
+ *items = 0;
+
+ if (!arr || !size)
+ return NULL;
+
+ /* base size of an Idata array header */
+ offset = be32_to_cpu(arr->offset);
+ actual_sz = be32_to_cpu(arr->eactsz);
+ alloc_sz = be32_to_cpu(arr->esize);
+ elements = be32_to_cpu(arr->ecnt);
+
+ /* actual size should always be smaller than allocated */
+ if (alloc_sz < actual_sz) {
+ prerror("HDIF %.6s iarray %u has actsz (%u) < alloc_sz (%u)\n)",
+ hdif->id, di, actual_sz, alloc_sz);
+ backtrace();
+ return NULL;
+ }
+
+ req_size = elements * alloc_sz + offset;
+ if (req_size > size) {
+ prerror("HDIF: %.6s iarray %u requires %#x bytes, but only %#x are allocated!\n",
+ hdif->id, di, req_size, size);
+ backtrace();
+ return NULL;
+ }
+
+ if (!elements || !actual_sz)
+ return NULL;
+
+ if (items)
+ *items = elements;
+
+ return arr;
+}
+
+const void *HDIF_iarray_item(const struct HDIF_array_hdr *ahdr,
+ unsigned int index)
+{
+ if (!ahdr || index >= be32_to_cpu(ahdr->ecnt))
+ return NULL;
+
+ return (const void * )ahdr + be32_to_cpu(ahdr->offset) +
+ index * be32_to_cpu(ahdr->esize);
+}
+
struct HDIF_child_ptr *
HDIF_child_arr(const struct HDIF_common_hdr *hdif, unsigned int idx)
{
diff --git a/hdata/hdif.h b/hdata/hdif.h
index 22345b368eca..d54e533309ea 100644
--- a/hdata/hdif.h
+++ b/hdata/hdif.h
@@ -105,6 +105,24 @@ extern const void *HDIF_get_iarray_item(const struct HDIF_common_hdr *hdif,
unsigned int di,
unsigned int ai, unsigned int *size);
+/* HDIF_get_iarray - Get a pointer to an internal array header
+ *
+ * @hdif : HDIF structure pointer
+ * @di : Index of the idata pointer
+ * @ai : Index in the resulting array
+ * @size : Return the entry actual size (or NULL if ignored)
+ */
+extern const struct HDIF_array_hdr *HDIF_get_iarray(
+ const struct HDIF_common_hdr *hdif, unsigned int di,
+ unsigned int *items);
+
+extern const void *HDIF_iarray_item(const struct HDIF_array_hdr *hdif,
+ unsigned int index);
+
+#define HDIF_iarray_for_each(arr, idx, ptr) \
+ for (idx = 0, ptr = HDIF_iarray_item(arr, idx); \
+ ptr; idx++, ptr = HDIF_iarray_item(arr, idx))
+
/* HDIF_get_iarray_size - Get the number of elements of an internal data array
*
* @hdif : HDIF structure pointer
--
2.9.5
More information about the Skiboot
mailing list