[Skiboot] [RFC PATCH 2/2] OPAL v4

Nicholas Piggin npiggin at gmail.com
Tue Dec 10 22:29:08 AEDT 2019


I'll call this OPAL v4 for no particularly good reason. The OS provides
servies to OPAL (depends on some of the recent previous patches, but the
concept stands by itself).

To start with for this patch, the OS is to provide logging support and
trap handling (decoding symbols and stack trace, we should grab the trap
message as well actually).

When the OS registers this, skiboot patches its traps back in, and sets
the console to raw mode and no longer uses its console facilities. It calls
the OS to log messages.

The benefit of this is that 1) OPAL messages get into kernel log
facilities, and 2) Linux's path to the console is much shorter, with
no locks or buffering between the kernel and the uart MMIO. Things like
xmon and BUG printing are careful to be as reliable as possible, I've
encountered times when the skiboot console code trips us up here.

Other OS facilities that may be useful:

- Virtual memory facilities. I have this working, but didn't want to cram
  too much in the one patch. The kernel allocates a PID for OPAL calls and
  resurrects the skiboot VM mappings in Q0. This allows skiboot to run with
  memory protection on, which helps with security and robustness.

- Sleep/wake facilities. This is pretty trivial to support, but we have
  to be careful how it's used in skiboot. Have to think about locking and
  re-entrancy. It could potentially avoid painful async APIs.

- Timer facilities. Skiboot could request an OS timer is scheduled which
  then makes an OPAL call with an opaque pointer which skiboot can then
  use to run functions.

- Interrupt enabling... probably not, we'd rather keep calls as short as
  possible. Except perhaps for watchog and perf interrupts.

- Some kind of ftrace and/or kprobes facilities.
---
 core/console-log.c      |  9 +++++++++
 core/console.c          | 11 +++++++++++
 core/fast-reboot.c      |  7 ++++++-
 core/init.c             |  4 +---
 core/opal.c             | 44 +++++++++++++++++++++++++++++++++++++++++
 include/mem_region.h    |  1 +
 include/opal-api.h      | 10 +++++++++-
 include/opal-internal.h |  9 +++++++++
 8 files changed, 90 insertions(+), 5 deletions(-)

diff --git a/core/console-log.c b/core/console-log.c
index 09176afd0..c9ec72e31 100644
--- a/core/console-log.c
+++ b/core/console-log.c
@@ -8,6 +8,7 @@
  * Copyright 2013-2018 IBM Corp.
  */
 
+#include <opal.h>
 #include "skiboot.h"
 #include "unistd.h"
 #include "stdio.h"
@@ -15,6 +16,8 @@
 #include "timebase.h"
 #include <debug_descriptor.h>
 
+extern void os_printf(uint32_t log_level, const char *str);
+
 static int vprlog(int log_level, const char *fmt, va_list ap)
 {
 	int count;
@@ -32,6 +35,12 @@ static int vprlog(int log_level, const char *fmt, va_list ap)
 	if (log_level > (debug_descriptor.console_log_levels >> 4))
 		return 0;
 
+	if (opal_v4_os) {
+		count = vsnprintf(buffer, sizeof(buffer), fmt, ap);
+		os_printf(log_level, buffer);
+		return count;
+	}
+
 	count = snprintf(buffer, sizeof(buffer), "[%5lu.%09lu,%d] ",
 			 tb_to_secs(tb), tb_remaining_nsecs(tb), log_level);
 	count+= vsnprintf(buffer+count, sizeof(buffer)-count, fmt, ap);
diff --git a/core/console.c b/core/console.c
index d72c0c879..b3d36b6ad 100644
--- a/core/console.c
+++ b/core/console.c
@@ -259,8 +259,19 @@ ssize_t console_write(bool flush_to_drivers, const void *buf, size_t count)
 	return count;
 }
 
+extern void os_printf(uint32_t log_level, const char *str);
+
 ssize_t write(int fd __unused, const void *buf, size_t count)
 {
+	if (opal_v4_os) {
+		char *b = malloc(count+1);
+		memcpy(b, buf, count);
+		b[count] = '\0';
+		os_printf(4, b);
+		free(b);
+		return count;
+	}
+
 	return console_write(true, buf, count);
 }
 
diff --git a/core/fast-reboot.c b/core/fast-reboot.c
index 65594efd8..f750d124c 100644
--- a/core/fast-reboot.c
+++ b/core/fast-reboot.c
@@ -312,7 +312,12 @@ void __noreturn fast_reboot_entry(void)
 		/* Restore skiboot vectors */
 		copy_exception_vectors();
 		copy_sreset_vector();
