/* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Generic Xtensa target * * Copyright (C) 2020-2022 Cadence Design Systems, Inc. * * Copyright (C) 2019 Espressif Systems Ltd. * ***************************************************************************/ #ifndef OPENOCD_TARGET_XTENSA_H #define OPENOCD_TARGET_XTENSA_H #include "assert.h" #include #include #include "xtensa_regs.h" #include "xtensa_debug_module.h" /** * @file * Holds the interface to Xtensa cores. */ /* Big-endian vs. little-endian detection */ #define XT_ISBE(X) ((X)->target->endianness == TARGET_BIG_ENDIAN) /* 24-bit break; BE version field-swapped then byte-swapped for use in memory R/W fns */ #define XT_INS_BREAK_LE(S, T) (0x004000 | (((S) & 0xF) << 8) | (((T) & 0xF) << 4)) #define XT_INS_BREAK_BE(S, T) (0x000400 | (((S) & 0xF) << 12) | ((T) & 0xF)) #define XT_INS_BREAK(X, S, T) (XT_ISBE(X) ? XT_INS_BREAK_BE(S, T) : XT_INS_BREAK_LE(S, T)) /* 16-bit break; BE version field-swapped then byte-swapped for use in memory R/W fns */ #define XT_INS_BREAKN_LE(IMM4) (0xF02D | (((IMM4) & 0xF) << 8)) #define XT_INS_BREAKN_BE(IMM4) (0x0FD2 | (((IMM4) & 0xF) << 12)) #define XT_INS_BREAKN(X, IMM4) (XT_ISBE(X) ? XT_INS_BREAKN_BE(IMM4) : XT_INS_BREAKN_LE(IMM4)) #define XT_ISNS_SZ_MAX 3 /* PS register bits (LX) */ #define XT_PS_RING(_v_) ((uint32_t)((_v_) & 0x3) << 6) #define XT_PS_RING_MSK (0x3 << 6) #define XT_PS_RING_GET(_v_) (((_v_) >> 6) & 0x3) #define XT_PS_CALLINC_MSK (0x3 << 16) #define XT_PS_OWB_MSK (0xF << 8) #define XT_PS_WOE_MSK BIT(18) /* PS register bits (NX) */ #define XT_PS_DIEXC_MSK BIT(2) /* MS register bits (NX) */ #define XT_MS_DE_MSK BIT(5) #define XT_MS_DISPST_MSK (0x1f) #define XT_MS_DISPST_DBG (0x10) /* WB register bits (NX) */ #define XT_WB_P_SHIFT (0) #define XT_WB_P_MSK (0x7U << XT_WB_P_SHIFT) #define XT_WB_C_SHIFT (4) #define XT_WB_C_MSK (0x7U << XT_WB_C_SHIFT) #define XT_WB_N_SHIFT (8) #define XT_WB_N_MSK (0x7U << XT_WB_N_SHIFT) #define XT_WB_S_SHIFT (30) #define XT_WB_S_MSK (0x3U << XT_WB_S_SHIFT) /* IBREAKC register bits (NX) */ #define XT_IBREAKC_FB (0x80000000) /* Definitions for imprecise exception registers (NX) */ #define XT_IMPR_EXC_MSK (0x00000013) #define XT_MESRCLR_IMPR_EXC_MSK (0x00000090) #define XT_LOCAL_MEM_REGIONS_NUM_MAX 8 #define XT_AREGS_NUM_MAX 64 #define XT_USER_REGS_NUM_MAX 256 #define XT_MEM_ACCESS_NONE 0x0 #define XT_MEM_ACCESS_READ 0x1 #define XT_MEM_ACCESS_WRITE 0x2 #define XT_MAX_TIE_REG_WIDTH (512) /* TIE register file max 4096 bits */ #define XT_QUERYPKT_RESP_MAX (XT_MAX_TIE_REG_WIDTH * 2 + 1) enum xtensa_qerr_e { XT_QERR_INTERNAL = 0, XT_QERR_FAIL, XT_QERR_INVAL, XT_QERR_MEM, XT_QERR_NUM, }; /* An and ARn registers potentially used as scratch regs */ enum xtensa_ar_scratch_set_e { XT_AR_SCRATCH_A3 = 0, XT_AR_SCRATCH_AR3, XT_AR_SCRATCH_A4, XT_AR_SCRATCH_AR4, XT_AR_SCRATCH_NUM }; struct xtensa_keyval_info_s { char *chrval; int intval; }; enum xtensa_type { XT_UNDEF = 0, XT_LX, XT_NX, }; struct xtensa_cache_config { uint8_t way_count; uint32_t line_size; uint32_t size; int writeback; }; struct xtensa_local_mem_region_config { target_addr_t base; uint32_t size; int access; }; struct xtensa_local_mem_config { uint16_t count; struct xtensa_local_mem_region_config regions[XT_LOCAL_MEM_REGIONS_NUM_MAX]; }; struct xtensa_mmu_config { bool enabled; uint8_t itlb_entries_count; uint8_t dtlb_entries_count; }; struct xtensa_mpu_config { bool enabled; uint8_t nfgseg; uint32_t minsegsize; bool lockable; bool execonly; }; struct xtensa_irq_config { bool enabled; uint8_t irq_num; }; struct xtensa_high_prio_irq_config { bool enabled; uint8_t level_num; uint8_t excm_level; }; struct xtensa_debug_config { bool enabled; uint8_t irq_level; uint8_t ibreaks_num; uint8_t dbreaks_num; uint8_t perfcount_num; }; struct xtensa_tracing_config { bool enabled; uint32_t mem_sz; bool reversed_mem_access; }; struct xtensa_config { enum xtensa_type core_type; uint8_t aregs_num; bool windowed; bool coproc; bool exceptions; struct xtensa_irq_config irq; struct xtensa_high_prio_irq_config high_irq; struct xtensa_mmu_config mmu; struct xtensa_mpu_config mpu; struct xtensa_debug_config debug; struct xtensa_tracing_config trace; struct xtensa_cache_config icache; struct xtensa_cache_config dcache; struct xtensa_local_mem_config irom; struct xtensa_local_mem_config iram; struct xtensa_local_mem_config drom; struct xtensa_local_mem_config dram; struct xtensa_local_mem_config sram; struct xtensa_local_mem_config srom; }; typedef uint32_t xtensa_insn_t; enum xtensa_stepping_isr_mode { XT_STEPPING_ISR_OFF, /* interrupts are disabled during stepping */ XT_STEPPING_ISR_ON, /* interrupts are enabled during stepping */ }; enum xtensa_nx_reg_idx { XT_NX_REG_IDX_IBREAKC0 = 0, XT_NX_REG_IDX_WB, XT_NX_REG_IDX_MS, XT_NX_REG_IDX_IEVEC, /* IEVEC, IEEXTERN, and MESR must be contiguous */ XT_NX_REG_IDX_IEEXTERN, XT_NX_REG_IDX_MESR, XT_NX_REG_IDX_MESRCLR, XT_NX_REG_IDX_NUM }; /* Only supported in cores with in-CPU MMU. None of Espressif chips as of now. */ enum xtensa_mode { XT_MODE_RING0, XT_MODE_RING1, XT_MODE_RING2, XT_MODE_RING3, XT_MODE_ANY /* special value to run algorithm in current core mode */ }; struct xtensa_sw_breakpoint { struct breakpoint *oocd_bp; /* original insn */ uint8_t insn[XT_ISNS_SZ_MAX]; /* original insn size */ uint8_t insn_sz; /* 2 or 3 bytes */ }; /** * Xtensa algorithm data. */ struct xtensa_algorithm { /** User can set this to specify which core mode algorithm should be run in. */ enum xtensa_mode core_mode; /** Used internally to backup and restore core state. */ enum target_debug_reason ctx_debug_reason; xtensa_reg_val_t ctx_ps; }; #define XTENSA_COMMON_MAGIC 0x54E4E555U /** * Represents a generic Xtensa core. */ struct xtensa { unsigned int common_magic; struct xtensa_chip_common *xtensa_chip; struct xtensa_config *core_config; struct xtensa_debug_module dbg_mod; struct reg_cache *core_cache; unsigned int total_regs_num; unsigned int core_regs_num; bool regmap_contiguous; unsigned int genpkt_regs_num; struct xtensa_reg_desc **contiguous_regs_desc; struct reg **contiguous_regs_list; /* Per-config Xtensa registers as specified via "xtreg" in xtensa-core*.cfg */ struct xtensa_reg_desc *optregs; unsigned int num_optregs; struct reg *empty_regs; char qpkt_resp[XT_QUERYPKT_RESP_MAX]; /* An array of pointers to buffers to backup registers' values while algo is run on target. * Size is 'regs_num'. */ void **algo_context_backup; unsigned int eps_dbglevel_idx; unsigned int dbregs_num; struct target *target; bool reset_asserted; enum xtensa_stepping_isr_mode stepping_isr_mode; struct breakpoint **hw_brps; struct watchpoint **hw_wps; struct xtensa_sw_breakpoint *sw_brps; bool trace_active; bool permissive_mode; /* bypass memory checks */ bool suppress_dsr_errors; uint32_t smp_break; uint32_t spill_loc; unsigned int spill_bytes; uint8_t *spill_buf; int8_t probe_lsddr32p; /* Sometimes debug module's 'powered' bit is cleared after reset, but get set after some * time.This is the number of polling periods after which core is considered to be powered * off (marked as unexamined) if the bit retains to be cleared (e.g. if core is disabled by * SW running on target).*/ uint8_t come_online_probes_num; bool proc_syscall; bool halt_request; uint32_t nx_stop_cause; uint32_t nx_reg_idx[XT_NX_REG_IDX_NUM]; struct xtensa_keyval_info_s scratch_ars[XT_AR_SCRATCH_NUM]; bool regs_fetched; /* true after first register fetch completed successfully */ }; static inline struct xtensa *target_to_xtensa(struct target *target) { assert(target); struct xtensa *xtensa = target->arch_info; assert(xtensa->common_magic == XTENSA_COMMON_MAGIC); return xtensa; } int xtensa_init_arch_info(struct target *target, struct xtensa *xtensa, const struct xtensa_debug_module_config *dm_cfg); int xtensa_target_init(struct command_context *cmd_ctx, struct target *target); void xtensa_target_deinit(struct target *target); static inline bool xtensa_addr_in_mem(const struct xtensa_local_mem_config *mem, uint32_t addr) { for (unsigned int i = 0; i < mem->count; i++) { if (addr >= mem->regions[i].base && addr < mem->regions[i].base + mem->regions[i].size) return true; } return false; } static inline bool xtensa_data_addr_valid(struct target *target, uint32_t addr) { struct xtensa *xtensa = target_to_xtensa(target); if (xtensa_addr_in_mem(&xtensa->core_config->drom, addr)) return true; if (xtensa_addr_in_mem(&xtensa->core_config->dram, addr)) return true; if (xtensa_addr_in_mem(&xtensa->core_config->sram, addr)) return true; return false; } static inline int xtensa_queue_dbg_reg_read(struct xtensa *xtensa, enum xtensa_dm_reg reg, uint8_t *data) { struct xtensa_debug_module *dm = &xtensa->dbg_mod; if (!xtensa->core_config->trace.enabled && (reg <= XDMREG_MEMADDREND || (reg >= XDMREG_PMG && reg <= XDMREG_PMSTAT7))) { LOG_ERROR("Can not access %u reg when Trace Port option disabled!", reg); return ERROR_FAIL; } return dm->dbg_ops->queue_reg_read(dm, reg, data); } static inline int xtensa_queue_dbg_reg_write(struct xtensa *xtensa, enum xtensa_dm_reg reg, uint32_t data) { struct xtensa_debug_module *dm = &xtensa->dbg_mod; if (!xtensa->core_config->trace.enabled && (reg <= XDMREG_MEMADDREND || (reg >= XDMREG_PMG && reg <= XDMREG_PMSTAT7))) { LOG_ERROR("Can not access %u reg when Trace Port option disabled!", reg); return ERROR_FAIL; } return dm->dbg_ops->queue_reg_write(dm, reg, data); } static inline int xtensa_core_status_clear(struct target *target, uint32_t bits) { struct xtensa *xtensa = target_to_xtensa(target); return xtensa_dm_core_status_clear(&xtensa->dbg_mod, bits); } int xtensa_core_status_check(struct target *target); int xtensa_examine(struct target *target); int xtensa_wakeup(struct target *target); int xtensa_smpbreak_set(struct target *target, uint32_t set); int xtensa_smpbreak_get(struct target *target, uint32_t *val); int xtensa_smpbreak_write(struct xtensa *xtensa, uint32_t set); int xtensa_smpbreak_read(struct xtensa *xtensa, uint32_t *val); xtensa_reg_val_t xtensa_reg_get(struct target *target, enum xtensa_reg_id reg_id); void xtensa_reg_set(struct target *target, enum xtensa_reg_id reg_id, xtensa_reg_val_t value); void xtensa_reg_set_deep_relgen(struct target *target, enum xtensa_reg_id a_idx, xtensa_reg_val_t value); int xtensa_fetch_all_regs(struct target *target); int xtensa_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class); uint32_t xtensa_cause_get(struct target *target); void xtensa_cause_clear(struct target *target); void xtensa_cause_reset(struct target *target); int xtensa_poll(struct target *target); void xtensa_on_poll(struct target *target); int xtensa_halt(struct target *target); int xtensa_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution); int xtensa_prepare_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution); int xtensa_do_resume(struct target *target); int xtensa_step(struct target *target, int current, target_addr_t address, int handle_breakpoints); int xtensa_do_step(struct target *target, int current, target_addr_t address, int handle_breakpoints); int xtensa_mmu_is_enabled(struct target *target, int *enabled); int xtensa_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); int xtensa_read_buffer(struct target *target, target_addr_t address, uint32_t count, uint8_t *buffer); int xtensa_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); int xtensa_write_buffer(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer); int xtensa_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum); int xtensa_assert_reset(struct target *target); int xtensa_deassert_reset(struct target *target); int xtensa_soft_reset_halt(struct target *target); int xtensa_breakpoint_add(struct target *target, struct breakpoint *breakpoint); int xtensa_breakpoint_remove(struct target *target, struct breakpoint *breakpoint); int xtensa_watchpoint_add(struct target *target, struct watchpoint *watchpoint); int xtensa_watchpoint_remove(struct target *target, struct watchpoint *watchpoint); int xtensa_start_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, void *arch_info); int xtensa_wait_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t exit_point, unsigned int timeout_ms, void *arch_info); int xtensa_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, unsigned int timeout_ms, void *arch_info); void xtensa_set_permissive_mode(struct target *target, bool state); const char *xtensa_get_gdb_arch(const struct target *target); int xtensa_gdb_query_custom(struct target *target, const char *packet, char **response_p); COMMAND_HELPER(xtensa_cmd_xtdef_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_xtopt_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_xtmem_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_xtmpu_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_xtmmu_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_xtreg_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_xtregfmt_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_permissive_mode_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_mask_interrupts_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_smpbreak_do, struct target *target); COMMAND_HELPER(xtensa_cmd_perfmon_dump_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_perfmon_enable_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_tracestart_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_tracestop_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_tracedump_do, struct xtensa *xtensa, const char *fname); extern const struct command_registration xtensa_command_handlers[]; #endif /* OPENOCD_TARGET_XTENSA_H */