[Skiboot] [RFC PATCH v7 02/12] Add functions to initialize and start an ultravisor

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


Power 9 introduces a mode called ultravisor mode.

init_uv looks for uv-src-address in the device tree and copies the image
to the address specified in "reg".

start_ultravisor is called in load_and_boot_kernel with the pointer to
the system fdt.

Every thread is sent to the ultravisor image and returns with UV mode
off.

A minimal ultravisor could disable UV and PEF, instructions in commit
"skiboot.tcl: ultravisor support."

[ maddy: Initial implementation]
[Signed-off-by: Madhavan Srinivasan <maddy at linux.vnet.ibm.com>
[ santosh: Initial implementation]
Signed-off-by: Santosh Sivaraj <santosh at fossix.org>
Signed-off-by: Ryan Grimm <grimm at us.ibm.com>
---
 asm/misc.S           | 21 ++++++++++
 core/init.c          |  7 +++-
 hw/Makefile.inc      |  2 +-
 hw/ultravisor.c      | 93 ++++++++++++++++++++++++++++++++++++++++++++
 include/processor.h  |  7 ++++
 include/ultravisor.h | 35 +++++++++++++++++
 6 files changed, 162 insertions(+), 3 deletions(-)
 create mode 100644 hw/ultravisor.c
 create mode 100644 include/ultravisor.h

diff --git a/asm/misc.S b/asm/misc.S
index 03344897..30f67872 100644
--- a/asm/misc.S
+++ b/asm/misc.S
@@ -306,3 +306,24 @@ exit_uv_mode:
 	mtspr	SPR_USRR0,%r4
 
 	PPC_INST_URFID
+/*
+ *  start_uv register usage:
+ *
+ *  r3 : UV entry addr
+ *  r4 : system fdt
+ */
+.global enter_uv
+enter_uv:
+	mflr    %r0
+	std     %r0,16(%r1)
+	sync
+	/* flush caches, etc */
+	icbi    0,%r3
+	sync
+	isync
+	mtctr   %r3
+	mr      %r3,%r4
+	bctrl			/* branch to UV here */
+	ld      %r0,16(%r1)
+	mtlr    %r0
+	blr
diff --git a/core/init.c b/core/init.c
index 07e3092f..e0166098 100644
--- a/core/init.c
+++ b/core/init.c
@@ -47,6 +47,7 @@
 #include <debug_descriptor.h>
 #include <occ.h>
 #include <opal-dump.h>
+#include <ultravisor.h>
 
 enum proc_gen proc_gen;
 unsigned int pcie_max_link_speed;
@@ -603,6 +604,8 @@ void __noreturn load_and_boot_kernel(bool is_reboot)
 		abort();
 	}
 
+	start_ultravisor(fdt);
+
 	op_display(OP_LOG, OP_MOD_INIT, 0x000C);
 
 	mem_dump_free();
@@ -1369,8 +1372,8 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt)
 	/* Add the list of interrupts going to OPAL */
 	add_opal_interrupts();
 
-	/* Disable protected execution facility in BML */
-	cpu_disable_pef();
+	/* Initialize the ultravisor */
+	init_uv();
 
 	/* Now release parts of memory nodes we haven't used ourselves... */
 	mem_region_release_unused();
diff --git a/hw/Makefile.inc b/hw/Makefile.inc
index a7f450cf..f5408735 100644
--- a/hw/Makefile.inc
+++ b/hw/Makefile.inc
@@ -9,7 +9,7 @@ HW_OBJS += fake-nvram.o lpc-mbox.o npu2.o npu2-hw-procedures.o
 HW_OBJS += npu2-common.o npu2-opencapi.o phys-map.o sbe-p9.o capp.o
 HW_OBJS += occ-sensor.o vas.o sbe-p8.o dio-p9.o lpc-port80h.o cache-p9.o
 HW_OBJS += npu-opal.o npu3.o npu3-nvlink.o npu3-hw-procedures.o
-HW_OBJS += ocmb.o
+HW_OBJS += ocmb.o ultravisor.o
 HW=hw/built-in.a
 
 include $(SRC)/hw/fsp/Makefile.inc
