[Skiboot] [RFC PATCH v7 10/12] Load the ultravisor from flash and decompress

Ryan Grimm grimm at linux.ibm.com
Tue Jul 7 02:14:37 AEST 2020


The ultravisor, labeled UVISOR is preloaded from the PNOR in
main_cpu_entry after the kernel is preloaded.  This also works on
FSP-based systems with an ultra.lid on the FSP.

Skiboot decompresses it later in init_uv.

Signed-off-by: Santosh Sivaraj <santosh at linux.ibm.com>
Signed-off-by: Ryan Grimm <grimm at linux.ibm.com>
---
 core/flash.c         |  1 +
 core/init.c          |  1 +
 hw/fsp/fsp.c         |  2 +
 hw/ultravisor.c      | 95 +++++++++++++++++++++++++++++++++++++++-----
 include/platform.h   |  1 +
 include/ultravisor.h |  3 ++
 6 files changed, 93 insertions(+), 10 deletions(-)

diff --git a/core/flash.c b/core/flash.c
index de748641..bc44a4e5 100644
--- a/core/flash.c
+++ b/core/flash.c
@@ -45,6 +45,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 e0166098..d9a181a7 100644
--- a/core/init.c
+++ b/core/init.c
@@ -1315,6 +1315,7 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt)
 
 	preload_capp_ucode();
 	start_preload_kernel();
+	uv_preload_image();
 
 	/* Catalog decompression routine */
 	imc_decompress_catalog();
diff --git a/hw/fsp/fsp.c b/hw/fsp/fsp.c
index 70452cf9..7b564f93 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
@@ -2381,6 +2382,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 467f0ca6..34c16404 100644
--- a/hw/ultravisor.c
+++ b/hw/ultravisor.c
@@ -10,11 +10,16 @@
 #include <cpu.h>
 #include <debug_descriptor.h>
 #include <console.h>
+#include <chip.h>
+#include <libstb/container.h>
 
 static struct dt_node *uv_fw_node;
 static uint64_t uv_base_addr;
 bool uv_present;
 
+static char *uv_image = NULL;
+static size_t uv_image_size;
+
 struct memcons uv_memcons __section(".data.memcons") = {
 	.magic		= MEMCONS_MAGIC,
 	.obuf_phys	= INMEM_UV_CON_START,
@@ -70,10 +75,44 @@ int start_ultravisor(void *fdt)
 	return OPAL_SUCCESS;
 }
 
+static int uv_decompress_image(void)
+{
+	struct xz_decompress uv_xz;
+	uint64_t uv_fw_size;
+
+	if (!uv_image) {
+		prerror("UV: Preload hasn't started yet! Aborting.\n");
+		return OPAL_INTERNAL_ERROR;
+	}
+
+	if (wait_for_resource_loaded(RESOURCE_ID_UV_IMAGE,
+				     RESOURCE_SUBID_NONE) != OPAL_SUCCESS) {
+		prerror("UV: Ultravisor image load failed\n");
+		return OPAL_INTERNAL_ERROR;
+	}
+
+	uv_xz.dst = (void *)dt_get_address(uv_fw_node, 0, &uv_fw_size);
+	uv_xz.dst_size = uv_fw_size;
+	uv_xz.src_size = uv_image_size;
+	uv_xz.src = uv_image;
+
+	if (stb_is_container((void*)uv_xz.src, uv_xz.src_size))
+		uv_xz.src = uv_xz.src + SECURE_BOOT_HEADERS_SIZE;
+
+	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);
+		return OPAL_INTERNAL_ERROR;
+	}
+
+	return OPAL_SUCCESS;
+}
+
 void init_uv()
 {
 	uint64_t uv_dt_src, uv_fw_sz;
 	struct dt_node *reserved_mem;
+	int ret;
 
 	if (!is_msr_bit_set(MSR_S)) {
 		prlog(PR_DEBUG, "UV: S bit not set\n");
@@ -84,23 +123,59 @@ void init_uv()
 	if (!uv_fw_node) {
 		prlog(PR_DEBUG, "UV: No ibm,uv-firmware node found, disabling pef\n");
 		cpu_disable_pef();
-		return;
+		goto err;
 	}
 
-	reserved_mem = dt_find_by_path(dt_root, "/reserved-memory/ibm,uv-firmware");
-	if (!reserved_mem) {
-		prerror("UV: No reserved memory for ibm,uv-firmware found\n");
-		return;
-	}
+	/* If decompress fails, look for reserved memory by Mambo tcl or cronus BML */
+	ret = uv_decompress_image();
+	if (ret) {
+		reserved_mem = dt_find_by_path(dt_root, "/reserved-memory/ibm,uv-firmware");
+		if (!reserved_mem) {
+			prerror("UV: No reserved memory for ibm,uv-firmware found\n");
+			return;
+		}
 
-	uv_dt_src = dt_get_address(reserved_mem, 0, &uv_fw_sz);
-	uv_base_addr = dt_get_address(uv_fw_node, 0, NULL);
+		uv_dt_src = dt_get_address(reserved_mem, 0, &uv_fw_sz);
+		uv_base_addr = dt_get_address(uv_fw_node, 0, NULL);
 
-	prlog(PR_INFO, "UV: Copying 0x%llx bytes to protected memory 0x%llx from 0x%llx\n",
+		prlog(PR_INFO, "UV: Copying 0x%llx bytes to protected memory 0x%llx from 0x%llx\n",
 					uv_fw_sz, uv_base_addr, uv_dt_src);
 
-	memcpy((void *)uv_base_addr, (void *)uv_dt_src, uv_fw_sz);
+		memcpy((void *)uv_base_addr, (void *)uv_dt_src, uv_fw_sz);
+	}
 
 	dt_add_property_u64(uv_fw_node, "memcons", (u64)&uv_memcons);
 	debug_descriptor.uv_memcons_phys = (u64)&uv_memcons;
+err:
+	local_free(uv_image);
+}
+
+/*
+ * Preload the UV image from PNOR partition
+ *
+ * uv_image is allocated locally to the chip and freed here if preload fails
+ * or free in init_uv
+ */
+void uv_preload_image(void)
+{
+	struct proc_chip *chip = next_chip(NULL);
+	int ret;
+
+	prlog(PR_DEBUG, "UV: Preload starting\n");
+
+	uv_image_size = MAX_COMPRESSED_UV_IMAGE_SIZE;
+	uv_image = local_alloc(chip->id, uv_image_size, uv_image_size);
+	if (!uv_image) {
+		prerror("UV: Memory allocation failed\n");
+		return;
+	}
+	memset(uv_image, 0, uv_image_size);
+
+	ret = start_preload_resource(RESOURCE_ID_UV_IMAGE, RESOURCE_SUBID_NONE,
+				     uv_image, &uv_image_size);
+
+	if (ret != OPAL_SUCCESS) {
+		local_free(uv_image);
+		prerror("UV: platform load failed: %d\n", ret);
+	}
 }
diff --git a/include/platform.h b/include/platform.h
index ef93278b..57b2eeef 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 d2fbb2f9..23e14b2c 100644
--- a/include/ultravisor.h
+++ b/include/ultravisor.h
@@ -66,4 +66,7 @@ static inline int uv_xscom_write(u64 partid, u64 pcb_addr, u64 val)
 
 #define UV_LOAD_MAX_SIZE 0x200000
 
+#define MAX_COMPRESSED_UV_IMAGE_SIZE	0x40000 /* 256 Kilobytes */
+void uv_preload_image(void);
+
 #endif /* __ULTRAVISOR_H */
-- 
2.21.0



More information about the Skiboot mailing list