/*
 * Copyright (c) 2021 Facebook, Inc. and its affiliates
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <string.h>
#include <zephyr/debug/coredump.h>

#define ARCH_HDR_VER 1

struct riscv_arch_block {
	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;
} __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 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));

	/*
	 * 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;
}
