On Fri, Feb 28, 2020 at 2:09 PM Nicholas Piggin <npig...@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 <npig...@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 >