hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Firmware-Assisted Dump support on POWER platform (OPAL).
 *
 * Copyright 2019, Hari Bathini, IBM Corporation.
 */
 
#ifndef _POWERNV_OPAL_FADUMP_H
#define _POWERNV_OPAL_FADUMP_H
 
#include <asm/reg.h>
 
/*
 * With kernel & initrd loaded at 512MB (with 256MB size), enforce a minimum
 * boot memory size of 768MB to ensure f/w loading kernel and initrd doesn't
 * mess with crash'ed kernel's memory during MPIPL.
 */
#define OPAL_FADUMP_MIN_BOOT_MEM        (0x30000000UL)
 
/*
 * OPAL FADump metadata structure format version
 *
 * OPAL FADump kernel metadata structure stores kernel metadata needed to
 * register-for/process crash dump. Format version is used to keep a tab on
 * the changes in the structure format. The changes, if any, to the format
 * are expected to be minimal and backward compatible.
 */
#define OPAL_FADUMP_VERSION            0x1
 
/*
 * OPAL FADump kernel metadata
 *
 * The address of this structure will be registered with f/w for retrieving
 * in the capture kernel to process the crash dump.
 */
struct opal_fadump_mem_struct {
   u8    version;
   u8    reserved[3];
   __be16    region_cnt;        /* number of regions */
   __be16    registered_regions;    /* Regions registered for MPIPL */
   __be64    fadumphdr_addr;
   struct opal_mpipl_region    rgn[FADUMP_MAX_MEM_REGS];
} __packed;
 
/*
 * CPU state data
 *
 * CPU state data information is provided by f/w. The format for this data
 * is defined in the HDAT spec. Version is used to keep a tab on the changes
 * in this CPU state data format. Changes to this format are unlikely, but
 * if there are any changes, please refer to latest HDAT specification.
 */
#define HDAT_FADUMP_CPU_DATA_VER        1
 
#define HDAT_FADUMP_CORE_INACTIVE        (0x0F)
 
/* HDAT thread header for register entries */
struct hdat_fadump_thread_hdr {
   __be32  pir;
   /* 0x00 - 0x0F - The corresponding stop state of the core */
   u8      core_state;
   u8      reserved[3];
 
   __be32    offset;    /* Offset to Register Entries array */
   __be32    ecnt;    /* Number of entries */
   __be32    esize;    /* Alloc size of each array entry in bytes */
   __be32    eactsz;    /* Actual size of each array entry in bytes */
} __packed;
 
/* Register types populated by f/w */
#define HDAT_FADUMP_REG_TYPE_GPR        0x01
#define HDAT_FADUMP_REG_TYPE_SPR        0x02
 
/* ID numbers used by f/w while populating certain registers */
#define HDAT_FADUMP_REG_ID_NIP            0x7D0
#define HDAT_FADUMP_REG_ID_MSR            0x7D1
#define HDAT_FADUMP_REG_ID_CCR            0x7D2
 
/* HDAT register entry. */
struct hdat_fadump_reg_entry {
   __be32        reg_type;
   __be32        reg_num;
   __be64        reg_val;
} __packed;
 
static inline void opal_fadump_set_regval_regnum(struct pt_regs *regs,
                        u32 reg_type, u32 reg_num,
                        u64 reg_val)
{
   if (reg_type == HDAT_FADUMP_REG_TYPE_GPR) {
       if (reg_num < 32)
           regs->gpr[reg_num] = reg_val;
       return;
   }
 
   switch (reg_num) {
   case SPRN_CTR:
       regs->ctr = reg_val;
       break;
   case SPRN_LR:
       regs->link = reg_val;
       break;
   case SPRN_XER:
       regs->xer = reg_val;
       break;
   case SPRN_DAR:
       regs->dar = reg_val;
       break;
   case SPRN_DSISR:
       regs->dsisr = reg_val;
       break;
   case HDAT_FADUMP_REG_ID_NIP:
       regs->nip = reg_val;
       break;
   case HDAT_FADUMP_REG_ID_MSR:
       regs->msr = reg_val;
       break;
   case HDAT_FADUMP_REG_ID_CCR:
       regs->ccr = reg_val;
       break;
   }
}
 
static inline void opal_fadump_read_regs(char *bufp, unsigned int regs_cnt,
                    unsigned int reg_entry_size,
                    bool cpu_endian,
                    struct pt_regs *regs)
{
   struct hdat_fadump_reg_entry *reg_entry;
   u64 val;
   int i;
 
   memset(regs, 0, sizeof(struct pt_regs));
 
   for (i = 0; i < regs_cnt; i++, bufp += reg_entry_size) {
       reg_entry = (struct hdat_fadump_reg_entry *)bufp;
       val = (cpu_endian ? be64_to_cpu(reg_entry->reg_val) :
              (u64)(reg_entry->reg_val));
       opal_fadump_set_regval_regnum(regs,
                         be32_to_cpu(reg_entry->reg_type),
                         be32_to_cpu(reg_entry->reg_num),
                         val);
   }
}
 
#endif /* _POWERNV_OPAL_FADUMP_H */