[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