-		patch_traps(true);
+		if (opal_v4_os) {
+			set_opal_console_to_cooked();
+			opal_v4_os = false;
+		} else {
+			patch_traps(true);
+		}
 	}
 
 	/* Must wait for others to because shared SPRs like HID0 are only set
diff --git a/core/init.c b/core/init.c
index 6bc464407..fe1eda55c 100644
--- a/core/init.c
+++ b/core/init.c
@@ -85,8 +85,6 @@ struct debug_descriptor debug_descriptor = {
 #endif
 };
 
-static void checksum_romem(void);
-
 static bool try_load_elf64_le(struct elf_hdr *header)
 {
 	struct elf64le_hdr *kh = (struct elf64le_hdr *)header;
@@ -1027,7 +1025,7 @@ static uint32_t mem_csum(void *_p, void *_e)
 
 static uint32_t romem_csum;
 
-static void checksum_romem(void)
+void checksum_romem(void)
 {
 	uint32_t csum;
 
diff --git a/core/opal.c b/core/opal.c
index 44345bcae..bb88d7710 100644
--- a/core/opal.c
+++ b/core/opal.c
@@ -23,6 +23,7 @@
 #include <elf-abi.h>
 #include <errorlog.h>
 #include <occ.h>
+#include <mem_region.h>
 
 /* Pending events to signal via opal_poll_events */
 uint64_t opal_pending_events;
@@ -415,6 +416,49 @@ static int64_t opal_v4_le_entry(uint64_t r3, uint64_t r4, uint64_t r5,
 	return r3;
 }
 
+bool opal_v4_os = false;
+struct os_ops os_ops;
+
+static int64_t opal_register_opal_ops(struct opal_os_ops *__os_ops)
+{
+	struct cpu_thread *cpu;
+
+	for_each_cpu(cpu) {
+		if (cpu == this_cpu())
+			continue;
+		if (cpu->state == cpu_state_os)
+			return OPAL_BUSY;
+	}
+
+	if (opal_v4_os)
+		return OPAL_WRONG_STATE;
+
+	if (!verify_romem()) {
+		prlog(PR_NOTICE, "OPAL checksums did not match\n");
+		disable_fast_reboot("Inconsistent firmware romem checksum");
+	}
+
+	/* v4 must handle OPAL traps */
+	patch_traps(true);
+
+	/* v4 must provide printf */
+	os_ops.os_printf = (void *)be64_to_cpu(__os_ops->os_printf);
+
+	set_opal_console_to_raw();
+
+	checksum_romem();
+
+	opal_v4_os = true;
+
+	return OPAL_SUCCESS;
+}
+opal_call(OPAL_REGISTER_OS_OPS, opal_register_opal_ops, 1);
+
+void os_printf(uint32_t log_level, const char *str)
+{
+	os_ops.os_printf(log_level, str);
+}
+
 void add_opal_node(void)
 {
 	uint64_t base, entry, size;
diff --git a/include/mem_region.h b/include/mem_region.h
index df8d03f01..3904f95eb 100644
--- a/include/mem_region.h
+++ b/include/mem_region.h
@@ -73,6 +73,7 @@ struct mem_region *find_mem_region(const char *name);
 bool mem_range_is_reserved(uint64_t start, uint64_t size);
 
 /* Read-only memory checksum */
+void checksum_romem(void);
 bool verify_romem(void);
 
 #endif /* __MEMORY_REGION */
diff --git a/include/opal-api.h b/include/opal-api.h
index 4474631a6..d7c2368a1 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -229,7 +229,8 @@
 #define OPAL_PHB_GET_OPTION			180
 #define OPAL_GET_SYMBOL				181
 #define OPAL_LOOKUP_SYMBOL			182
-#define OPAL_LAST				182
+#define OPAL_REGISTER_OS_OPS			183
+#define OPAL_LAST				183
 
 #define QUIESCE_HOLD			1 /* Spin all calls at entry */
 #define QUIESCE_REJECT			2 /* Fail all calls with OPAL_BUSY */
@@ -1256,6 +1257,13 @@ struct opal_mpipl_fadump {
 	struct	opal_mpipl_region region[];
 };
 
+struct opal_os_ops {
+        __be16  version;
+        __be16  reserved0;
+        __be32  reserved1;
+        __be64  os_printf;      /* void printf(int32_t level, const char *str) */
+};
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __OPAL_API_H */
diff --git a/include/opal-internal.h b/include/opal-internal.h
index 83bf77084..cd968a0fe 100644
--- a/include/opal-internal.h
+++ b/include/opal-internal.h
@@ -18,6 +18,15 @@ struct opal_table_entry {
 	u32	nargs;
 };
 
+struct os_ops {
+        void (*os_printf)(uint32_t log_level, const char *str);
+};
+
+extern bool opal_v4_os;
+extern struct os_ops os_ops;
+
+extern void os_printf(uint32_t log_level, const char *str);
+
 #ifdef __CHECKER__
 #define __opal_func_test_arg(__func, __nargs) 0
 #else
-- 
2.23.0



More information about the Skiboot mailing list