diff mbox series

[RFC,3/8] pef: Load ultravisor from pnor/flash

Message ID 20190905132919.8765-4-grimm@linux.ibm.com
State Superseded
Headers show
Series PEF support in Skiboot | expand

Checks

Context Check Description
snowpatch_ozlabs/apply_patch warning Failed to apply on branch master (7b12d5489fcfd73ef7ec0cb27eff7f8a5f13b238)
snowpatch_ozlabs/apply_patch fail Failed to apply to any branch

Commit Message

Ryan Grimm Sept. 5, 2019, 1:29 p.m. UTC
From: Santosh Sivaraj <santosh@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@fossix.org>
[ grimm: Define load identifiers for ultra.lid.xz ]
[ grimm: Improve error logging ]
Signed-off-by: Ryan Grimm <grimm@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(+)

Comments

Stewart Smith Sept. 5, 2019, 4:35 p.m. UTC | #1
On Thu, Sep 5, 2019, at 6:29 AM, Ryan Grimm wrote:
> From: Santosh Sivaraj <santosh@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@fossix.org>
> [ grimm: Define load identifiers for ultra.lid.xz ]
> [ grimm: Improve error logging ]
> Signed-off-by: Ryan Grimm <grimm@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?
Ryan Grimm Sept. 11, 2019, 9:26 p.m. UTC | #2
Thanks for reviewing!  I was subscribed to the skiboot list in digest
mode so I'm fixing up replies by hand for this thread, apologies if it
looks weird.  

>> + * Preload the uv image from SMF pnor partition
>> + */

>SMF isn't a term that's used elsewhere

Oops, we don't want to use that term, I thought I grep'd for them, will
remove/fix.

>> +	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?

Good point.  You asked below but to answer here the UV partition is
1MB.  

So, we can use local_alloc, but I'm struggling a little bit to figure
out how to free it.  I looked at examples of local_alloc, but it
doesn't seem any of the code in occ, phb4, or xive free their
allocations.

Is it up to the caller to deal with mem_regions and call mem_free with
the mem_region?

>> +
>> +	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.

K, it is similar to loading KERNEL and INITRAMFS, but, I thought we
were doing it right.  I'll look again.

>> +	if (uv_on_hw() == false)
>> +		return;

>why can't we run in sim? What prevents us from loading and running it
>with mambo?

Good point, we don't need that.  I removed uv_on_hw and calls to it and
things are OK.

>> +
>> +	if (uv_image == NULL) {
>> +		prerror("UV: Preload hasn't started yet! Aborting.\n");

>or did it error out?

K, will check what is done with kernel and try to be consistent.

>> +		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.

K, right, will fix it up.

>> +	/* 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.

K, will do.

Thanks,
Ryan
diff mbox series

Patch

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
+ */
+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;
+	}
+
+	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;
+	}
+}
+
+/*
+ * 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;
+
+	if (uv_image == NULL) {
+		prerror("UV: Preload hasn't started yet! Aborting.\n");
+		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;
+	}
+
+	/* 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? */
+	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 */
 
 extern int start_uv(uint64_t entry, void *ptr);
 extern bool uv_add_mem_range(__be64 start, __be64 end);
+extern void uv_preload_image(void);
+extern void uv_decompress_image(void);
+extern void init_uv(const void *fdt);
 
 #endif /* __ULTRAVISOR_H */