138 lines
3.0 KiB
C
138 lines
3.0 KiB
C
/*
|
|
* Copyright (c) 2021 Facebook, Inc. and its affiliates
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/debug/coredump.h>
|
|
|
|
#ifndef CONFIG_64BIT
|
|
#define ARCH_HDR_VER 1
|
|
#else
|
|
#define ARCH_HDR_VER 2
|
|
#endif
|
|
|
|
struct riscv_arch_block {
|
|
#ifdef CONFIG_64BIT
|
|
struct {
|
|
uint64_t ra;
|
|
uint64_t tp;
|
|
uint64_t t0;
|
|
uint64_t t1;
|
|
uint64_t t2;
|
|
uint64_t a0;
|
|
uint64_t a1;
|
|
uint64_t a2;
|
|
uint64_t a3;
|
|
uint64_t a4;
|
|
uint64_t a5;
|
|
uint64_t a6;
|
|
uint64_t a7;
|
|
uint64_t t3;
|
|
uint64_t t4;
|
|
uint64_t t5;
|
|
uint64_t t6;
|
|
uint64_t pc;
|
|
} r;
|
|
#else /* !CONFIG_64BIT */
|
|
struct {
|
|
uint32_t ra;
|
|
uint32_t tp;
|
|
uint32_t t0;
|
|
uint32_t t1;
|
|
uint32_t t2;
|
|
uint32_t a0;
|
|
uint32_t a1;
|
|
uint32_t a2;
|
|
uint32_t a3;
|
|
uint32_t a4;
|
|
uint32_t a5;
|
|
#if !defined(CONFIG_RISCV_ISA_RV32E)
|
|
uint32_t a6;
|
|
uint32_t a7;
|
|
uint32_t t3;
|
|
uint32_t t4;
|
|
uint32_t t5;
|
|
uint32_t t6;
|
|
#endif /* !CONFIG_RISCV_ISA_RV32E */
|
|
uint32_t pc;
|
|
} r;
|
|
#endif /* CONFIG_64BIT */
|
|
} __packed;
|
|
|
|
/*
|
|
* This might be too large for stack space if defined
|
|
* inside function. So do it here.
|
|
*/
|
|
static struct riscv_arch_block arch_blk;
|
|
|
|
void arch_coredump_info_dump(const struct arch_esf *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));
|
|
|
|
/*
|
|
* 33 registers expected by GDB. Not all are in ESF but the GDB stub will need
|
|
* to send all 33 as one packet. The stub will need to send undefined for
|
|
* registers not presented in coredump.
|
|
*/
|
|
arch_blk.r.ra = esf->ra;
|
|
arch_blk.r.t0 = esf->t0;
|
|
arch_blk.r.t1 = esf->t1;
|
|
arch_blk.r.t2 = esf->t2;
|
|
arch_blk.r.a0 = esf->a0;
|
|
arch_blk.r.a1 = esf->a1;
|
|
arch_blk.r.a2 = esf->a2;
|
|
arch_blk.r.a3 = esf->a3;
|
|
arch_blk.r.a4 = esf->a4;
|
|
arch_blk.r.a5 = esf->a5;
|
|
#if !defined(CONFIG_RISCV_ISA_RV32E)
|
|
arch_blk.r.t3 = esf->t3;
|
|
arch_blk.r.t4 = esf->t4;
|
|
arch_blk.r.t5 = esf->t5;
|
|
arch_blk.r.t6 = esf->t6;
|
|
arch_blk.r.a6 = esf->a6;
|
|
arch_blk.r.a7 = esf->a7;
|
|
#endif /* !CONFIG_RISCV_ISA_RV32E */
|
|
arch_blk.r.pc = esf->mepc;
|
|
|
|
/* 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_RISC_V;
|
|
}
|
|
|
|
#if defined(CONFIG_DEBUG_COREDUMP_DUMP_THREAD_PRIV_STACK)
|
|
void arch_coredump_priv_stack_dump(struct k_thread *thread)
|
|
{
|
|
uintptr_t start_addr, end_addr;
|
|
|
|
/* See: zephyr/include/zephyr/arch/riscv/arch.h */
|
|
if (IS_ENABLED(CONFIG_PMP_POWER_OF_TWO_ALIGNMENT)) {
|
|
start_addr = thread->arch.priv_stack_start + Z_RISCV_STACK_GUARD_SIZE;
|
|
} else {
|
|
start_addr = thread->stack_info.start - CONFIG_PRIVILEGED_STACK_SIZE;
|
|
}
|
|
end_addr = Z_STACK_PTR_ALIGN(thread->arch.priv_stack_start + K_KERNEL_STACK_RESERVED +
|
|
CONFIG_PRIVILEGED_STACK_SIZE);
|
|
|
|
coredump_memory_dump(start_addr, end_addr);
|
|
}
|
|
#endif /* CONFIG_DEBUG_COREDUMP_DUMP_THREAD_PRIV_STACK */
|