@@ -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" },
};
@@ -1300,6 +1300,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();
@@ -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
@@ -2372,6 +2373,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 },
@@ -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 = false;
+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,
@@ -69,9 +74,51 @@ 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 = malloc(sizeof(struct xz_decompress));
+ if (!uv_xz) {
+ prerror("UV: Cannot allocate memory for decompression of UV\n");
+ return OPAL_NO_MEM;
+ }
+
+ 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);
+ free(uv_xz);
+ return OPAL_INTERNAL_ERROR;
+ }
+
+ free(uv_xz);
+ return OPAL_SUCCESS;
+}
+
void init_uv()
{
uint64_t uv_dt_src, uv_fw_sz;
+ int ret;
if (!is_msr_bit_set(MSR_S)) {
prlog(PR_DEBUG, "UV: S bit not set\n");
@@ -81,22 +128,57 @@ void init_uv()
uv_fw_node = dt_find_compatible_node(dt_root, NULL, "ibm,uv-firmware");
if (!uv_fw_node) {
prerror("UV: No ibm,uv-firmware node found\n");
- return;
+ goto err;
}
- if (!dt_find_property(uv_fw_node, "uv-src-address")) {
- prerror("UV: No uv-src-address found\n");
- return;
- }
+ ret = uv_decompress_image();
+ if (ret) {
+ if (!dt_find_property(uv_fw_node, "uv-src-address")) {
+ prerror("UV: No uv-src-address found\n");
+ goto err;
+ }
- uv_dt_src = dt_prop_get_u64(uv_fw_node, "uv-src-address");
- uv_base_addr = dt_get_address(uv_fw_node, 0, &uv_fw_sz);
+ uv_dt_src = dt_prop_get_u64(uv_fw_node, "uv-src-address");
+ uv_base_addr = dt_get_address(uv_fw_node, 0, &uv_fw_sz);
- prlog(PR_INFO, "UV: Copying to protected memory 0x%llx from 0x%llx\n",
- uv_base_addr, uv_dt_src);
+ prlog(PR_INFO, "UV: Copying to protected memory 0x%llx from 0x%llx\n",
+ uv_base_addr, uv_dt_src);
- memcpy((void *)uv_base_addr, (void *)uv_dt_src, UV_LOAD_MAX_SIZE);
+ memcpy((void *)uv_base_addr, (void *)uv_dt_src, UV_LOAD_MAX_SIZE);
+ }
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);
+ }
}
@@ -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,
};
@@ -8,7 +8,8 @@
#include <types.h>
#include <processor.h>
-#define UV_LOAD_MAX_SIZE 0x200000
+#define MAX_COMPRESSED_UV_IMAGE_SIZE 0x40000 /* 256 Kilobytes */
+#define UV_LOAD_MAX_SIZE 0x200000
#define UCALL_BUFSIZE 4
#define UV_READ_SCOM 0xF114
@@ -19,6 +20,7 @@ extern int start_uv(uint64_t entry, void *fdt);
extern bool uv_present;
int start_ultravisor(void *fdt);
+void uv_preload_image(void);
void init_uv(void);
static inline int uv_xscom_read(u64 partid, u64 pcb_addr, u64 *val)