diff mbox series

[RFC,2/9] Add OPAL_SYM_TO_ADDR and OPAL_ADDR_TO_SYM

Message ID 20200502113649.176329-3-npiggin@gmail.com
State New
Headers show
Series OPAL V4 | expand

Checks

Context Check Description
snowpatch_ozlabs/apply_patch success Successfully applied on branch master (0f1937ef40fca0c3212a9dff1010b832a24fb063)
snowpatch_ozlabs/snowpatch_job_snowpatch-skiboot success Test snowpatch/job/snowpatch-skiboot on branch master
snowpatch_ozlabs/snowpatch_job_snowpatch-skiboot-dco success Signed-off-by present

Commit Message

Nicholas Piggin May 2, 2020, 11:36 a.m. UTC
These calls can be used by Linux to annotate BUG addresses with symbols,
look up symbol addresses in xmon, etc.

This is preferable over having Linux parse the OPAL symbol map itself,
because OPAL's parsing code already exists for its own symbol printing,
and it can support other code regions than the skiboot symbols, e.g.,
the wake-up code in the HOMER (where CPUs have been seen to get stuck).

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 core/opal.c                             |   2 +
 core/utils.c                            | 102 ++++++++++++++++++++++--
 doc/opal-api/opal-get-symbol-181.rst    |  42 ++++++++++
 doc/opal-api/opal-lookup-symbol-182.rst |  35 ++++++++
 include/opal-api.h                      |   4 +-
 5 files changed, 177 insertions(+), 8 deletions(-)
 create mode 100644 doc/opal-api/opal-get-symbol-181.rst
 create mode 100644 doc/opal-api/opal-lookup-symbol-182.rst
diff mbox series

Patch

diff --git a/core/opal.c b/core/opal.c
index 97b5f89a8..864c244cc 100644
--- a/core/opal.c
+++ b/core/opal.c
@@ -162,6 +162,8 @@  int64_t opal_entry_check(struct stack_frame *eframe)
 		case OPAL_CEC_REBOOT:
 		case OPAL_CEC_REBOOT2:
 		case OPAL_SIGNAL_SYSTEM_RESET:
+		case OPAL_ADDR_TO_SYM:
+		case OPAL_SYM_TO_ADDR:
 			break;
 		default:
 			printf("CPU ATTEMPT TO RE-ENTER FIRMWARE! PIR=%04lx cpu @%p -> pir=%04x token=%llu\n",
diff --git a/core/utils.c b/core/utils.c
index d778fcdff..d53bcf374 100644
--- a/core/utils.c
+++ b/core/utils.c
@@ -52,40 +52,128 @@  char __attrconst tohex(uint8_t nibble)
 	return __tohex[nibble];
 }
 
