aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--asm/head.S6
-rw-r--r--core/stack.c33
-rw-r--r--include/stack.h25
3 files changed, 53 insertions, 11 deletions
diff --git a/asm/head.S b/asm/head.S
index 8049d78..ad30625 100644
--- a/asm/head.S
+++ b/asm/head.S
@@ -359,7 +359,10 @@ boot_entry:
/* Get ready for C code: get a stack */
2: GET_STACK(%r1,%r31)
- /* Clear up initial frame */
+ /* Clear up initial frame.
+ * Zero back chain indicates stack entry from boot,
+ * non-zero indicates entry from OS (see backtrace code).
+ */
li %r3,0
std %r3,0(%r1)
std %r3,8(%r1)
@@ -965,6 +968,7 @@ opal_entry:
stdu %r12,-STACK_FRAMESIZE(%r12)
/* Save caller r1, establish new r1 */
+ std %r1,0(%r12)
std %r1,STACK_GPR1(%r12)
mr %r1,%r12
diff --git a/core/stack.c b/core/stack.c
index e04a4dd..10118e4 100644
--- a/core/stack.c
+++ b/core/stack.c
@@ -29,11 +29,14 @@ static struct bt_entry bt_buf[STACK_BUF_ENTRIES];
extern uint32_t _stext, _etext;
/* Dumps backtrace to buffer */
-void __nomcount __backtrace(struct bt_entry *entries, unsigned int *count)
+void __nomcount ___backtrace(struct bt_entry *entries, unsigned int *count,
+ unsigned long r1,
+ unsigned long *token, unsigned long *r1_caller)
{
unsigned int room = *count;
- unsigned long *fp = __builtin_frame_address(0);
+ unsigned long *fp = (unsigned long *)r1;
unsigned long top_adj = top_of_ram;
+ struct stack_frame *eframe = (struct stack_frame *)fp;
/* Assume one stack for early backtraces */
if (top_of_ram == SKIBOOT_BASE + SKIBOOT_SIZE)
@@ -44,17 +47,26 @@ void __nomcount __backtrace(struct bt_entry *entries, unsigned int *count)
fp = (unsigned long *)fp[0];
if (!fp || (unsigned long)fp > top_adj)
break;
+ eframe = (struct stack_frame *)fp;
entries->sp = (unsigned long)fp;
entries->pc = fp[2];
entries++;
*count = (*count) + 1;
room--;
}
+
+ *r1_caller = eframe->gpr[1];
+
+ if (fp)
+ *token = eframe->gpr[0];
+ else
+ *token = -1UL;
}
-void __print_backtrace(unsigned int pir,
- struct bt_entry *entries, unsigned int count,
- char *out_buf, unsigned int *len, bool symbols)
+void ___print_backtrace(unsigned int pir, struct bt_entry *entries,
+ unsigned int count, unsigned long token,
+ unsigned long r1_caller, char *out_buf,
+ unsigned int *len, bool symbols)
{
static char bt_text_buf[4096];
int i, l = 0, max;
@@ -89,6 +101,10 @@ void __print_backtrace(unsigned int pir,
l += snprintf(buf + l, max - l, "\n");
entries++;
}
+ if (token <= OPAL_LAST)
+ l += snprintf(buf + l, max - l, " --- OPAL call token: 0x%lx caller R1: 0x%016lx ---\n", token, r1_caller);
+ else if (token == -1UL)
+ l += snprintf(buf + l, max - l, " --- OPAL boot ---\n");
if (!out_buf)
write(stdout->fd, bt_text_buf, l);
buf[l++] = 0;
@@ -107,11 +123,14 @@ struct lock bt_lock = LOCK_UNLOCKED;
void backtrace(void)
{
unsigned int ents = STACK_BUF_ENTRIES;
+ unsigned long token, r1_caller;
lock(&bt_lock);
- __backtrace(bt_buf, &ents);
- __print_backtrace(mfspr(SPR_PIR), bt_buf, ents, NULL, NULL, true);
+ ___backtrace(bt_buf, &ents, (unsigned long)__builtin_frame_address(0),
+ &token, &r1_caller);
+ ___print_backtrace(mfspr(SPR_PIR), bt_buf, ents, token, r1_caller,
+ NULL, NULL, true);
unlock(&bt_lock);
}
diff --git a/include/stack.h b/include/stack.h
index df08ac1..4d3e504 100644
--- a/include/stack.h
+++ b/include/stack.h
@@ -49,6 +49,7 @@
#ifndef __ASSEMBLY__
#include <stdint.h>
+#include <opal-api.h>
/* This is the struct used to save GPRs etc.. on OPAL entry
* and from some exceptions. It is not always entirely populated
@@ -108,13 +109,31 @@ struct bt_entry {
extern void *boot_stack_top;
/* Create a backtrace */
-extern void __backtrace(struct bt_entry *entries, unsigned int *count);
+void ___backtrace(struct bt_entry *entries, unsigned int *count,
+ unsigned long r1,
+ unsigned long *token, unsigned long *r1_caller);
+static inline void __backtrace(struct bt_entry *entries, unsigned int *count)
+{
+ unsigned long token, r1_caller;
+
+ ___backtrace(entries, count,
+ (unsigned long)__builtin_frame_address(0),
+ &token, &r1_caller);
+}
/* Convert a backtrace to ASCII */
-extern void __print_backtrace(unsigned int pir, struct bt_entry *entries,
- unsigned int count, char *out_buf,
+extern void ___print_backtrace(unsigned int pir, struct bt_entry *entries,
+ unsigned int count, unsigned long token,
+ unsigned long r1_caller, char *out_buf,
unsigned int *len, bool symbols);
+static inline void __print_backtrace(unsigned int pir, struct bt_entry *entries,
+ unsigned int count, char *out_buf,
+ unsigned int *len, bool symbols)
+{
+ ___print_backtrace(pir, entries, count, OPAL_LAST + 1, 0, out_buf, len, symbols);
+}
+
/* For use by debug code, create and print backtrace, uses a static buffer */
extern void backtrace(void);