[Skiboot] [PATCH v2 4/7] skiboot: Fetch the IMA dtb
Oliver O'Halloran
oohall at gmail.com
Tue Nov 22 13:15:57 AEDT 2016
On Fri, Nov 18, 2016 at 1:10 PM, Hemant Kumar <hemant at linux.vnet.ibm.com> wrote:
> 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;
Should we be using be64_to_cpu(), etc when reading from the control block?
> + for (i = 0; i < 48; i++) {
48 shouldn't be hardcoded
> + 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");
If this fails we would have an invalid device tree. Personally I'd
rework this to be something like:
dev = dt_new_root("ima-counters");
dt_expand_node(dev, fdt, 0);
disable_unavailable_units(dev);
dt_attach_root(dev, dt_root);
That way we can prune the expanded IMA without affecting the main DT
and safely exit if any part of the process fails.
> err:
> free(buf);
> }
> --
> 2.7.4
>
> _______________________________________________
> Skiboot mailing list
> Skiboot at lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/skiboot
More information about the Skiboot
mailing list