summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/backtrace.c90
-rw-r--r--core/cpu.c10
-rw-r--r--hw/fsp/fsp-attn.c12
-rw-r--r--include/cpu.h4
-rw-r--r--include/skiboot.h12
-rw-r--r--include/stack.h26
-rw-r--r--skiboot.lds.S4
7 files changed, 114 insertions, 44 deletions
diff --git a/core/backtrace.c b/core/backtrace.c
index c4c85467..9b751865 100644
--- a/core/backtrace.c
+++ b/core/backtrace.c
@@ -18,43 +18,85 @@
#include <skiboot.h>
#include <processor.h>
#include <cpu.h>
+#include <stack.h>
-/* Upto 10 frames each of length 40 bytes + header = 440 bytes */
-#define STACK_BUF_SZ 440
-static char backtrace_buffer[STACK_BUF_SZ];
+#define STACK_BUF_ENTRIES 20
+static struct bt_entry bt_buf[STACK_BUF_ENTRIES];
+
+extern uint32_t _stext, _etext;
/* Dumps backtrace to buffer */
-void __nomcount __backtrace(char *bt_buf, int bt_buf_len)
+void __nomcount __backtrace(struct bt_entry *entries, unsigned int *count)
{
- unsigned int pir = mfspr(SPR_PIR);
- unsigned long *sp;
- unsigned long *bottom, *top;
- char *buf;
- int len = 0;
+ unsigned int room = *count;
+ unsigned int i = 1; /* Start at level 1 */
- /* Check if there's a __builtin_something instead */
- asm("mr %0,1" : "=r" (sp));
+ *count = 0;
+ while(room) {
+ unsigned long pc,
+ fp = (unsigned long)__builtin_frame_address(i);
+ if (!fp)
+ break;
+ pc = (unsigned long)__builtin_return_address(i);
+ entries->sp = fp;
+ entries->pc = pc;
+ entries++;
+ *count = (*count) + 1;
+ room--;
+ }
+}
+
+void __print_backtrace(unsigned int pir,
+ struct bt_entry *entries, unsigned int count,
+ char *out_buf, unsigned int *len)
+{
+ int i, l = 0, max;
+ char *buf = out_buf;
+ unsigned long bottom, top, tbot, ttop;
+ char mark;
+
+ if (len)
+ max = *len - 1;
+ else
+ max = INT_MAX;
bottom = cpu_stack_bottom(pir);
top = cpu_stack_top(pir);
+ tbot = (unsigned long)&_stext;
+ ttop = (unsigned long)&_etext;
- if (!bt_buf || !bt_buf_len)
- return;
-
- buf = bt_buf;
- len += snprintf(buf, bt_buf_len, "CPU %08x Backtrace:\n", pir);
- /* XXX Handle SMP */
- while (sp > bottom && sp < top) {
- len += snprintf(buf + len, bt_buf_len - len, " S: %016lx "
- "R: %016lx\n", (unsigned long)sp, sp[2]);
- sp = (unsigned long *)sp[0];
+ if (buf)
+ l += snprintf(buf, max, "CPU %04x Backtrace:\n", pir);
+ else
+ l += printf("CPU %04x Backtrace:\n", pir);
+ for (i = 0; i < count && l < max; i++) {
+ if (entries->sp < bottom || entries->sp > top)
+ mark = '!';
+ else if (entries->pc < tbot || entries->pc > ttop)
+ mark = '*';
+ else
+ mark = ' ';
+ if (buf)
+ l += snprintf(buf + l, max - l,
+ " S: %016lx R: %016lx %c\n",
+ entries->sp, entries->pc, mark);
+ else
+ l += printf(" S: %016lx R: %016lx %c\n",
+ entries->sp, entries->pc, mark);
+ entries++;
}
+ if (buf)
+ buf[l++] = 0;
+ else
+ l++;
+ if (len)
+ *len = l;
}
void backtrace(void)
{
- memset(backtrace_buffer, 0, STACK_BUF_SZ);
- __backtrace(backtrace_buffer, STACK_BUF_SZ);
+ unsigned int ents = STACK_BUF_ENTRIES;
- fputs(backtrace_buffer, stderr);
+ __backtrace(bt_buf, &ents);
+ __print_backtrace(mfspr(SPR_PIR), bt_buf, ents, NULL, NULL);
}
diff --git a/core/cpu.c b/core/cpu.c
index aa046cc1..5e60da2e 100644
--- a/core/cpu.c
+++ b/core/cpu.c
@@ -57,19 +57,21 @@ struct cpu_job {
};
/* attribute const as cpu_stacks is constant. */
-void __attrconst *cpu_stack_bottom(unsigned int pir)
+unsigned long __attrconst cpu_stack_bottom(unsigned int pir)
{
- return (void *)&cpu_stacks[pir] + sizeof(struct cpu_thread);
+ return ((unsigned long)&cpu_stacks[pir]) +
+ sizeof(struct cpu_thread) + STACK_SAFETY_GAP;
}
-void __attrconst *cpu_stack_top(unsigned int pir)
+unsigned long __attrconst cpu_stack_top(unsigned int pir)
{
/* This is the top of the MC stack which is above the normal
* stack, which means a SP between cpu_stack_bottom() and
* cpu_stack_top() can either be a normal stack pointer or
* a Machine Check stack pointer
*/
- return (void *)&cpu_stacks[pir] + STACK_SIZE - STACK_TOP_GAP;
+ return ((unsigned long)&cpu_stacks[pir]) +
+ NORMAL_STACK_SIZE - STACK_TOP_GAP;
}
void __nomcount cpu_relax(void)
diff --git a/hw/fsp/fsp-attn.c b/hw/fsp/fsp-attn.c
index 755b95da..036962cd 100644
--- a/hw/fsp/fsp-attn.c
+++ b/hw/fsp/fsp-attn.c
@@ -18,6 +18,8 @@
#include <fsp-elog.h>
#include <fsp-attn.h>
#include <hdata/spira.h>
+#include <stack.h>
+#include <processor.h>
#define TI_CMD_VALID 0x1 /* Command valid */
#define TI_CMD 0xA1 /* Terminate Immediate command */
@@ -88,6 +90,10 @@ static void init_sp_attn_area(void)
*/
void update_sp_attn_area(const char *msg)
{
+#define STACK_BUF_ENTRIES 20
+ struct bt_entry bt_buf[STACK_BUF_ENTRIES];
+ unsigned int ent_cnt, len;
+
if (!fsp_present())
return;
@@ -99,7 +105,11 @@ void update_sp_attn_area(const char *msg)
(uint32_t)((uint64_t)__builtin_return_address(0) & 0xffffffff);
snprintf(ti_attn->msg.gitid, GITID_LEN, "%s", gitid);
- __backtrace(ti_attn->msg.bt_buf, BT_FRAME_LEN);
+ ent_cnt = STACK_BUF_ENTRIES;
+ __backtrace(bt_buf, &ent_cnt);
+ len = BT_FRAME_LEN;
+ __print_backtrace(mfspr(SPR_PIR), bt_buf, ent_cnt,
+ ti_attn->msg.bt_buf, &len);
snprintf(ti_attn->msg.file_info, FILE_INFO_LEN, "%s", msg);
ti_attn->msg_len = GITID_LEN + BT_FRAME_LEN +
diff --git a/include/cpu.h b/include/cpu.h
index 8cb17beb..6c8274cc 100644
--- a/include/cpu.h
+++ b/include/cpu.h
@@ -208,7 +208,7 @@ static inline void cpu_give_self_os(void)
__this_cpu->state = cpu_state_os;
}
-extern void *cpu_stack_bottom(unsigned int pir);
-extern void *cpu_stack_top(unsigned int pir);
+extern unsigned long cpu_stack_bottom(unsigned int pir);
+extern unsigned long cpu_stack_top(unsigned int pir);
#endif /* __CPU_H */
diff --git a/include/skiboot.h b/include/skiboot.h
index 53660af8..8750c70a 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -116,18 +116,6 @@ enum proc_gen {
};
extern enum proc_gen proc_gen;
-/* Boot stack top */
-extern void *boot_stack_top;
-
-/* For use by debug code */
-extern void backtrace(void);
-extern void __backtrace(char *bt_buf, int bt_buf_len);
-#ifdef STACK_CHECK_ENABLED
-extern void check_stacks(void);
-#else
-static inline void check_stacks(void) { }
-#endif
-
/* Convert a 4-bit number to a hex char */
extern char tohex(uint8_t nibble);
diff --git a/include/stack.h b/include/stack.h
index 57771b4d..d4664dd6 100644
--- a/include/stack.h
+++ b/include/stack.h
@@ -99,6 +99,32 @@ struct stack_frame {
uint64_t srr1;
} __attribute__((aligned(16)));
+/* Backtrace */
+struct bt_entry {
+ unsigned long sp;
+ unsigned long pc;
+};
+
+/* Boot stack top */
+extern void *boot_stack_top;
+
+/* Create a backtrace */
+extern void __backtrace(struct bt_entry *entries, unsigned int *count);
+
+/* Convert a backtrace to ASCII */
+extern void __print_backtrace(unsigned int pir, struct bt_entry *entries,
+ unsigned int count, char *out_buf,
+ unsigned int *len);
+
+/* For use by debug code, create and print backtrace, uses a static buffer */
+extern void backtrace(void);
+
+#ifdef STACK_CHECK_ENABLED
+extern void check_stacks(void);
+#else
+static inline void check_stacks(void) { }
+#endif
+
#endif /* __ASSEMBLY__ */
#endif /* __STACKFRAME_H */
diff --git a/skiboot.lds.S b/skiboot.lds.S
index 82cbdb28..4e905f87 100644
--- a/skiboot.lds.S
+++ b/skiboot.lds.S
@@ -47,11 +47,13 @@ SECTIONS
}
. = ALIGN(0x10);
+ _stext = .;
.text : {
*(.text*)
*(.sfpr)
}
-
+ _etext = .;
+
.rodata : {
__rodata_start = .;
*(.rodata .rodata.*)
OpenPOWER on IntegriCloud