Add OPAL_GET_SYMBOL / OPAL_LOOKUP_SYMBOL
diff mbox series

Message ID 20200228030751.271382-1-npiggin@gmail.com
State New
Headers show
Series
  • Add OPAL_GET_SYMBOL / OPAL_LOOKUP_SYMBOL
Related show

Checks

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

Commit Message

Nicholas Piggin Feb. 28, 2020, 3:07 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                            | 92 +++++++++++++++++++++++--
 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, 168 insertions(+), 7 deletions(-)
 create mode 100644 doc/opal-api/opal-get-symbol-181.rst
 create mode 100644 doc/opal-api/opal-lookup-symbol-182.rst

Comments

Oliver O'Halloran March 6, 2020, 2:42 a.m. UTC | #1
On Fri, Feb 28, 2020 at 2:09 PM Nicholas Piggin <npiggin@gmail.com> wrote:
>
> 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                            | 92 +++++++++++++++++++++++--
>  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, 168 insertions(+), 7 deletions(-)
>  create mode 100644 doc/opal-api/opal-get-symbol-181.rst
>  create mode 100644 doc/opal-api/opal-lookup-symbol-182.rst
>
> 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:

These names are still awful :|

>                         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 */
> --
> 2.23.0
>
Nicholas Piggin March 7, 2020, 12:15 a.m. UTC | #2
Oliver O'Halloran's on March 6, 2020 12:42 pm:
> On Fri, Feb 28, 2020 at 2:09 PM Nicholas Piggin <npiggin@gmail.com> wrote:
>>
>> 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                            | 92 +++++++++++++++++++++++--
>>  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, 168 insertions(+), 7 deletions(-)
>>  create mode 100644 doc/opal-api/opal-get-symbol-181.rst
>>  create mode 100644 doc/opal-api/opal-lookup-symbol-182.rst
>>
>> 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:
> 
> These names are still awful :|

Ah yeah sorry I said I'd change them didn't I? Anyway don't merge before
the kernel is on board with the idea.

Thanks,
Nick

Patch
diff mbox series

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 */