1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/kernel.h>
3 #include <linux/string.h>
4 #include <linux/ctype.h>
5 #include <asm/stacktrace.h>
6 #include <asm/boot_data.h>
7 #include <asm/lowcore.h>
14 const char hex_asc
[] = "0123456789abcdef";
16 static char *as_hex(char *dst
, unsigned long val
, int pad
)
18 char *p
, *end
= p
= dst
+ max(pad
, (int)__fls(val
| 1) / 4 + 1);
20 for (*p
-- = 0; p
>= dst
; val
>>= 4)
21 *p
-- = hex_asc
[val
& 0x0f];
25 static char *symstart(char *p
)
32 extern char _decompressor_syms_start
[], _decompressor_syms_end
[];
33 static noinline
char *findsym(unsigned long ip
, unsigned short *off
, unsigned short *len
)
35 /* symbol entries are in a form "10000 c4 startup\0" */
36 char *a
= _decompressor_syms_start
;
37 char *b
= _decompressor_syms_end
;
44 pivot
= symstart(a
+ (b
- a
) / 2);
45 start
= simple_strtoull(pivot
, &endp
, 16);
46 size
= simple_strtoull(endp
+ 1, &endp
, 16);
51 if (ip
> start
+ size
) {
52 a
= pivot
+ strlen(pivot
) + 1;
62 static noinline
char *strsym(void *ip
)
69 p
= findsym((unsigned long)ip
, &off
, &len
);
71 strncpy(buf
, p
, sizeof(buf
));
72 /* reserve 15 bytes for offset/len in symbol+0x1234/0x1234 */
73 p
= buf
+ strnlen(buf
, sizeof(buf
) - 15);
75 p
= as_hex(p
+ 3, off
, 0);
77 as_hex(p
+ 3, len
, 0);
79 as_hex(buf
, (unsigned long)ip
, 16);
84 void decompressor_printk(const char *fmt
, ...)
86 char buf
[1024] = { 0 };
87 char *end
= buf
+ sizeof(buf
) - 1; /* make sure buf is 0 terminated */
93 for (; p
< end
&& *fmt
; fmt
++) {
98 pad
= isdigit(*++fmt
) ? simple_strtol(fmt
, (char **)&fmt
, 10) : 0;
101 p
= buf
+ strlcat(buf
, va_arg(args
, char *), sizeof(buf
));
106 p
= buf
+ strlcat(buf
, strsym(va_arg(args
, void *)), sizeof(buf
));
109 if (*++fmt
!= 'x' || end
- p
<= max(sizeof(long) * 2, pad
))
111 p
= as_hex(p
, va_arg(args
, unsigned long), pad
);
114 if (end
- p
<= max(sizeof(int) * 2, pad
))
116 p
= as_hex(p
, va_arg(args
, unsigned int), pad
);
124 sclp_early_printk(buf
);
127 static noinline
void print_stacktrace(void)
129 struct stack_info boot_stack
= { STACK_TYPE_TASK
, BOOT_STACK_OFFSET
,
130 BOOT_STACK_OFFSET
+ BOOT_STACK_SIZE
};
131 unsigned long sp
= S390_lowcore
.gpregs_save_area
[15];
134 decompressor_printk("Call Trace:\n");
135 while (!(sp
& 0x7) && on_stack(&boot_stack
, sp
, sizeof(struct stack_frame
))) {
136 struct stack_frame
*sf
= (struct stack_frame
*)sp
;
138 decompressor_printk(first
? "(sp:%016lx [<%016lx>] %pS)\n" :
139 " sp:%016lx [<%016lx>] %pS\n",
140 sp
, sf
->gprs
[8], (void *)sf
->gprs
[8]);
141 if (sf
->back_chain
<= sp
)
148 void print_pgm_check_info(void)
150 unsigned long *gpregs
= (unsigned long *)S390_lowcore
.gpregs_save_area
;
151 struct psw_bits
*psw
= &psw_bits(S390_lowcore
.psw_save_area
);
153 decompressor_printk("Linux version %s\n", kernel_version
);
154 if (!is_prot_virt_guest() && early_command_line
[0])
155 decompressor_printk("Kernel command line: %s\n", early_command_line
);
156 decompressor_printk("Kernel fault: interruption code %04x ilc:%x\n",
157 S390_lowcore
.pgm_code
, S390_lowcore
.pgm_ilc
>> 1);
159 decompressor_printk("Kernel random base: %lx\n", __kaslr_offset
);
160 decompressor_printk("PSW : %016lx %016lx (%pS)\n",
161 S390_lowcore
.psw_save_area
.mask
,
162 S390_lowcore
.psw_save_area
.addr
,
163 (void *)S390_lowcore
.psw_save_area
.addr
);
165 " R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x P:%x AS:%x CC:%x PM:%x RI:%x EA:%x\n",
166 psw
->per
, psw
->dat
, psw
->io
, psw
->ext
, psw
->key
, psw
->mcheck
,
167 psw
->wait
, psw
->pstate
, psw
->as
, psw
->cc
, psw
->pm
, psw
->ri
,
169 decompressor_printk("GPRS: %016lx %016lx %016lx %016lx\n",
170 gpregs
[0], gpregs
[1], gpregs
[2], gpregs
[3]);
171 decompressor_printk(" %016lx %016lx %016lx %016lx\n",
172 gpregs
[4], gpregs
[5], gpregs
[6], gpregs
[7]);
173 decompressor_printk(" %016lx %016lx %016lx %016lx\n",
174 gpregs
[8], gpregs
[9], gpregs
[10], gpregs
[11]);
175 decompressor_printk(" %016lx %016lx %016lx %016lx\n",
176 gpregs
[12], gpregs
[13], gpregs
[14], gpregs
[15]);
178 decompressor_printk("Last Breaking-Event-Address:\n");
179 decompressor_printk(" [<%016lx>] %pS\n", (unsigned long)S390_lowcore
.breaking_event_addr
,
180 (void *)S390_lowcore
.breaking_event_addr
);