diff --git a/hw/ultravisor.c b/hw/ultravisor.c
new file mode 100644
index 00000000..1be47ec5
--- /dev/null
+++ b/hw/ultravisor.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: Apache-2.0
+/* Copyright 2018-2019 IBM Corp. */
+
+#include <ultravisor.h>
+#include <device.h>
+#include <stdlib.h>
+#include <skiboot.h>
+#include <processor.h>
+#include <opal-api.h>
+#include <cpu.h>
+
+static struct dt_node *uv_fw_node;
+static uint64_t uv_base_addr;
+bool uv_present;
+
+static void cpu_start_ultravisor(void *fdt)
+{
+	uint64_t uv_entry = 0;
+
+	if (dt_find_property(uv_fw_node, "uv-entry"))
+		uv_entry = dt_prop_get_u64(uv_fw_node, "uv-entry");
+
+	prlog(PR_DEBUG, "UV: Starting on CPU 0x%04x\n", this_cpu()->pir);
+	enter_uv(uv_base_addr + uv_entry, fdt);
+}
+
+int start_ultravisor(void *fdt)
+{
+	struct cpu_thread *cpu;
+	struct cpu_job **jobs;
+	int i = 0;
+
+	if (!uv_base_addr || !fdt) {
+		prlog(PR_DEBUG, "UV: uv_base_addr 0x%llx or fdt %p not set\n",
+					uv_base_addr, fdt);
+		return OPAL_INTERNAL_ERROR;
+	}
+
+	jobs = zalloc(sizeof(struct cpu_job *) * cpu_max_pir);
+
+	prlog(PR_DEBUG, "UV: Starting @0x%016llx fdt %p\n",
+				uv_base_addr, fdt);
+
+	for_each_available_cpu(cpu) {
+		if (cpu == this_cpu())
+			continue;
+		jobs[i++] = cpu_queue_job(cpu, "start_ultravisor",
+					cpu_start_ultravisor, fdt);
+	}
+
+	cpu_start_ultravisor(fdt);
+
+	uv_present = true;
+
+	while (i > 0)
+		cpu_wait_job(jobs[--i], true);
+
+	free(jobs);
+
+	return OPAL_SUCCESS;
+}
+
+void init_uv()
+{
+	uint64_t uv_dt_src, uv_fw_sz;
+	struct dt_node *reserved_mem;
+
+	if (!is_msr_bit_set(MSR_S)) {
+		prlog(PR_DEBUG, "UV: S bit not set\n");
+		return;
+	}
+
+	uv_fw_node = dt_find_compatible_node(dt_root, NULL, "ibm,uv-firmware");
+	if (!uv_fw_node) {
+		prlog(PR_DEBUG, "UV: No ibm,uv-firmware node found, disabling pef\n");
+		cpu_disable_pef();
+		return;
+	}
+
+	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);
+
+	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);
+}
diff --git a/include/processor.h b/include/processor.h
index ddec6c04..cb81aabb 100644
--- a/include/processor.h
+++ b/include/processor.h
@@ -397,6 +397,13 @@ static inline void st_le32(uint32_t *addr, uint32_t val)
 	asm volatile("stwbrx %0,0,%1" : : "r"(val), "r"(addr), "m"(*addr));
 }
 
+static inline bool is_msr_bit_set(uint64_t bit)
+{
+	if (mfmsr() & bit)
+		return true;
+	return false;
+}
+
 #endif /* __TEST__ */
 
 #endif /* __ASSEMBLY__ */
diff --git a/include/ultravisor.h b/include/ultravisor.h
new file mode 100644
index 00000000..05edb53e
--- /dev/null
+++ b/include/ultravisor.h
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: Apache-2.0
+/* Copyright 2018-2019 IBM Corp. */
+
+#ifndef __ULTRAVISOR_H
+#define __ULTRAVISOR_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <types.h>
+
+/*
+ * enter_uv: Each thread enters ultravisor and exits with S=0
+ * @entry: Offset into ultravisor image for threads to jump to
+ * @fdt: Flattened system device tree
+ *
+ * All threads sent here by skiboot from C code
+ *
+ * return value: 0 on success, non-zero on failure
+ */
+extern int enter_uv(uint64_t entry, void *fdt);
+
+/*
+ * start_ultravisor: Start the ultravisor on all threads
+ * @fdt: Flattened system device tree
+ *
+ * return value: 0 on success, non-zero on failure
+ */
+int start_ultravisor(void *fdt);
+
+/* Set when ultravisor started, so code knows to make a ucall */
+extern bool uv_present;
+
+void init_uv(void);
+
+#endif /* __ULTRAVISOR_H */
-- 
2.21.0



More information about the Skiboot mailing list