-static unsigned long get_symbol(unsigned long addr, char **sym, char **sym_end)
+static unsigned long addr_to_sym(unsigned long addr, char **sym, char **sym_end, unsigned long *size)
 {
-	unsigned long prev = 0, next;
+	unsigned long prev = 0, next = 0;
 	char *psym = NULL, *p = __sym_map_start;
 
 	*sym = *sym_end = NULL;
-	while(p < __sym_map_end) {
+
+	while (p < __sym_map_end) {
 		next = strtoul(p, &p, 16) | SKIBOOT_BASE;
 		if (next > addr && prev <= addr) {
-			p = psym + 3;;
+			if (!psym)
+				return 0;
+			p = psym + 3;
 			if (p >= __sym_map_end)
 				return 0;
 			*sym = p;
-			while(p < __sym_map_end && *p != 10)
+			while (p < __sym_map_end && *p != '\n')
 				p++;
 			*sym_end = p;
+			*size = next - prev;
+
 			return prev;
 		}
+
 		prev = next;
 		psym = p;
-		while(p < __sym_map_end && *p != 10)
+		while (p < __sym_map_end && *p != '\n')
+			p++;
+		p++;
+	}
+
+	return 0;
+}
+
+static unsigned long sym_to_addr(const char *name, unsigned long *size)
+{
+	size_t len = strlen(name);
+	unsigned long addr = 0;
+	char *sym;
+	char *p = __sym_map_start;
+
+	while (p < __sym_map_end) {
+		addr = strtoul(p, &p, 16) | SKIBOOT_BASE;
+		p += 3;
+		if (p >= __sym_map_end)
+			return 0;
+
+		if (*(p + len) == '\n' && !strncmp(name, p, len)) {
+			char *sym_end;
+
+			/* Now get the size */
+			if (addr_to_sym(addr, &sym, &sym_end, size) == 0) {
+				if (strcmp(name, "_end"))
+					printf("sym_to_addr: name=%s p=%p addr=%lx addr_to_sym failed\n", name, p, addr);
+				*size = 0;
+			}
+
+			/*
+			 * May be more than one symbol at this address but
+			 * symbol length calculation should still work in
+			 * that case.
+			 */
+
+			return addr;
+		}
+
+		while (p < __sym_map_end && *p != '\n')
 			p++;
 		p++;
 	}
 	return 0;
 }
 
+static int64_t opal_addr_to_sym(uint64_t addr, __be64 *symaddr, __be64 *symsize, char *namebuf, uint64_t buflen)
+{
+	unsigned long saddr;
+	unsigned long ssize;
+	char *sym, *sym_end;
+	size_t l;
+
+	saddr = addr_to_sym(addr, &sym, &sym_end, &ssize);
+	if (!saddr)
+		return OPAL_RESOURCE;
+
+	if (buflen > sym_end - sym)
+		l = sym_end - sym;
+	else
+		l = buflen - 1;
+	memcpy(namebuf, sym, l);
+	namebuf[l] = '\0';
+
+	*symaddr = cpu_to_be64(saddr);
+	*symsize = cpu_to_be64(ssize);
+
+	return OPAL_SUCCESS;
+}
+opal_call(OPAL_ADDR_TO_SYM, opal_addr_to_sym, 5);
+
+static int64_t opal_sym_to_addr(const char *name, __be64 *symaddr, __be64 *symsize)
+{
+	unsigned long saddr;
+	unsigned long ssize;
+
+	saddr = sym_to_addr(name, &ssize);
+	if (!saddr)
+		return OPAL_RESOURCE;
+
+	*symaddr = cpu_to_be64(saddr);
+	*symsize = cpu_to_be64(ssize);
+
+	return OPAL_SUCCESS;
+}
+opal_call(OPAL_SYM_TO_ADDR, opal_sym_to_addr, 3);
+
 size_t snprintf_symbol(char *buf, size_t len, uint64_t addr)
 {
 	unsigned long saddr;
+	unsigned long ssize;
 	char *sym, *sym_end;
 	size_t l;
 
-	saddr = get_symbol(addr, &sym, &sym_end);
+	saddr = addr_to_sym(addr, &sym, &sym_end, &ssize);
 	if (!saddr)
 		return 0;
 
diff --git a/doc/opal-api/opal-get-symbol-181.rst b/doc/opal-api/opal-get-symbol-181.rst
new file mode 100644
index 000000000..00ff18431
--- /dev/null
+++ b/doc/opal-api/opal-get-symbol-181.rst
@@ -0,0 +1,42 @@ 
+.. _OPAL_ADDR_TO_SYM:
+
+OPAL_ADDR_TO_SYM
+================
+
+.. code-block:: c
+
+   #define OPAL_ADDR_TO_SYM			181
+
+   static int64_t opal_addr_to_sym(uint64_t addr, __be64 *symaddr, __be64 *symsize, char *namebuf, uint64_t buflen);
+
+This OPAL call looks up a firmware code address for symbol information.
+
+Arguments
+---------
+
+  ``addr``
+    Contains address to be looked up.
+
+  ``symaddr``
+    Returns the start address of the symbol for the object which
+    contains addr or immediately precedes addr.
+
+  ``symsize``
+    Returns the size of the object, or the number of bytes until the
+    next symbol.
+
+  ``namebuf``
+    Contains a buffer for the symbol name to be copied into, as a NUL
+    terminated string.
+
+  ``buflen``
+    Contains the length of the bufer that may be used.
+
+
+Returns
+-------
+
+:ref:`OPAL_SUCCESS`
+  Found a symbol.
+:ref:`OPAL_RESOURCE`
+  Did not find a symbol.
diff --git a/doc/opal-api/opal-lookup-symbol-182.rst b/doc/opal-api/opal-lookup-symbol-182.rst
new file mode 100644
index 000000000..06ab4baff
--- /dev/null
+++ b/doc/opal-api/opal-lookup-symbol-182.rst
@@ -0,0 +1,35 @@ 
+.. _OPAL_SYM_TO_ADDR:
+
+OPAL_SYM_TO_ADDR
+================
+
+.. code-block:: c
+
+   #define OPAL_SYM_TO_ADDR			182
+
+   static int64_t opal_sym_to_addr(const char *name, __be64 *symaddr, __be64 *symsize);
+
+This OPAL call looks up a firmware symbol name for its address.
+
+Arguments
+---------
+
+  ``name``
+    Contains a pointer to NUL terminated symbol name to be looked up.
+
+  ``symaddr``
+    Returns the start address of the symbol for the object which
+    contains addr or immediately precedes addr.
+
+  ``symsize``
+    Returns the size of the object, or the number of bytes until the
+    next symbol.
+
+
+Returns
+-------
+
+:ref:`OPAL_SUCCESS`
+  Found a symbol.
+:ref:`OPAL_RESOURCE`
+  Did not find a symbol.
diff --git a/include/opal-api.h b/include/opal-api.h
index e90cab1e9..ab8fc721f 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -227,7 +227,9 @@ 
 #define OPAL_SECVAR_ENQUEUE_UPDATE		178
 #define OPAL_PHB_SET_OPTION			179
 #define OPAL_PHB_GET_OPTION			180
-#define OPAL_LAST				180
+#define OPAL_ADDR_TO_SYM			181
+#define OPAL_SYM_TO_ADDR			182
+#define OPAL_LAST				182
 
 #define QUIESCE_HOLD			1 /* Spin all calls at entry */
 #define QUIESCE_REJECT			2 /* Fail all calls with OPAL_BUSY */