linux/arch/s390/boot/pgm_check_info.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/kernel.h>
   3#include <linux/stdarg.h>
   4#include <linux/string.h>
   5#include <linux/ctype.h>
   6#include <asm/stacktrace.h>
   7#include <asm/boot_data.h>
   8#include <asm/lowcore.h>
   9#include <asm/setup.h>
  10#include <asm/sclp.h>
  11#include <asm/uv.h>
  12#include "boot.h"
  13
  14const char hex_asc[] = "0123456789abcdef";
  15
  16static char *as_hex(char *dst, unsigned long val, int pad)
  17{
  18        char *p, *end = p = dst + max(pad, (int)__fls(val | 1) / 4 + 1);
  19
  20        for (*p-- = 0; p >= dst; val >>= 4)
  21                *p-- = hex_asc[val & 0x0f];
  22        return end;
  23}
  24
  25static char *symstart(char *p)
  26{
  27        while (*p)
  28                p--;
  29        return p + 1;
  30}
  31
  32static noinline char *findsym(unsigned long ip, unsigned short *off, unsigned short *len)
  33{
  34        /* symbol entries are in a form "10000 c4 startup\0" */
  35        char *a = _decompressor_syms_start;
  36        char *b = _decompressor_syms_end;
  37        unsigned long start;
  38        unsigned long size;
  39        char *pivot;
  40        char *endp;
  41
  42        while (a < b) {
  43                pivot = symstart(a + (b - a) / 2);
  44                start = simple_strtoull(pivot, &endp, 16);
  45                size = simple_strtoull(endp + 1, &endp, 16);
  46                if (ip < start) {
  47                        b = pivot;
  48                        continue;
  49                }
  50                if (ip > start + size) {
  51                        a = pivot + strlen(pivot) + 1;
  52                        continue;
  53                }
  54                *off = ip - start;
  55                *len = size;
  56                return endp + 1;
  57        }
  58        return NULL;
  59}
  60
  61static noinline char *strsym(void *ip)
  62{
  63        static char buf[64];
  64        unsigned short off;
  65        unsigned short len;
  66        char *p;
  67
  68        p = findsym((unsigned long)ip, &off, &len);
  69        if (p) {
  70                strncpy(buf, p, sizeof(buf));
  71                /* reserve 15 bytes for offset/len in symbol+0x1234/0x1234 */
  72                p = buf + strnlen(buf, sizeof(buf) - 15);
  73                strcpy(p, "+0x");
  74                p = as_hex(p + 3, off, 0);
  75                strcpy(p, "/0x");
  76                as_hex(p + 3, len, 0);
  77        } else {
  78                as_hex(buf, (unsigned long)ip, 16);
  79        }
  80        return buf;
  81}
  82
  83void decompressor_printk(const char *fmt, ...)
  84{
  85        char buf[1024] = { 0 };
  86        char *end = buf + sizeof(buf) - 1; /* make sure buf is 0 terminated */
  87        unsigned long pad;
  88        char *p = buf;
  89        va_list args;
  90
  91        va_start(args, fmt);
  92        for (; p < end && *fmt; fmt++) {
  93                if (*fmt != '%') {
  94                        *p++ = *fmt;
  95                        continue;
  96                }
  97                pad = isdigit(*++fmt) ? simple_strtol(fmt, (char **)&fmt, 10) : 0;
  98                switch (*fmt) {
  99                case 's':
 100                        p = buf + strlcat(buf, va_arg(args, char *), sizeof(buf));
 101                        break;
 102                case 'p':
 103                        if (*++fmt != 'S')
 104                                goto out;
 105                        p = buf + strlcat(buf, strsym(va_arg(args, void *)), sizeof(buf));
 106                        break;
 107                case 'l':
 108                        if (*++fmt != 'x' || end - p <= max(sizeof(long) * 2, pad))
 109                                goto out;
 110                        p = as_hex(p, va_arg(args, unsigned long), pad);
 111                        break;
 112                case 'x':
 113                        if (end - p <= max(sizeof(int) * 2, pad))
 114                                goto out;
 115                        p = as_hex(p, va_arg(args, unsigned int), pad);
 116                        break;
 117                default:
 118                        goto out;
 119                }
 120        }
 121out:
 122        va_end(args);
 123        sclp_early_printk(buf);
 124}
 125
 126static noinline void print_stacktrace(void)
 127{
 128        struct stack_info boot_stack = { STACK_TYPE_TASK, (unsigned long)_stack_start,
 129                                         (unsigned long)_stack_end };
 130        unsigned long sp = S390_lowcore.gpregs_save_area[15];
 131        bool first = true;
 132
 133        decompressor_printk("Call Trace:\n");
 134        while (!(sp & 0x7) && on_stack(&boot_stack, sp, sizeof(struct stack_frame))) {
 135                struct stack_frame *sf = (struct stack_frame *)sp;
 136
 137                decompressor_printk(first ? "(sp:%016lx [<%016lx>] %pS)\n" :
 138                                            " sp:%016lx [<%016lx>] %pS\n",
 139                                    sp, sf->gprs[8], (void *)sf->gprs[8]);
 140                if (sf->back_chain <= sp)
 141                        break;
 142                sp = sf->back_chain;
 143                first = false;
 144        }
 145}
 146
 147void print_pgm_check_info(void)
 148{
 149        unsigned long *gpregs = (unsigned long *)S390_lowcore.gpregs_save_area;
 150        struct psw_bits *psw = &psw_bits(S390_lowcore.psw_save_area);
 151
 152        decompressor_printk("Linux version %s\n", kernel_version);
 153        if (!is_prot_virt_guest() && early_command_line[0])
 154                decompressor_printk("Kernel command line: %s\n", early_command_line);
 155        decompressor_printk("Kernel fault: interruption code %04x ilc:%x\n",
 156                            S390_lowcore.pgm_code, S390_lowcore.pgm_ilc >> 1);
 157        if (kaslr_enabled)
 158                decompressor_printk("Kernel random base: %lx\n", __kaslr_offset);
 159        decompressor_printk("PSW : %016lx %016lx (%pS)\n",
 160                            S390_lowcore.psw_save_area.mask,
 161                            S390_lowcore.psw_save_area.addr,
 162                            (void *)S390_lowcore.psw_save_area.addr);
 163        decompressor_printk(
 164                "      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",
 165                psw->per, psw->dat, psw->io, psw->ext, psw->key, psw->mcheck,
 166                psw->wait, psw->pstate, psw->as, psw->cc, psw->pm, psw->ri,
 167                psw->eaba);
 168        decompressor_printk("GPRS: %016lx %016lx %016lx %016lx\n",
 169                            gpregs[0], gpregs[1], gpregs[2], gpregs[3]);
 170        decompressor_printk("      %016lx %016lx %016lx %016lx\n",
 171                            gpregs[4], gpregs[5], gpregs[6], gpregs[7]);
 172        decompressor_printk("      %016lx %016lx %016lx %016lx\n",
 173                            gpregs[8], gpregs[9], gpregs[10], gpregs[11]);
 174        decompressor_printk("      %016lx %016lx %016lx %016lx\n",
 175                            gpregs[12], gpregs[13], gpregs[14], gpregs[15]);
 176        print_stacktrace();
 177        decompressor_printk("Last Breaking-Event-Address:\n");
 178        decompressor_printk(" [<%016lx>] %pS\n", (unsigned long)S390_lowcore.breaking_event_addr,
 179                            (void *)S390_lowcore.breaking_event_addr);
 180}
 181