zephyr/arch/xtensa/core/coredump.c

168 lines
3.9 KiB
C

/*
* Copyright (c) 2021 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <zephyr/debug/coredump.h>
#include <xtensa-asm2.h>
#define ARCH_HDR_VER 1
#define XTENSA_BLOCK_HDR_VER 2
enum xtensa_soc_code {
XTENSA_SOC_UNKNOWN = 0,
XTENSA_SOC_SAMPLE_CONTROLLER,
XTENSA_SOC_ESP32,
XTENSA_SOC_INTEL_ADSP,
};
struct xtensa_arch_block {
/* Each Xtensa SOC can omit registers (e.g. loop
* registers) or assign different index numbers
* in xtensa-config.c. GDB identifies registers
* based on these indices
*
* (This must be the first field or the GDB server
* won't be able to unpack the struct while parsing)
*/
uint8_t soc;
/* Future versions of Xtensa coredump may expand
* minimum set of registers
*
* (This should stay the second field for the same
* reason as the first once we have more versions)
*/
uint16_t version;
uint8_t toolchain;
struct {
/* Minimum set shown by GDB 'info registers',
* skipping user-defined register EXPSTATE
*
* WARNING: IF YOU CHANGE THE ORDER OF THE REGISTERS,
* YOU MUST UPDATE THE ORDER OF THE REGISTERS IN
* EACH OF THE XtensaSoc_ RegNum enums IN
* scripts/coredump/gdbstubs/arch/xtensa.py TO MATCH.
* See xtensa.py's map_register function for details
*/
uint32_t pc;
uint32_t exccause;
uint32_t excvaddr;
uint32_t sar;
uint32_t ps;
#if XCHAL_HAVE_S32C1I
uint32_t scompare1;
#endif
uint32_t a0;
uint32_t a1;
uint32_t a2;
uint32_t a3;
uint32_t a4;
uint32_t a5;
uint32_t a6;
uint32_t a7;
uint32_t a8;
uint32_t a9;
uint32_t a10;
uint32_t a11;
uint32_t a12;
uint32_t a13;
uint32_t a14;
uint32_t a15;
#if XCHAL_HAVE_LOOPS
uint32_t lbeg;
uint32_t lend;
uint32_t lcount;
#endif
} r;
} __packed;
/*
* This might be too large for stack space if defined
* inside function. So do it here.
*/
static struct xtensa_arch_block arch_blk;
void arch_coredump_info_dump(const z_arch_esf_t *esf)
{
struct coredump_arch_hdr_t hdr = {
.id = COREDUMP_ARCH_HDR_ID,
.hdr_version = ARCH_HDR_VER,
.num_bytes = sizeof(arch_blk),
};
/* Nothing to process */
if (esf == NULL) {
return;
}
(void)memset(&arch_blk, 0, sizeof(arch_blk));
arch_blk.version = XTENSA_BLOCK_HDR_VER;
#if CONFIG_SOC_XTENSA_SAMPLE_CONTROLLER
arch_blk.soc = XTENSA_SOC_SAMPLE_CONTROLLER;
#elif CONFIG_SOC_ESP32
arch_blk.soc = XTENSA_SOC_ESP32;
#elif CONFIG_SOC_FAMILY_INTEL_ADSP
arch_blk.soc = XTENSA_SOC_INTEL_ADSP;
#else
arch_blk.soc = XTENSA_SOC_UNKNOWN;
#endif
/* Set in top-level CMakeLists.txt for use with Xtensa coredump */
arch_blk.toolchain = XTENSA_TOOLCHAIN_VARIANT;
__asm__ volatile("rsr.exccause %0" : "=r"(arch_blk.r.exccause));
int *bsa = *(int **)esf;
arch_blk.r.pc = bsa[BSA_PC_OFF/4];
__asm__ volatile("rsr.excvaddr %0" : "=r"(arch_blk.r.excvaddr));
arch_blk.r.ps = bsa[BSA_PS_OFF/4];
#if XCHAL_HAVE_S32C1I
arch_blk.r.scompare1 = bsa[BSA_SCOMPARE1_OFF];
#endif
arch_blk.r.sar = bsa[BSA_SAR_OFF/4];
arch_blk.r.a0 = bsa[BSA_A0_OFF/4];
arch_blk.r.a1 = (uint32_t)((char *)bsa) + BASE_SAVE_AREA_SIZE;
arch_blk.r.a2 = bsa[BSA_A2_OFF/4];
arch_blk.r.a3 = bsa[BSA_A3_OFF/4];
if (bsa - esf > 4) {
arch_blk.r.a4 = bsa[-4];
arch_blk.r.a5 = bsa[-3];
arch_blk.r.a6 = bsa[-2];
arch_blk.r.a7 = bsa[-1];
}
if (bsa - esf > 8) {
arch_blk.r.a8 = bsa[-8];
arch_blk.r.a9 = bsa[-7];
arch_blk.r.a10 = bsa[-6];
arch_blk.r.a11 = bsa[-5];
}
if (bsa - esf > 12) {
arch_blk.r.a12 = bsa[-12];
arch_blk.r.a13 = bsa[-11];
arch_blk.r.a14 = bsa[-10];
arch_blk.r.a15 = bsa[-9];
}
#if XCHAL_HAVE_LOOPS
arch_blk.r.lbeg = bsa[BSA_LBEG_OFF/4];
arch_blk.r.lend = bsa[BSA_LEND_OFF/4];
arch_blk.r.lcount = bsa[BSA_LCOUNT_OFF/4];
#endif
/* Send for output */
coredump_buffer_output((uint8_t *)&hdr, sizeof(hdr));
coredump_buffer_output((uint8_t *)&arch_blk, sizeof(arch_blk));
}
uint16_t arch_coredump_tgt_code_get(void)
{
return COREDUMP_TGT_XTENSA;
}