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

Hemant Kumar hemant at linux.vnet.ibm.com
Tue Dec 6 05:30:58 AEDT 2016


Thanks for all the suggestions Oliver. They have been taken care of in 
the v3 of this patchset : 
https://lists.ozlabs.org/pipermail/skiboot/2016-December/005729.html

--

Thanks,

Hemant Kumar


On 11/22/2016 07:45 AM, Oliver O'Halloran wrote:
> 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