coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
crashlog.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <console/console.h>
4 #include <cbmem.h>
5 #include <delay.h>
6 #include <intelblocks/crashlog.h>
7 #include <string.h>
8 
10 {
11  return 0;
12 }
13 
15 {
16  return 0;
17 }
18 
20 {
21  return 0;
22 }
23 
25 {
26  return 0;
27 }
28 
30 {
31  return 0;
32 }
33 
35 {
37 }
38 
40 {
41  return false;
42 }
43 
45 {
46  return false;
47 }
48 
50 {
51  return false;
52 }
53 
55 {
56  return false;
57 }
58 
60 {
61  return false;
62 }
63 
65 
66 __weak void update_new_pmc_crashlog_size(u32 *pmc_crash_size) {}
67 
68 __weak void update_new_cpu_crashlog_size(u32 *cpu_crash_size) {}
69 
70 pmc_ipc_discovery_buf_t __weak cl_get_pmc_discovery_buf(void)
71 {
72  pmc_ipc_discovery_buf_t discov_buf;
73  memset(&discov_buf, 0, sizeof(pmc_ipc_discovery_buf_t));
74  return discov_buf;
75 }
76 
77 pmc_crashlog_desc_table_t __weak cl_get_pmc_descriptor_table(void)
78 {
79  pmc_crashlog_desc_table_t desc_tab;
80  memset(&desc_tab, 0, sizeof(pmc_crashlog_desc_table_t));
81  return desc_tab;
82 }
83 
84 cpu_crashlog_discovery_table_t __weak cl_get_cpu_discovery_table(void)
85 {
86  cpu_crashlog_discovery_table_t cpu_disc_tab;
87  memset(&cpu_disc_tab, 0, sizeof(cpu_crashlog_discovery_table_t));
88  return cpu_disc_tab;
89 }
90 
91 int cpu_cl_poll_mailbox_ready(u32 cl_mailbox_addr)
92 {
93  cpu_crashlog_mailbox_t cl_mailbox_interface;
94  u16 stall_cnt = 0;
95 
96  do {
97  cl_mailbox_interface.data = read32((u32 *)cl_mailbox_addr);
99  stall_cnt++;
100  } while ((cl_mailbox_interface.fields.busy == 1)
101  && stall_cnt < CPU_CRASHLOG_MAILBOX_WAIT_TIMEOUT);
102 
103  if ((cl_mailbox_interface.fields.busy == 1)
104  && (stall_cnt >= CPU_CRASHLOG_MAILBOX_WAIT_TIMEOUT)) {
105  printk(BIOS_ERR, "CPU crashlog mailbox timed out.\n");
106  return 0;
107  }
108 
109  return 1;
110 }
111 
112 int cpu_cl_mailbox_cmd(u8 cmd, u8 param)
113 {
114  cpu_crashlog_mailbox_t cl_mailbox_intf;
115  u32 cl_base_addr;
116 
117  memset(&cl_mailbox_intf, 0, sizeof(cpu_crashlog_mailbox_t));
118 
119  cl_base_addr = cl_get_cpu_bar_addr();
120 
121  cl_mailbox_intf.fields.command = cmd;
122  cl_mailbox_intf.fields.param = param;
123  cl_mailbox_intf.fields.busy = 1;
124 
125  write32((u32 *)(cl_base_addr + cl_get_cpu_mb_int_addr()),
126  cl_mailbox_intf.data);
127 
129 
130  return 1;
131 }
132 
134 {
136 }
137 
138 int pmc_cl_gen_descriptor_table(u32 desc_table_addr,
139  pmc_crashlog_desc_table_t *descriptor_table)
140 {
141  int total_data_size = 0;
142  descriptor_table->numb_regions = read32((u32 *)desc_table_addr);
143  printk(BIOS_DEBUG, "CL PMC desc table: numb of regions is 0x%x at addr 0x%x\n",
144  descriptor_table->numb_regions, desc_table_addr);
145  for (int i = 0; i < descriptor_table->numb_regions; i++) {
146  desc_table_addr += 4;
147  descriptor_table->regions[i].data = read32((u32 *)(desc_table_addr));
148  total_data_size += descriptor_table->regions[i].bits.size * sizeof(u32);
149  printk(BIOS_DEBUG, "CL PMC desc table: region 0x%x has size 0x%x at offset 0x%x\n",
150  i, descriptor_table->regions[i].bits.size,
151  descriptor_table->regions[i].bits.offset);
152  if (i > 255) {
153  printk(BIOS_ERR, "More than 255 regions in PMC crashLog descriptor table");
154  break;
155  }
156  }
157  return total_data_size;
158 }
159 
161 {
162  return false;
163 }
164 
166 {
167  return false;
168 }
169 
171 {
172 
173  const struct pmc_ipc_buffer req = { 0 };
174  struct pmc_ipc_buffer res;
175  uint32_t cmd_reg;
176  int r;
177 
181 
182  r = pmc_send_ipc_cmd(cmd_reg, &req, &res);
183 
184  if (r < 0) {
185  printk(BIOS_ERR, "pmc_send_ipc_cmd failed in %s\n", __func__);
186  return 0;
187  }
188 
189  return r;
190 }
191 
192 /* Sends PMC IPC to clear CrashLog from PMC SSRAM area */
193 int cl_pmc_clear(void)
194 {
195  const struct pmc_ipc_buffer req = { 0 };
196  struct pmc_ipc_buffer res;
197  uint32_t cmd_reg;
198  int r;
199 
203 
204  r = pmc_send_ipc_cmd(cmd_reg, &req, &res);
205 
206  if (r < 0) {
207  printk(BIOS_ERR, "pmc_send_ipc_cmd failed in %s\n", __func__);
208  return 0;
209  }
210 
211  return r;
212 }
213 
214 /*
215  * Sends PMC IPC to populate CrashLog on all reboot.
216  * The SSRAM area will be cleared on G3 by PMC automatically
217  */
219 {
220  const struct pmc_ipc_buffer req = { 0 };
221  struct pmc_ipc_buffer res;
222  uint32_t cmd_reg;
223  int r;
224 
228 
229  r = pmc_send_ipc_cmd(cmd_reg, &req, &res);
230 
231  if (r < 0) {
232  printk(BIOS_ERR, "pmc_send_ipc_cmd failed in %s\n", __func__);
233  return 0;
234  }
235 
236  return r;
237 }
238 
240 {
241  bool cpu_cl_discovered = false, pmc_cl_discovered = false;
242 
244 
245  /* PCH crashLog discovery */
246  pmc_cl_discovered = pmc_cl_discovery();
247 
248  /* CPU crashLog discovery */
249  cpu_cl_discovered = cpu_cl_discovery();
250 
251  return (cpu_cl_discovered || pmc_cl_discovered);
252 }
253 
255  u32 offset,
256  u32 size,
257  u32 *dest_addr,
258  u32 buffer_index,
259  bool pmc_sram)
260 {
261  if (src_bar == 0) {
262  printk(BIOS_ERR, "Invalid bar 0x%x and offset 0x%x for %s\n",
263  src_bar, offset, __func__);
264  return false;
265  }
266 
267  u32 src_addr = src_bar + offset;
268 
269  u32 data = read32((u32 *)src_addr);
270  /* PMC: copy if 1st DWORD in buffer is not zero and its 31st bit is not set */
271  if (pmc_sram && !(data && !(data & BIT(31)))) {
272  printk(BIOS_DEBUG, "Invalid data 0x%x at offset 0x%x from addr 0x%x"
273  " of PMC SRAM.\n", data, offset, src_bar);
274  return false;
275  }
276  /*CPU: don't copy if 1st DWORD in first buffer is zero */
277  if (!pmc_sram && !data && (buffer_index == 0)) {
278  printk(BIOS_DEBUG, "Invalid data 0x%x at offset 0x%x from addr 0x%x"
279  " of telemetry SRAM.\n", data, offset, src_bar);
280  return false;
281  }
282 
283  u32 copied = 0;
284  while (copied < size) {
285  /* DW by DW copy: byte access to PMC SRAM not allowed */
286  *dest_addr = read32((u32 *)src_addr);
287  dest_addr++;
288  src_addr += 4;
289  copied++;
290  }
291  return true;
292 }
293 
295 {
296  u32 *dest = NULL;
297  u32 tmp_bar_addr = cl_get_cpu_tmp_bar();
298  u32 pmc_crashLog_size = cl_get_pmc_record_size();
299 
301  return;
302 
303  pmc_ipc_discovery_buf_t discovery_buf = cl_get_pmc_discovery_buf();
304 
305  if (discovery_buf.bits.supported != 1) {
306  printk(BIOS_DEBUG, "PCH crashlog feature not supported.\n");
307  goto pmc_send_re_arm_after_reset;
308  }
309 
310  /* Get the size of data to copy */
311  if (discovery_buf.bits.discov_mechanism == 1) {
312  if (discovery_buf.bits.base_offset & BIT(31)) {
313  printk(BIOS_DEBUG, "PCH discovery to be used is disabled.\n");
314  goto pmc_send_re_arm_after_reset;
315  }
316  printk(BIOS_DEBUG, "PMC crashLog size in discovery mode : 0x%X\n",
317  pmc_crashLog_size);
318  } else {
319  if (discovery_buf.bits.dis) {
320  printk(BIOS_DEBUG, "PCH crashlog is disabled in legacy mode.\n");
321  return;
322  }
323  pmc_crashLog_size = (discovery_buf.bits.size != 0) ?
324  discovery_buf.bits.size : 0xC00;
325  printk(BIOS_DEBUG, "PMC crashLog size in legacy mode : 0x%X\n",
326  pmc_crashLog_size);
327  }
328 
329  /* allocate mem for the record to be copied */
330  unsigned long pmc_cl_cbmem_addr;
331 
332  pmc_cl_cbmem_addr = (unsigned long) cbmem_add(CBMEM_ID_PMC_CRASHLOG,
333  pmc_crashLog_size);
334  if (!pmc_cl_cbmem_addr) {
335  printk(BIOS_ERR, "Unable to allocate CBMEM PMC crashLog entry.\n");
336  return;
337  }
338 
339  memset((void *)pmc_cl_cbmem_addr, 0, pmc_crashLog_size);
340  dest = (u32 *)(uintptr_t) pmc_cl_cbmem_addr;
341  bool pmc_sram = true;
342  pmc_crashlog_desc_table_t descriptor_table = cl_get_pmc_descriptor_table();
343  if (discovery_buf.bits.discov_mechanism == 1) {
344  for (int i = 0; i < descriptor_table.numb_regions; i++) {
345  if (cl_copy_data_from_sram(tmp_bar_addr,
346  descriptor_table.regions[i].bits.offset,
347  descriptor_table.regions[i].bits.size,
348  dest,
349  i,
350  pmc_sram)) {
351  dest = (u32 *)((u32)dest +
352  (descriptor_table.regions[i].bits.size
353  * sizeof(u32)));
354  } else {
355  pmc_crashLog_size -= descriptor_table.regions[i].bits.size *
356  sizeof(u32);
357  printk(BIOS_DEBUG, "discover mode PMC crashlog size adjusted"
358  " to: 0x%x\n", pmc_crashLog_size);
359  }
360  }
361  } else {
362  if (!cl_copy_data_from_sram(tmp_bar_addr,
363  discovery_buf.bits.base_offset,
364  discovery_buf.bits.size,
365  dest,
366  0,
367  pmc_sram)) {
368  pmc_crashLog_size -= discovery_buf.bits.size * sizeof(u32);
369  printk(BIOS_DEBUG, "legacy mode PMC crashlog size adjusted to: 0x%x\n",
370  pmc_crashLog_size);
371  }
372  }
373 
374  update_new_pmc_crashlog_size(&pmc_crashLog_size);
375 
376 pmc_send_re_arm_after_reset:
377  /* when bit 7 of discov cmd resp is set -> bit 2 of size field */
378  if (discovery_buf.bits.size & BIT(2))
380 
381  /* Clear the SSRAM region after copying the error log */
382  cl_pmc_clear();
383 
384 }
385 
387 {
388  u32 tmp_bar_addr = 0;
389  u32 *dest = NULL;
391  cpu_crashlog_discovery_table_t cpu_cl_disc_tab = cl_get_cpu_discovery_table();
392 
393  if (m_cpu_crashLog_size < 1) {
394  printk(BIOS_DEBUG, "%s: no data to collect.\n", __func__);
395  return;
396  }
397 
398  printk(BIOS_DEBUG, "CPU crash data size: 0x%X bytes in 0x%X region(s).\n",
399  m_cpu_crashLog_size, cpu_cl_disc_tab.header.fields.count);
400 
401  /* allocate memory buffers for CPU crashog data to be copied */
402  unsigned long cpu_crashlog_cbmem_addr;
403  cpu_crashlog_cbmem_addr = (unsigned long) cbmem_add(CBMEM_ID_CPU_CRASHLOG,
405  if (!cpu_crashlog_cbmem_addr) {
406  printk(BIOS_ERR, "Failed to add CPU main crashLog entries to CBMEM.\n");
407  return;
408  }
409 
410  memset((void *) cpu_crashlog_cbmem_addr, 0, m_cpu_crashLog_size);
411  tmp_bar_addr = cl_get_cpu_bar_addr();
412  dest = (u32 *)(uintptr_t) cpu_crashlog_cbmem_addr;
413  bool pmc_sram = false;
414  cpu_crashlog_buffer_info_t buff_info;
415 
416  for (int i = 0 ; i < cpu_cl_disc_tab.header.fields.count ; i++) {
417  buff_info = cpu_cl_disc_tab.buffers[i];
418 
419  if (cl_copy_data_from_sram(tmp_bar_addr,
420  cpu_cl_disc_tab.buffers[i].fields.offset,
421  cpu_cl_disc_tab.buffers[i].fields.size,
422  dest,
423  i,
424  pmc_sram)) {
425  dest = (u32 *)((u32)dest +
426  (cpu_cl_disc_tab.buffers[i].fields.size * sizeof(u32)));
427  } else {
428  m_cpu_crashLog_size -= cpu_cl_disc_tab.buffers[i].fields.size
429  * sizeof(u32);
430 
431  /* for CPU skip all buffers if the 1st one is not valid */
432  if (i == 0) {
434  break;
435  }
436  }
437  }
438 
440 
441  /* clear telemetry SRAM region */
443 }
444 
446 {
448  && (cl_get_pmc_record_size() > 0)) {
449  if (CONFIG(SOC_INTEL_CRASHLOG_ON_RESET)) {
451  printk(BIOS_DEBUG, "Crashlog collection enabled on every reboot.\n");
452  }
454  } else {
455  printk(BIOS_DEBUG, "Skipping PMC crashLog collection. Data not present.\n");
456  }
457 
458  printk(BIOS_DEBUG, "m_cpu_crashLog_size : 0x%X bytes\n", cl_get_cpu_record_size());
459 
461  && (cl_get_cpu_record_size() > 0)) {
462  printk(BIOS_DEBUG, "CPU crashLog present.\n");
464  } else {
465  printk(BIOS_DEBUG, "Skipping CPU crashLog collection. Data not present.\n");
466  }
467 }
468 
469 bool cl_fill_cpu_records(void *cl_record)
470 {
471  void *cl_src_addr = NULL;
472 
474 
475  if (!cl_cpu_data_present() || m_cpu_crashLog_size == 0) {
476  printk(BIOS_DEBUG, "CPU crashLog not present, skipping.\n");
477  return false;
478  }
479 
480  printk(BIOS_DEBUG, "CPU crash data collection.\n");
481  cl_src_addr = cbmem_find(CBMEM_ID_CPU_CRASHLOG);
482  memcpy(cl_record, cl_src_addr, m_cpu_crashLog_size);
483 
484  return true;
485 }
486 
487 bool cl_fill_pmc_records(void *cl_record)
488 {
489  void *cl_src_addr = NULL;
490 
492 
493  if (!cl_pmc_data_present() || m_pmc_crashLog_size == 0) {
494  printk(BIOS_DEBUG, "PMC crashLog not present, skipping.\n");
495  return false;
496  }
497 
498  printk(BIOS_DEBUG, "PMC crash data collection.\n");
499  cl_src_addr = cbmem_find(CBMEM_ID_PMC_CRASHLOG);
500  memcpy(cl_record, cl_src_addr, m_pmc_crashLog_size);
501 
502  return true;
503 }
bool cl_pmc_sram_has_mmio_access(void)
Definition: crashlog.c:117
bool cl_pmc_data_present(void)
Definition: crashlog.c:260
int cl_get_total_data_size(void)
Definition: crashlog.c:230
int cl_get_pmc_record_size(void)
Definition: crashlog.c:245
cpu_crashlog_discovery_table_t cl_get_cpu_discovery_table(void)
Definition: crashlog.c:280
static u32 m_cpu_crashLog_size
Definition: crashlog.c:17
static pmc_crashlog_desc_table_t descriptor_table
Definition: crashlog.c:20
pmc_ipc_discovery_buf_t cl_get_pmc_discovery_buf(void)
Definition: crashlog.c:235
int cl_get_cpu_record_size(void)
Definition: crashlog.c:250
bool cl_cpu_data_present(void)
Definition: crashlog.c:255
static u32 m_pmc_crashLog_size
Definition: crashlog.c:16
static pmc_ipc_discovery_buf_t discovery_buf
Definition: crashlog.c:19
bool pmc_crashlog_support(void)
Definition: crashlog.c:270
void update_new_pmc_crashlog_size(u32 *pmc_crash_size)
Definition: crashlog.c:275
u32 cl_get_cpu_bar_addr(void)
Definition: crashlog.c:94
void update_new_cpu_crashlog_size(u32 *cpu_crash_size)
Definition: crashlog.c:285
pmc_crashlog_desc_table_t cl_get_pmc_descriptor_table(void)
Definition: crashlog.c:240
bool cpu_crashlog_support(void)
Definition: crashlog.c:265
bool cpu_cl_discovery(void)
Definition: crashlog.c:199
u32 cl_get_cpu_tmp_bar(void)
Definition: crashlog.c:112
static cpu_crashlog_discovery_table_t cpu_cl_disc_tab
Definition: crashlog.c:22
bool pmc_cl_discovery(void)
Definition: crashlog.c:29
u32 __weak cl_get_cpu_mb_int_addr(void)
Definition: crashlog.c:24
void reset_discovery_buffers(void)
Definition: crashlog.c:223
static void write32(void *addr, uint32_t val)
Definition: mmio.h:40
static uint32_t read32(const void *addr)
Definition: mmio.h:22
void * memcpy(void *dest, const void *src, size_t n)
Definition: memcpy.c:7
void * memset(void *dstpp, int c, size_t len)
Definition: memset.c:12
void * cbmem_add(u32 id, u64 size)
Definition: imd_cbmem.c:144
void * cbmem_find(u32 id)
Definition: imd_cbmem.c:166
#define CBMEM_ID_CPU_CRASHLOG
Definition: cbmem_id.h:20
#define CBMEM_ID_PMC_CRASHLOG
Definition: cbmem_id.h:38
bool cl_fill_pmc_records(void *cl_record)
Definition: crashlog.c:487
void collect_pmc_and_cpu_crashlog_from_srams(void)
Definition: crashlog.c:445
bool discover_crashlog(void)
Definition: crashlog.c:239
int cl_pmc_clear(void)
Definition: crashlog.c:193
int cpu_cl_clear_data(void)
Definition: crashlog.c:133
int cl_pmc_re_arm_after_reset(void)
Definition: crashlog.c:170
bool cl_copy_data_from_sram(u32 src_bar, u32 offset, u32 size, u32 *dest_addr, u32 buffer_index, bool pmc_sram)
Definition: crashlog.c:254
int pmc_cl_gen_descriptor_table(u32 desc_table_addr, pmc_crashlog_desc_table_t *descriptor_table)
Definition: crashlog.c:138
void cl_get_cpu_sram_data(void)
Definition: crashlog.c:386
int cpu_cl_mailbox_cmd(u8 cmd, u8 param)
Definition: crashlog.c:112
bool cl_fill_cpu_records(void *cl_record)
Definition: crashlog.c:469
int cpu_cl_poll_mailbox_ready(u32 cl_mailbox_addr)
Definition: crashlog.c:91
int cl_pmc_en_gen_on_all_reboot(void)
Definition: crashlog.c:218
void cl_get_pmc_sram_data(void)
Definition: crashlog.c:294
#define PMC_IPC_CMD_CRASHLOG
Definition: crashlog.h:16
#define CPU_CRASHLOG_MAILBOX_WAIT_TIMEOUT
Definition: crashlog.h:27
#define PMC_IPC_CMD_ID_CRASHLOG_ERASE
Definition: crashlog.h:19
#define PMC_IPC_CMD_ID_CRASHLOG_ON_RESET
Definition: crashlog.h:20
#define PMC_IPC_CMD_ID_CRASHLOG_RE_ARM_ON_RESET
Definition: crashlog.h:21
#define CPU_CRASHLOG_CMD_CLEAR
Definition: crashlog.h:25
#define CPU_CRASHLOG_MAILBOX_WAIT_STALL
Definition: crashlog.h:26
#define printk(level,...)
Definition: stdlib.h:16
@ CONFIG
Definition: dsi_common.h:201
#define BIT(nr)
Definition: ec_commands.h:45
static size_t offset
Definition: flashconsole.c:16
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
enum cb_err pmc_send_ipc_cmd(uint32_t cmd, const struct pmc_ipc_buffer *wbuf, struct pmc_ipc_buffer *rbuf)
Definition: pmc_ipc.c:81
#define PMC_IPC_CMD_SIZE_SHIFT
Definition: pmc_ipc.h:16
static uint32_t pmc_make_ipc_cmd(uint32_t cmd, uint32_t subcmd, uint32_t size)
Definition: pmc_ipc.h:56
const struct smm_save_state_ops *legacy_ops __weak
Definition: save_state.c:8
#define NULL
Definition: stddef.h:19
unsigned int uint32_t
Definition: stdint.h:14
uint32_t u32
Definition: stdint.h:51
unsigned long uintptr_t
Definition: stdint.h:21
uint16_t u16
Definition: stdint.h:48
uint8_t u8
Definition: stdint.h:45
void udelay(uint32_t us)
Definition: udelay.c:15