forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
s390/decompressor: add decompressor_printk
The decompressor does not have any special debug means. Running the kernel under qemu with gdb is helpful but tedious exercise if done repeatedly. It is also not applicable to debugging under LPAR and z/VM. One special thing which stands out is a working sclp_early_printk, which could be used once the kernel switches to 64-bit addressing mode. But sclp_early_printk does not provide any string formating capabilities. Formatting and printing string without printk-alike function is a not fun. The lack of printk-alike function means people would save up on testing and introduce more bugs. So, finally, provide decompressor_printk function, which fits on one screen and trades features for simplicity. It only supports "%s", "%x" and "%lx" specifiers and zero padding for hex values. Reviewed-by: Alexander Egorenkov <[email protected]> Signed-off-by: Vasily Gorbik <[email protected]> Signed-off-by: Heiko Carstens <[email protected]>
- Loading branch information
Showing
2 changed files
with
68 additions
and
78 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,99 +1,86 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
#include <linux/kernel.h> | ||
#include <linux/string.h> | ||
#include <linux/ctype.h> | ||
#include <asm/lowcore.h> | ||
#include <asm/setup.h> | ||
#include <asm/sclp.h> | ||
#include <stdarg.h> | ||
#include "boot.h" | ||
|
||
const char hex_asc[] = "0123456789abcdef"; | ||
|
||
#define add_val_as_hex(dst, val) \ | ||
__add_val_as_hex(dst, (const unsigned char *)&val, sizeof(val)) | ||
|
||
static char *__add_val_as_hex(char *dst, const unsigned char *src, size_t count) | ||
static char *as_hex(char *dst, unsigned long val, int pad) | ||
{ | ||
while (count--) | ||
dst = hex_byte_pack(dst, *src++); | ||
return dst; | ||
} | ||
char *p, *end = p = dst + max(pad, (int)__fls(val | 1) / 4 + 1); | ||
|
||
static char *add_str(char *dst, char *src) | ||
{ | ||
strcpy(dst, src); | ||
return dst + strlen(dst); | ||
for (*p-- = 0; p >= dst; val >>= 4) | ||
*p-- = hex_asc[val & 0x0f]; | ||
return end; | ||
} | ||
|
||
void print_pgm_check_info(void) | ||
void decompressor_printk(const char *fmt, ...) | ||
{ | ||
struct psw_bits *psw = &psw_bits(S390_lowcore.psw_save_area); | ||
unsigned short ilc = S390_lowcore.pgm_ilc >> 1; | ||
char buf[256]; | ||
int row, col; | ||
char *p; | ||
char buf[1024] = { 0 }; | ||
char *end = buf + sizeof(buf) - 1; /* make sure buf is 0 terminated */ | ||
unsigned long pad; | ||
char *p = buf; | ||
va_list args; | ||
|
||
add_str(buf, "Linux version "); | ||
strlcat(buf, kernel_version, sizeof(buf) - 1); | ||
strlcat(buf, "\n", sizeof(buf)); | ||
sclp_early_printk(buf); | ||
|
||
p = add_str(buf, "Kernel fault: interruption code "); | ||
p = add_val_as_hex(buf + strlen(buf), S390_lowcore.pgm_code); | ||
p = add_str(p, " ilc:"); | ||
*p++ = hex_asc_lo(ilc); | ||
add_str(p, "\n"); | ||
sclp_early_printk(buf); | ||
|
||
if (kaslr_enabled) { | ||
p = add_str(buf, "Kernel random base: "); | ||
p = add_val_as_hex(p, __kaslr_offset); | ||
add_str(p, "\n"); | ||
sclp_early_printk(buf); | ||
va_start(args, fmt); | ||
for (; p < end && *fmt; fmt++) { | ||
if (*fmt != '%') { | ||
*p++ = *fmt; | ||
continue; | ||
} | ||
pad = isdigit(*++fmt) ? simple_strtol(fmt, (char **)&fmt, 10) : 0; | ||
switch (*fmt) { | ||
case 's': | ||
p = buf + strlcat(buf, va_arg(args, char *), sizeof(buf)); | ||
break; | ||
case 'l': | ||
if (*++fmt != 'x' || end - p <= max(sizeof(long) * 2, pad)) | ||
goto out; | ||
p = as_hex(p, va_arg(args, unsigned long), pad); | ||
break; | ||
case 'x': | ||
if (end - p <= max(sizeof(int) * 2, pad)) | ||
goto out; | ||
p = as_hex(p, va_arg(args, unsigned int), pad); | ||
break; | ||
default: | ||
goto out; | ||
} | ||
} | ||
|
||
p = add_str(buf, "PSW : "); | ||
p = add_val_as_hex(p, S390_lowcore.psw_save_area.mask); | ||
p = add_str(p, " "); | ||
p = add_val_as_hex(p, S390_lowcore.psw_save_area.addr); | ||
add_str(p, "\n"); | ||
out: | ||
va_end(args); | ||
sclp_early_printk(buf); | ||
} | ||
|
||
p = add_str(buf, " R:"); | ||
*p++ = hex_asc_lo(psw->per); | ||
p = add_str(p, " T:"); | ||
*p++ = hex_asc_lo(psw->dat); | ||
p = add_str(p, " IO:"); | ||
*p++ = hex_asc_lo(psw->io); | ||
p = add_str(p, " EX:"); | ||
*p++ = hex_asc_lo(psw->ext); | ||
p = add_str(p, " Key:"); | ||
*p++ = hex_asc_lo(psw->key); | ||
p = add_str(p, " M:"); | ||
*p++ = hex_asc_lo(psw->mcheck); | ||
p = add_str(p, " W:"); | ||
*p++ = hex_asc_lo(psw->wait); | ||
p = add_str(p, " P:"); | ||
*p++ = hex_asc_lo(psw->pstate); | ||
p = add_str(p, " AS:"); | ||
*p++ = hex_asc_lo(psw->as); | ||
p = add_str(p, " CC:"); | ||
*p++ = hex_asc_lo(psw->cc); | ||
p = add_str(p, " PM:"); | ||
*p++ = hex_asc_lo(psw->pm); | ||
p = add_str(p, " RI:"); | ||
*p++ = hex_asc_lo(psw->ri); | ||
p = add_str(p, " EA:"); | ||
*p++ = hex_asc_lo(psw->eaba); | ||
add_str(p, "\n"); | ||
sclp_early_printk(buf); | ||
void print_pgm_check_info(void) | ||
{ | ||
unsigned long *gpregs = (unsigned long *)S390_lowcore.gpregs_save_area; | ||
struct psw_bits *psw = &psw_bits(S390_lowcore.psw_save_area); | ||
|
||
for (row = 0; row < 4; row++) { | ||
p = add_str(buf, row == 0 ? "GPRS:" : " "); | ||
for (col = 0; col < 4; col++) { | ||
p = add_str(p, " "); | ||
p = add_val_as_hex(p, S390_lowcore.gpregs_save_area[row * 4 + col]); | ||
} | ||
add_str(p, "\n"); | ||
sclp_early_printk(buf); | ||
} | ||
decompressor_printk("Linux version %s\n", kernel_version); | ||
decompressor_printk("Kernel fault: interruption code %04x ilc:%x\n", | ||
S390_lowcore.pgm_code, S390_lowcore.pgm_ilc >> 1); | ||
if (kaslr_enabled) | ||
decompressor_printk("Kernel random base: %lx\n", __kaslr_offset); | ||
decompressor_printk("PSW : %016lx %016lx\n", | ||
S390_lowcore.psw_save_area.mask, | ||
S390_lowcore.psw_save_area.addr); | ||
decompressor_printk( | ||
" 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", | ||
psw->per, psw->dat, psw->io, psw->ext, psw->key, psw->mcheck, | ||
psw->wait, psw->pstate, psw->as, psw->cc, psw->pm, psw->ri, | ||
psw->eaba); | ||
decompressor_printk("GPRS: %016lx %016lx %016lx %016lx\n", | ||
gpregs[0], gpregs[1], gpregs[2], gpregs[3]); | ||
decompressor_printk(" %016lx %016lx %016lx %016lx\n", | ||
gpregs[4], gpregs[5], gpregs[6], gpregs[7]); | ||
decompressor_printk(" %016lx %016lx %016lx %016lx\n", | ||
gpregs[8], gpregs[9], gpregs[10], gpregs[11]); | ||
decompressor_printk(" %016lx %016lx %016lx %016lx\n", | ||
gpregs[12], gpregs[13], gpregs[14], gpregs[15]); | ||
} |