[Skiboot] [RFC PATCH 4/8] pef: Ultravisor initialisation
Ryan Grimm
grimm at linux.ibm.com
Thu Sep 5 23:29:15 AEST 2019
From: Madhavan Srinivasan <maddy at linux.vnet.ibm.com>
The ultravisor image after is start on each CPU after being loaded from
the flash/fsp. It is copied to secure memory and run.
Signed-off-by: Madhavan Srinivasan <maddy at linux.vnet.ibm.com>
Signed-off-by: Santosh Sivaraj <santosh at fossix.org>
[ grimm: Add init_uv comments, logging, and logic cleanups ]
[ grimm: Increase UV image max size to 2MB ]
[ grimm: Redfine the OPAL UV shared data structure ]
[ grimm: Remove Hostboot regions from secure range 0 ]
Signed-off-by: Ryan Grimm <grimm at linux.ibm.com>
[ andmike: Split init and start of ultravisor ]
Signed-off-by: Michael Anderson <andmike at linux.ibm.com>
---
core/init.c | 11 +-
hw/ultravisor.c | 256 +++++++++++++++++++++++++++++++++++++--
include/ultravisor-api.h | 31 +++++
include/ultravisor.h | 13 +-
4 files changed, 294 insertions(+), 17 deletions(-)
create mode 100644 include/ultravisor-api.h
diff --git a/core/init.c b/core/init.c
index 08989b2d..756ee211 100644
--- a/core/init.c
+++ b/core/init.c
@@ -544,6 +544,10 @@ void __noreturn load_and_boot_kernel(bool is_reboot)
trustedboot_exit_boot_services();
+ if (!is_reboot) {
+ start_ultravisor();
+ }
+
ipmi_set_fw_progress_sensor(IPMI_FW_OS_BOOT);
@@ -1265,12 +1269,7 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt)
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);
+ init_uv();
/* Now release parts of memory nodes we haven't used ourselves... */
mem_region_release_unused();
diff --git a/hw/ultravisor.c b/hw/ultravisor.c
index 4f049254..e3d7d42a 100644
--- a/hw/ultravisor.c
+++ b/hw/ultravisor.c
@@ -23,10 +23,14 @@
#include <string.h>
#include <inttypes.h>
#include <ultravisor.h>
+#include <mem_region.h>
+#include <ultravisor-api.h>
+#include <libfdt/libfdt.h>
static char *uv_image = NULL;
static size_t uv_image_size;
struct xz_decompress *uv_xz = NULL;
+static struct uv_opal *uv_opal;
static struct dt_node *add_uv_dt_node(void)
{
@@ -63,32 +67,266 @@ static struct dt_node *find_uv_node(void)
return uv_node;
}
-void init_uv(const void *fdt)
+static bool find_secure_mem_to_copy(uint64_t *target, uint64_t *sz)
+{
+ struct dt_node *uv_node = find_uv_node();
+ const struct dt_property *ranges;
+ uint64_t uv_pef_reg;
+ uint64_t *range, sm_size, img_size = UV_LOAD_MAX_SIZE;
+
+ /*
+ * "uv-secure-memory" property could have multiple
+ * secure memory blocks. Pick first to load
+ * ultravisor in it.
+ */
+ ranges = dt_find_property(uv_node, "secure-memory-ranges");
+ if (!ranges)
+ return false;
+
+ range = (void *)ranges->prop;
+ do {
+ uv_pef_reg = dt_get_number(range, 2);
+ if (!uv_pef_reg)
+ return false;
+
+ sm_size = dt_get_number(range + 1, 2);
+ if (sm_size > img_size)
+ break;
+ range += 2;
+ } while (range);
+
+ *target = uv_pef_reg;
+ *sz = sm_size;
+ return true;
+}
+
+static uint64_t find_uv_fw_base_addr(struct dt_node *uv_node)
+{
+ uint64_t base_addr = 0;
+
+ if (dt_has_node_property(uv_node, "uv-base-address", NULL))
+ base_addr = dt_prop_get_u64(uv_node, "uv-base-address");
+
+ return base_addr;
+}
+
+static void reserve_secure_memory_region(void)
+{
+ struct dt_node *uv_node = find_uv_node();
+ const struct dt_property *ranges;
+ uint64_t *range, *rangesp, sm_size, addr;
+ char buf[128];
+ int i=0;
+
+ ranges = dt_find_property(uv_node, "secure-memory-ranges");
+ if (!ranges)
+ return;
+
+ for (rangesp = (uint64_t *)(ranges->prop + ranges->len),
+ range = (uint64_t *)ranges->prop;
+ range < rangesp;
+ range += 2) {
+ addr = dt_get_number(range, 2);
+ if (!addr)
+ break;
+
+ sm_size = dt_get_number(range + 1, 2);
+ if (!sm_size)
+ break;
+
+ /* Remove Hostboot regions from secure memory 0 so we don't abort
+ * on overlapping regions */
+ if (i == 0) {
+ prlog(PR_INFO, "Secure region 0, removing HB region\n");
+ /* TODO: Check with Hostboot for memory map */
+ sm_size = sm_size - UV_HB_RESERVE_SIZE;
+ }
+
+ snprintf(buf, 128, "ibm,secure-region-%d",i++);
+ mem_reserve_fw(strdup(buf), addr, sm_size);
+ }
+
+ return;
+}
+
+static void reserve_uv_memory(struct uv_opal *uv_opal)
+{
+ if (uv_opal->uv_base_addr == UV_LOAD_BASE) {
+ mem_reserve_fw("ibm,uv-code", UV_LOAD_BASE, UV_LOAD_MAX_SIZE);
+ } else {
+ reserve_secure_memory_region();
+ }
+}
+
+static void cpu_start_ultravisor(void *data)
+{
+ struct uv_opal *ptr = (struct uv_opal *)data;
+ start_uv(ptr->uv_base_addr, ptr);
+}
+
+int start_ultravisor(void)
+{
+ struct cpu_thread *cpu;
+ struct cpu_job **jobs;
+ int i=0;
+
+ prlog(PR_NOTICE, "UV: Starting Ultravisor at 0x%llx sys_fdt 0x%llx uv_fdt 0x%0llx\n",
+ uv_opal->uv_base_addr, uv_opal->sys_fdt, uv_opal->uv_fdt);
+
+ /* Alloc memory for Jobs */
+ jobs = zalloc(sizeof(struct cpu_job*) * cpu_max_pir);
+
+ for_each_available_cpu(cpu) {
+ if (cpu == this_cpu())
+ continue;
+ jobs[i++] = cpu_queue_job(cpu, "start_ultravisor",
+ cpu_start_ultravisor, (void *)uv_opal);
+ }
+
+ cpu_start_ultravisor((void *)uv_opal);
+
+ /* wait for everyone to sync back */
+ while (i > 0) {
+ cpu_wait_job(jobs[--i], true);
+ }
+
+ /* free used stuff */
+ free(jobs);
+
+ /* Check everything is fine */
+ if (uv_opal->uv_ret_code) {
+ return OPAL_HARDWARE;
+ }
+
+ return OPAL_SUCCESS;
+}
+
+static int create_dtb_uv(void *uv_fdt)
+{
+ if (fdt_create(uv_fdt, UV_FDT_MAX_SIZE)) {
+ prerror("UV: Failed to create uv_fdt\n");
+ return 1;
+ }
+
+ fdt_finish_reservemap(uv_fdt);
+ fdt_begin_node(uv_fdt, "");
+ fdt_property_string(uv_fdt, "description", "UV dt");
+ fdt_begin_node(uv_fdt, "ibm,uv-firmware");
+ fdt_property_string(uv_fdt, "compatible", "ibm,uv-v1");
+ fdt_end_node(uv_fdt);
+ fdt_end_node(uv_fdt);
+ fdt_finish(uv_fdt);
+
+ return OPAL_SUCCESS;
+}
+
+/* We could be running on Mambo, Cronus, or Hostboot
+ *
+ * Detect Mambo via chip quirk. Mambo writes the uncompressed UV images
+ * directly to secure memory and passes secure memory location via device tree.
+ *
+ * Detect Cronus when HB decompress fails. Cronus writes the uncompressed UV
+ * image to insecure memory and init_uv will copy from insecure to secure.
+ *
+ * Assume HB by waiting for decompress. UV should have been loaded from FSP
+ * and decompressed earlier via uv_preload_image and uv_decompress_image. The
+ * secure location of the UV provided by those functions in xz struct. */
+void init_uv()
{
struct dt_node *node;
const struct dt_property *base;
+ uint64_t uv_src_addr, uv_pef_reg, uv_pef_size;
+ void *uv_fdt;
- assert(fdt);
+ prlog(PR_NOTICE, "UV: Init starting\n");
- if (!is_msr_bit_set(MSR_S))
+ uv_opal = zalloc(sizeof(struct uv_opal));
+ if (!uv_opal) {
+ prerror("UV: Failed to allocate uv_opal\n");
return;
+ }
+
+ if (!is_msr_bit_set(MSR_S)) {
+ prlog(PR_DEBUG, "UV: S bit not set\n");
+ return;
+ }
- if (!uv_xz)
+ node = find_uv_node();
+ if (!node) {
+ prlog(PR_DEBUG, "UV: Device tree node not found\n");
return;
+ }
+
+ if (proc_chip_quirks & QUIRK_MAMBO_CALLOUTS) {
+ prlog(PR_INFO, "UV: Mambo simulator detected\n");
+
+ if (!find_secure_mem_to_copy(&uv_pef_reg, &uv_pef_size)) {
+ prlog(PR_DEBUG, "UV: No secure memory configured, exiting\n");
+ goto load_error;
+ }
+
+ goto start;
+ }
+
+ /* This would be null in case we are on Mambo or Cronus */
+ if (!uv_xz) {
+
+ prlog(PR_INFO, "UV: Platform load failed, detecting UV image via device tree\n");
+
+ if (!find_secure_mem_to_copy(&uv_pef_reg, &uv_pef_size)) {
+ prlog(PR_DEBUG, "UV: No secure memory configured, exiting\n");
+ goto load_error;
+ }
+
+ uv_src_addr = find_uv_fw_base_addr(node);
+ if (!uv_src_addr) {
+ prlog(PR_DEBUG, "UV: Couldn't find UV base address in device tree\n");
+ goto load_error;
+ }
+ prlog(PR_INFO, "UV: Copying Ultravisor to protected memory 0x%llx from 0x%llx\n", uv_pef_reg, uv_src_addr);
+
+ memcpy((void *)uv_pef_reg, (void *)uv_src_addr, UV_LOAD_MAX_SIZE);
+
+ goto start;
+ }
+
+ /* Hostboot path */
wait_xz_decompress(uv_xz);
- if (uv_xz->status)
+ if (uv_xz->status) {
+ prlog(PR_INFO, "UV: Compressed Ultravisor image failed to decompress");
goto load_error;
+ }
- /* the uncompressed location will be the base address of ultravisor */
- node = find_uv_node();
+ /* the uncompressed location will be the base address of ultravisor
+ * so fix up if it's already there */
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 */
+ uv_pef_reg = (uint64_t)uv_xz->dst;
+ uv_pef_size = (uint64_t)uv_xz->dst_size;
+
+start:
+ uv_opal->uv_base_addr = uv_pef_reg;
+
+ uv_opal->sys_fdt = (__be64)create_dtb(dt_root, false);
+ if (!uv_opal->sys_fdt) {
+ prerror("UV: Failed to create system fdt\n");
+ goto load_error;
+ }
+
+ uv_fdt = (void *)(uv_pef_reg + UV_LOAD_MAX_SIZE);
+ if (create_dtb_uv(uv_fdt)) {
+ prerror("UV: Failed to create uv fdt\n");
+ goto load_error;
+ }
+ uv_opal->uv_fdt = (__be64)uv_fdt;
+
+ reserve_uv_memory(uv_opal);
+
load_error:
free(uv_image);
free(uv_xz);
@@ -190,7 +428,7 @@ void uv_preload_image(void)
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");
+ prerror("UV: Memory allocation for Ultravisor failed\n");
return;
}
diff --git a/include/ultravisor-api.h b/include/ultravisor-api.h
new file mode 100644
index 00000000..52d86024
--- /dev/null
+++ b/include/ultravisor-api.h
@@ -0,0 +1,31 @@
+/* Copyright 2013-2018 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ULTRAVISOR_API_H
+#define __ULTRAVISOR_API_H
+
+struct uv_opal {
+ __be32 magic; /**< 'OPUV' 0x4F505556 OPUV_MAGIC */
+ __be32 version; /**< uv_opal struct version */
+ __be32 uv_ret_code; /**< 0 - Success, <0> : error. */
+ __be32 uv_api_ver; /**< Current uv api version. */
+ __be64 uv_base_addr; /**< Base address of UV in secure memory. */
+ __be64 sys_fdt; /**< System FDT. */
+ __be64 uv_fdt; /**< UV FDT in secure memory. */
+ __be64 uv_mem; /**< struct memcons */
+};
+
+#endif /* __ULTRAVISOR_API_H */
diff --git a/include/ultravisor.h b/include/ultravisor.h
index 08f10da4..976b6323 100644
--- a/include/ultravisor.h
+++ b/include/ultravisor.h
@@ -17,15 +17,24 @@
#ifndef __ULTRAVISOR_H
#define __ULTRAVISOR_H
+#include <ultravisor-api.h>
+
/* 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 */
+#define UV_ACCESS_BIT 0x1ULL << 48
+/* Address at which the Ultravisor is loaded for BML and Mambo */
+#define UV_LOAD_BASE 0xC0000000
+#define UV_LOAD_MAX_SIZE 0x200000
+#define UV_FDT_MAX_SIZE 0x100000
+#define UV_HB_RESERVE_SIZE 0x4000000;
-extern int start_uv(uint64_t entry, void *ptr);
+extern int start_uv(uint64_t entry, struct uv_opal *uv_opal);
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);
+extern void init_uv(void);
+extern int start_ultravisor(void);
#endif /* __ULTRAVISOR_H */
--
2.21.0
More information about the Skiboot
mailing list