[Skiboot] [RFC PATCH 3/8] pef: Load ultravisor from pnor/flash
Stewart Smith
stewart at flamingspork.com
Fri Sep 6 02:35:37 AEST 2019
On Thu, Sep 5, 2019, at 6:29 AM, Ryan Grimm wrote:
> From: Santosh Sivaraj <santosh at fossix.org>
>
> Ultravisor firmware is present as a lid file or as 'UVISOR' partition.
> Use flash resource load helper to load ultravisor firmware into secure
> memory area pointed by the hdata.
>
> Signed-off-by: Santosh Sivaraj <santosh at fossix.org>
> [ grimm: Define load identifiers for ultra.lid.xz ]
> [ grimm: Improve error logging ]
> Signed-off-by: Ryan Grimm <grimm at linux.vnet.ibm.com>
> ---
> core/flash.c | 1 +
> core/init.c | 14 +++++
> hw/fsp/fsp.c | 2 +
> hw/ultravisor.c | 129 +++++++++++++++++++++++++++++++++++++++++++
> include/platform.h | 1 +
> include/ultravisor.h | 4 ++
> 6 files changed, 151 insertions(+)
>
> diff --git a/core/flash.c b/core/flash.c
> index 203b695d..a9c25486 100644
> --- a/core/flash.c
> +++ b/core/flash.c
> @@ -42,6 +42,7 @@ static struct {
> { RESOURCE_ID_INITRAMFS,RESOURCE_SUBID_NONE, "ROOTFS" },
> { RESOURCE_ID_CAPP, RESOURCE_SUBID_SUPPORTED, "CAPP" },
> { RESOURCE_ID_IMA_CATALOG, RESOURCE_SUBID_SUPPORTED, "IMA_CATALOG" },
> + { RESOURCE_ID_UV_IMAGE, RESOURCE_SUBID_NONE, "UVISOR" },
> { RESOURCE_ID_VERSION, RESOURCE_SUBID_NONE, "VERSION" },
> { RESOURCE_ID_KERNEL_FW, RESOURCE_SUBID_NONE, "BOOTKERNFW" },
> };
> diff --git a/core/init.c b/core/init.c
> index 25d827f2..08989b2d 100644
> --- a/core/init.c
> +++ b/core/init.c
> @@ -44,6 +44,7 @@
> #include <sbe-p9.h>
> #include <debug_descriptor.h>
> #include <occ.h>
> +#include <ultravisor.h>
>
> enum proc_gen proc_gen;
> unsigned int pcie_max_link_speed;
> @@ -1203,6 +1204,11 @@ void __noreturn __nomcount main_cpu_entry(const
> void *fdt)
> pci_nvram_init();
>
> preload_capp_ucode();
> +
> + /* preload and decompress ultravisor image */
> + uv_preload_image();
> + uv_decompress_image();
> +
> start_preload_kernel();
>
> /* Catalog decompression routine */
> @@ -1258,6 +1264,14 @@ void __noreturn __nomcount main_cpu_entry(const
> void *fdt)
> /* Add the list of interrupts going to OPAL */
> add_opal_interrupts();
>
> + /* Init uiltravisor software */
> + fdt = create_dtb(dt_root, false);
> + if (!fdt) {
> + op_display(OP_FATAL, OP_MOD_INIT, 2);
> + abort();
> + }
> + init_uv(fdt);
> +
> /* Now release parts of memory nodes we haven't used ourselves... */
> mem_region_release_unused();
>
> diff --git a/hw/fsp/fsp.c b/hw/fsp/fsp.c
> index 6fa6534f..829e56f4 100644
> --- a/hw/fsp/fsp.c
> +++ b/hw/fsp/fsp.c
> @@ -114,6 +114,7 @@ static u64 fsp_hir_timeout;
> #define KERNEL_LID_PHYP 0x80a00701
> #define KERNEL_LID_OPAL 0x80f00101
> #define INITRAMFS_LID_OPAL 0x80f00102
> +#define ULTRA_LID_OPAL 0x80f00105
>
> /*
> * We keep track on last logged values for some things to print only on
> @@ -2375,6 +2376,7 @@ static struct {
> } fsp_lid_map[] = {
> { RESOURCE_ID_KERNEL, RESOURCE_SUBID_NONE, KERNEL_LID_OPAL },
> { RESOURCE_ID_INITRAMFS,RESOURCE_SUBID_NONE, INITRAMFS_LID_OPAL },
> + { RESOURCE_ID_UV_IMAGE, RESOURCE_SUBID_NONE, ULTRA_LID_OPAL },
> { RESOURCE_ID_IMA_CATALOG,IMA_CATALOG_NIMBUS, 0x80f00103 },
> { RESOURCE_ID_CAPP, CAPP_IDX_MURANO_DD20, 0x80a02002 },
> { RESOURCE_ID_CAPP, CAPP_IDX_MURANO_DD21, 0x80a02001 },
> diff --git a/hw/ultravisor.c b/hw/ultravisor.c
> index f79699ef..4f049254 100644
> --- a/hw/ultravisor.c
> +++ b/hw/ultravisor.c
> @@ -24,6 +24,10 @@
> #include <inttypes.h>
> #include <ultravisor.h>
>
> +static char *uv_image = NULL;
> +static size_t uv_image_size;
> +struct xz_decompress *uv_xz = NULL;
> +
> static struct dt_node *add_uv_dt_node(void)
> {
> struct dt_node *dev, *uv;
> @@ -59,6 +63,37 @@ static struct dt_node *find_uv_node(void)
> return uv_node;
> }
>
> +void init_uv(const void *fdt)
> +{
> + struct dt_node *node;
> + const struct dt_property *base;
> +
> + assert(fdt);
> +
> + if (!is_msr_bit_set(MSR_S))
> + return;
> +
> + if (!uv_xz)
> + return;
> +
> + wait_xz_decompress(uv_xz);
> + if (uv_xz->status)
> + goto load_error;
> +
> + /* the uncompressed location will be the base address of ultravisor */
> + node = find_uv_node();
> + base = dt_find_property(node, "uv-base-address");
> + if (base)
> + dt_del_property(node, (struct dt_property *)base);
> +
> + dt_add_property_u64(node, "uv-base-address", (uint64_t)uv_xz->dst);
> +
> + /* TODO start ultravisor */
> +load_error:
> + free(uv_image);
> + free(uv_xz);
> +}
> +
> static bool dt_append_memory_range(struct dt_node *node, __be64 start,
> __be64 len)
> {
> @@ -131,3 +166,97 @@ bool uv_add_mem_range(__be64 start, __be64 end)
>
> return ret;
> }
> +
> +static bool uv_on_hw(void)
> +{
> + return (is_msr_bit_set(MSR_S) &&
> + !(proc_chip_quirks & QUIRK_MAMBO_CALLOUTS) &&
> + (proc_gen >= proc_gen_p9));
> +}
> +
> +/*
> + * Preload the uv image from SMF pnor partition
> + */
SMF isn't a term that's used elsewhere
> +void uv_preload_image(void)
> +{
> + int ret;
> +
> +
> + if (uv_on_hw() == false)
> + return;
> +
> + prlog(PR_DEBUG, "UV preload starting\n");
> +
> + uv_image_size = MAX_COMPRESSED_UV_IMAGE_SIZE;
> + uv_image = malloc(MAX_COMPRESSED_UV_IMAGE_SIZE);
> + if (!uv_image) {
> + prerror("Memory allocation for ultravisor failed\n");
> + return;
> + }
Should this be on the heap or should we allocate it off a main memory region somewhere (and subsequently free it)?
What if the UV grows?
> +
> + ret = start_preload_resource(RESOURCE_ID_UV_IMAGE, RESOURCE_SUBID_NONE,
> + uv_image, &uv_image_size);
> +
> + if (ret != OPAL_SUCCESS) {
> + prerror("UV: Failed to preload Ultravisor image: %d\n", ret);
> + free(uv_image);
> + uv_image = NULL;
> + }
All of this code looks familiar to other resources, there should probably be just some common code o do this.
> +}
> +
> +/*
> + * Decompress the UV image
> + *
> + * This function modifies the uv_image variable to point to the decompressed
> + * image location.
> + */
> +void uv_decompress_image(void)
> +{
> + const struct dt_property *ranges;
> + struct dt_node *uv_node;
> + uint64_t *range;
> +
> + if (uv_on_hw() == false)
> + return;
why can't we run in sim? What prevents us from loading and running it with mambo?
> +
> + if (uv_image == NULL) {
> + prerror("UV: Preload hasn't started yet! Aborting.\n");
or did it error out?
> + return;
> + }
> +
> + if (wait_for_resource_loaded(RESOURCE_ID_UV_IMAGE,
> + RESOURCE_SUBID_NONE) != OPAL_SUCCESS) {
> + prerror("UV: Ultravisor image load failed\n");
> + return;
> + }
> +
> + uv_node = dt_find_by_name(dt_root, "ibm,uv-firmware");
> + if (!uv_node) {
> + prerror("UV: Cannot find ibm,uv-firmware node\n");
> + return;
> + }
> +
> + ranges = dt_find_property(uv_node, "secure-memory-ranges");
> + if (!ranges) {
> + prerror("UV: Cannot find secure-memory-ranges");
> + return;
> + }
> +
> + uv_xz = malloc(sizeof(struct xz_decompress));
> + if (!uv_xz) {
> + prerror("UV: Cannot allocate memory for decompression of UV\n");
> + return;
> + }
in all of these cases, memory allocated for the UV image isn't freed.
> + /* the load area is the first secure memory range */
> + range = (void *)ranges->prop;
> + uv_xz->dst = (void *)dt_get_number(range, 2);
> + uv_xz->dst_size = dt_get_number(range + 1, 2);
> + uv_xz->src = uv_image;
> + uv_xz->src_size = uv_image_size;
> +
> + /* TODO security and integrity checks? */
I think it should certainly verify and measure loading the UV before any UV patch is merged.
> + xz_start_decompress(uv_xz);
> + if ((uv_xz->status != OPAL_PARTIAL) && (uv_xz->status != OPAL_SUCCESS))
> + prerror("UV: XZ decompression failed status 0x%x\n", uv_xz->status);
> +}
> diff --git a/include/platform.h b/include/platform.h
> index 0b043856..259550d4 100644
> --- a/include/platform.h
> +++ b/include/platform.h
> @@ -17,6 +17,7 @@ enum resource_id {
> RESOURCE_ID_INITRAMFS,
> RESOURCE_ID_CAPP,
> RESOURCE_ID_IMA_CATALOG,
> + RESOURCE_ID_UV_IMAGE,
> RESOURCE_ID_VERSION,
> RESOURCE_ID_KERNEL_FW,
> };
> diff --git a/include/ultravisor.h b/include/ultravisor.h
> index d038d42b..08f10da4 100644
> --- a/include/ultravisor.h
> +++ b/include/ultravisor.h
> @@ -20,8 +20,12 @@
> /* Bit 15 of an address should be set for it to be used as a secure memory area
> * for the secure virtual machines */
> #define UV_SECURE_MEM_BIT (PPC_BIT(15))
> +#define MAX_COMPRESSED_UV_IMAGE_SIZE 0x40000 /* 256 Kilobytes */
How big is the partition size currently?
More information about the Skiboot
mailing list