diff --git a/core/opal.c b/core/opal.c
index d6ff6027b..d9fc4fe05 100644
--- a/core/opal.c
+++ b/core/opal.c
@@ -142,6 +142,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_GET_SYMBOL:
+		case OPAL_LOOKUP_SYMBOL:
 			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 8fd63fcb7..5f0d5130b 100644
--- a/core/utils.c
+++ b/core/utils.c
@@ -48,40 +48,120 @@ 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 get_symbol(unsigned long addr, char **sym, char **sym_end, unsigned long *size)
 {
 	unsigned long prev = 0, next;
 	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;;
+			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 lookup_symbol(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;
+
+			if (get_symbol(addr, &sym, &sym_end, size) == 0) {
+				assert(!strcmp(name, "_end"));
+				*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_get_symbol(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 = get_symbol(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_GET_SYMBOL, opal_get_symbol, 5);
+
+static int64_t opal_lookup_symbol(const char *name, __be64 *symaddr, __be64 *symsize)
+{
+	unsigned long saddr;
+	unsigned long ssize;
+
+	saddr = lookup_symbol(name, &ssize);
+	if (!saddr)
+		return OPAL_RESOURCE;
+
+	*symaddr = cpu_to_be64(saddr);
+	*symsize = cpu_to_be64(ssize);
+
+	return OPAL_SUCCESS;
+}
+opal_call(OPAL_LOOKUP_SYMBOL, opal_lookup_symbol, 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 = get_symbol(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..a57de6c1c
--- /dev/null
+++ b/doc/opal-api/opal-get-symbol-181.rst
@@ -0,0 +1,42 @@
+.. _OPAL_GET_SYMBOL:
+
+OPAL_GET_SYMBOL
+================
+
+.. code-block:: c
+
+   #define OPAL_GET_SYMBOL			181
+
+   static int64_t opal_get_symbol(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..e9f6eba33
--- /dev/null
+++ b/doc/opal-api/opal-lookup-symbol-182.rst
@@ -0,0 +1,35 @@
+.. _OPAL_LOOKUP_SYMBOL:
+
+OPAL_LOOKUP_SYMBOL
+================
+
+.. code-block:: c
+
+   #define OPAL_LOOKUP_SYMBOL			182
+
+   static int64_t opal_lookup_symbol(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 5b07dea13..4474631a6 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_GET_SYMBOL				181
+#define OPAL_LOOKUP_SYMBOL			182
+#define OPAL_LAST				182
 
 #define QUIESCE_HOLD			1 /* Spin all calls at entry */
 #define QUIESCE_REJECT			2 /* Fail all calls with OPAL_BUSY */
