diff options
-rw-r--r-- | core/backtrace.c | 90 | ||||
-rw-r--r-- | core/cpu.c | 10 | ||||
-rw-r--r-- | hw/fsp/fsp-attn.c | 12 | ||||
-rw-r--r-- | include/cpu.h | 4 | ||||
-rw-r--r-- | include/skiboot.h | 12 | ||||
-rw-r--r-- | include/stack.h | 26 | ||||
-rw-r--r-- | skiboot.lds.S | 4 |
7 files changed, 114 insertions, 44 deletions
diff --git a/core/backtrace.c b/core/backtrace.c index c4c8546..9b75186 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); } @@ -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 755b95d..036962c 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 8cb17be..6c8274c 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 53660af..8750c70 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 57771b4..d4664dd 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 82cbdb2..4e905f8 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.*) |