[Skiboot] [PATCH v2 4/7] skiboot: Fetch the IMA dtb

Hemant Kumar hemant at linux.vnet.ibm.com
Fri Nov 18 13:10:57 AEDT 2016


The sub-partition that we obtain from the IMA_CATALOG partition is a
compressed device tree binary. We uncompress it using the libxz's
functions. After uncompressing it, we link the device tree binary to the
system's device tree. The kernel can now access the device tree and get
the IMA PMUs and their events' information.

Not all the IMA PMUs listed in the device tree may be available. This is
indicated by ima availability vector (which is a part of the IMA control
block structure). We need to check this vector and make sure to remove
the IMA device nodes which are unavailable.

Signed-off-by: Hemant Kumar <hemant at linux.vnet.ibm.com>
---
Changelog:
v1 -> v2:
 - Added a new function disable_unavailable_units() to check the IMA
   availability vector and remove the nest PMU nodes from the device
   tree.

 hw/ima.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 122 insertions(+)

diff --git a/hw/ima.c b/hw/ima.c
index 7f9184f..1fb07fd 100644
--- a/hw/ima.c
+++ b/hw/ima.c
@@ -18,6 +18,66 @@
 #include <xscom.h>
 #include <ima.h>
 #include <chip.h>
+#include <libxz/xz.h>
+#include <nest_ima.h>
+
+/*
+ * Decompresses the blob obtained from the IMA catalog sub-partition
+ * in "buf" of size "size", assigns the uncompressed device tree
+ * binary to "fdt" and returns.
+ * Returns 0 on success and -1 on error.
+ */
+static int decompress_subpartition(char *buf, size_t size, void **fdt)
+{
+	struct xz_dec *s;
+	struct xz_buf b;
+	void *data;
+	int ret = 0;
+
+	/* Initialize the xz library first */
+	xz_crc32_init();
+	s = xz_dec_init(XZ_SINGLE, 0);
+	if (s == NULL)
+	{
+		prerror("IMA: initialization error for xz\n");
+		return -1;
+	}
+
+	/* Allocate memory for the uncompressed data */
+	data = malloc(IMA_DTB_SIZE);
+	if (!data) {
+		prerror("IMA: memory allocation error\n");
+		ret = -1;
+		goto err;
+	}
+
+	/*
+	 * Source address : buf
+	 * Source size : size
+	 * Destination address : data
+	 * Destination size : IMA_DTB_SIZE
+	 */
+	b.in = buf;
+	b.in_pos = 0;
+	b.in_size = size;
+	b.out = data;
+	b.out_pos = 0;
+	b.out_size = IMA_DTB_SIZE;
+
+	/* Start decompressing */
+	ret = xz_dec_run(s, &b);
+	if (ret != XZ_STREAM_END) {
+		prerror("IMA: failed to decompress subpartition\n");
+		free(data);
+		ret = -1;
+	}
+	*fdt = data;
+
+err:
+	/* Clean up memory */
+	xz_dec_end(s);
+	return ret;
+}
 
 static bool is_power8(void)
 {
@@ -32,8 +92,46 @@ static bool is_power8(void)
 }
 
 /*
+ * Remove the PMU device nodes from the system's dt, if they are not
+ * available in the hardware. The availability is described by the
+ * control block's ima_chip_avl_vector.
+ * Each bit represents a device unit. If the device is available, then
+ * the bit is set else its unset.
+ */
+static int disable_unavailable_units(void)
+{
+	uint64_t cb_loc, avl_vec;
+	struct ima_chip_cb *cb;
+	struct proc_chip *chip;
+	struct dt_node *target;
+	int i;
+
+	chip = get_chip(this_cpu()->chip_id);
+
+	/* Fetch the IMA control block structure */
+	cb_loc = chip->homer_base + CB_STRUCT_OFFSET;
+	cb = (struct ima_chip_cb *)cb_loc;
+
+	avl_vec = cb->ima_chip_avl_vector;
+	for (i = 0; i < 48; i++) {
+		if (!(PPC_BITMASK(i, i) & avl_vec)) {
+			/* Check if the device node exists */
+			target = dt_find_by_name(dt_root, nest_pmus[i]);
+			if (!target)
+				continue;
+			/* Remove the device node */
+			dt_free(target);
+		}
+	}
+
+	return 0;
+}
+
+/*
  * Fetch the IMA Catalog partition and find the appropriate sub-partition
  * based on the platform's PVR.
+ * Decompress the sub-partition and link the ima device tree to the
+ * existing device tree.
  */
 void ima_init(void)
 {
@@ -41,6 +139,8 @@ void ima_init(void)
 	size_t size = IMA_DTB_SIZE;
 	uint32_t pvr = mfspr(SPR_PVR);
 	int ret;
+	struct dt_node *dev;
+	void *fdt = NULL;
 
 	/* Disable this for power 8 */
 	if (is_power8())
@@ -64,6 +164,28 @@ void ima_init(void)
 		goto err;
 	}
 
+	/* Decompress the subpartition now */
+	ret = decompress_subpartition(buf, size, &fdt);
+	if (ret < 0) {
+		goto err;
+	}
+
+	/* Create a device tree entry for ima counters */
+	dev = dt_new(dt_root, "ima-counters");
+	if (!dev) {
+		prerror("IMA: Unable to create device node\n");
+		goto err;
+	}
+
+	/* Attach the new fdt to the ima-counters node */
+	ret = dt_expand_node(dev, fdt, 0);
+	if (ret < 0)
+		prerror("IMA: device tree couldn't be linked\n");
+
+	/* Check availability of the PMU units from the availability vector */
+	ret = disable_unavailable_units();
+	if (ret < 0)
+		prerror("IMA: error in disabling unavailable units\n");
 err:
 	free(buf);
 }
-- 
2.7.4



More information about the Skiboot mailing list