zephyr/arch/xtensa/core/coredump.c
Yong Cong Sin bbe5e1e6eb build: namespace the generated headers with zephyr/
Namespaced the generated headers with `zephyr` to prevent
potential conflict with other headers.

Introduce a temporary Kconfig `LEGACY_GENERATED_INCLUDE_PATH`
that is enabled by default. This allows the developers to
continue the use of the old include paths for the time being
until it is deprecated and eventually removed. The Kconfig will
generate a build-time warning message, similar to the
`CONFIG_TIMER_RANDOM_GENERATOR`.

Updated the includes path of in-tree sources accordingly.

Most of the changes here are scripted, check the PR for more
info.

Signed-off-by: Yong Cong Sin <ycsin@meta.com>
2024-05-28 22:03:55 +02:00

192 lines
4.8 KiB
C

/*
* Copyright (c) 2021 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <zephyr/debug/coredump.h>
#include <xtensa_asm2_context.h>
#include <zephyr/offsets.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,
XTENSA_SOC_ESP32S2,
XTENSA_SOC_ESP32S3,
XTENSA_SOC_DC233C,
};
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_FAMILY_INTEL_ADSP
arch_blk.soc = XTENSA_SOC_INTEL_ADSP;
#elif CONFIG_SOC_SERIES_ESP32
arch_blk.soc = XTENSA_SOC_ESP32;
#elif CONFIG_SOC_SERIES_ESP32S2
arch_blk.soc = XTENSA_SOC_ESP32S2;
#elif CONFIG_SOC_SERIES_ESP32S3
arch_blk.soc = XTENSA_SOC_ESP32S3;
#elif CONFIG_SOC_XTENSA_DC233C
arch_blk.soc = XTENSA_SOC_DC233C;
#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));
_xtensa_irq_stack_frame_raw_t *frame = (void *)esf;
_xtensa_irq_bsa_t *bsa = frame->ptr_to_bsa;
uintptr_t num_high_regs;
int regs_blk_remaining;
/* Calculate number of high registers. */
num_high_regs = (uint8_t *)bsa - (uint8_t *)frame + sizeof(void *);
num_high_regs /= sizeof(uintptr_t);
/* And high registers are always comes in 4 in a block. */
regs_blk_remaining = (int)num_high_regs / 4;
arch_blk.r.pc = bsa->pc;
__asm__ volatile("rsr.excvaddr %0" : "=r"(arch_blk.r.excvaddr));
arch_blk.r.ps = bsa->ps;
#if XCHAL_HAVE_S32C1I
arch_blk.r.scompare1 = bsa->scompare1;
#endif
arch_blk.r.sar = bsa->sar;
arch_blk.r.a0 = bsa->a0;
arch_blk.r.a1 = (uint32_t)((char *)bsa) + sizeof(*bsa);
arch_blk.r.a2 = bsa->a2;
arch_blk.r.a3 = bsa->a3;
if (regs_blk_remaining > 0) {
regs_blk_remaining--;
arch_blk.r.a4 = frame->blks[regs_blk_remaining].r0;
arch_blk.r.a5 = frame->blks[regs_blk_remaining].r1;
arch_blk.r.a6 = frame->blks[regs_blk_remaining].r2;
arch_blk.r.a7 = frame->blks[regs_blk_remaining].r3;
}
if (regs_blk_remaining > 0) {
regs_blk_remaining--;
arch_blk.r.a8 = frame->blks[regs_blk_remaining].r0;
arch_blk.r.a9 = frame->blks[regs_blk_remaining].r1;
arch_blk.r.a10 = frame->blks[regs_blk_remaining].r2;
arch_blk.r.a11 = frame->blks[regs_blk_remaining].r3;
}
if (regs_blk_remaining > 0) {
arch_blk.r.a12 = frame->blks[regs_blk_remaining].r0;
arch_blk.r.a13 = frame->blks[regs_blk_remaining].r1;
arch_blk.r.a14 = frame->blks[regs_blk_remaining].r2;
arch_blk.r.a15 = frame->blks[regs_blk_remaining].r3;
}
#if XCHAL_HAVE_LOOPS
arch_blk.r.lbeg = bsa->lbeg;
arch_blk.r.lend = bsa->lend;
arch_blk.r.lcount = bsa->lcount;
#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;
}