The trap message consists of a Format 3 Subformat 1 e-trace message. According to the Efficient Trace for RISC-V spec, section "Format 3 thaddr, address and privilege fields", the 'thaddr' will be zero if:
- we can't infer the EPC after an uninferable PC discontinuity (like traps). This doesn't happen in our current TCG backend - we'll always know the trap EPC in riscv_cpu_do_interrupt(); - a second interrupt/exception happens while the handler of the first trap hasn't exited. This also doesn't happen in TCG given that we do not emulate a multi-insn pipeline model, i.e. we'll only retire one insns at a time. This means that we'll always send trap packets with 'thaddr' set to 1, thus we're hardcoding it in the message helper. Signed-off-by: Daniel Henrique Barboza <[email protected]> --- hw/riscv/rv-trace-messages.c | 94 ++++++++++++++++++++++++++++++++++++ hw/riscv/rv-trace-messages.h | 5 ++ 2 files changed, 99 insertions(+) diff --git a/hw/riscv/rv-trace-messages.c b/hw/riscv/rv-trace-messages.c index 215135dd47..3e9466633d 100644 --- a/hw/riscv/rv-trace-messages.c +++ b/hw/riscv/rv-trace-messages.c @@ -35,6 +35,24 @@ typedef struct RVTraceSyncPayload { } RVTraceSyncPayload; #define SYNC_PAYLOAD_SIZE_64BITS 9 +/* + * Format 3 subformat 1 without 'time' and 'context' fields + */ +typedef struct RVTraceTrapPayload { + uint8_t format:2; + uint8_t subformat:2; + uint8_t branch:1; + uint8_t privilege:3; + uint8_t ecause:6; + uint8_t interrupt:1; + uint8_t thaddr:1; + uint32_t addressLow; + uint32_t addressHigh; + uint32_t tvalLow; + uint32_t tvalHigh; +} RVTraceTrapPayload; +#define TRAP_PAYLOAD_SIZE_64BITS 18 + static void rv_etrace_write_bits(uint8_t *bytes, uint32_t bit_pos, uint32_t num_bits, uint32_t val) { @@ -92,3 +110,79 @@ size_t rv_etrace_gen_encoded_sync_msg(uint8_t *buf, uint64_t pc, return HEADER_SIZE + SYNC_PAYLOAD_SIZE_64BITS; } + +/* + * Note: this function assumes thaddr = 1. + */ +size_t rv_etrace_gen_encoded_trap_msg(uint8_t *buf, uint64_t trap_addr, + TracePrivLevel priv_level, + uint8_t ecause, + bool is_interrupt, + uint64_t tval) +{ + RVTraceTrapPayload payload = {.format = 0b11, + .subformat = 0b01, + .branch = 1, + .privilege = priv_level, + .ecause = ecause}; + RVTraceMessageHeader header = {.flow = 0, .extend = 0, + .length = TRAP_PAYLOAD_SIZE_64BITS}; + uint8_t bit_pos; + + payload.addressLow = extract64(trap_addr, 0, 32); + payload.addressHigh = extract64(trap_addr, 32, 32); + + /* + * When interrupt = 1 'tval' is ommited. Take 8 bytes + * from the final size. + */ + if (is_interrupt) { + header.length = TRAP_PAYLOAD_SIZE_64BITS - 8; + } + + rv_etrace_write_header(buf, header); + bit_pos = 8; + + rv_etrace_write_bits(buf, bit_pos, 2, payload.format); + bit_pos += 2; + rv_etrace_write_bits(buf, bit_pos, 2, payload.subformat); + bit_pos += 2; + rv_etrace_write_bits(buf, bit_pos, 1, payload.branch); + bit_pos += 1; + rv_etrace_write_bits(buf, bit_pos, 3, payload.privilege); + bit_pos += 3; + + rv_etrace_write_bits(buf, bit_pos, 6, payload.ecause); + bit_pos += 6; + + if (is_interrupt) { + rv_etrace_write_bits(buf, bit_pos, 1, 1); + } else { + rv_etrace_write_bits(buf, bit_pos, 1, 0); + } + bit_pos += 1; + + /* thaddr is hardcoded to 1 for now */ + rv_etrace_write_bits(buf, bit_pos, 1, 1); + bit_pos += 1; + + rv_etrace_write_bits(buf, bit_pos, 32, payload.addressLow); + bit_pos += 32; + rv_etrace_write_bits(buf, bit_pos, 32, payload.addressHigh); + bit_pos += 32; + + /* Skip trap_addr if is_interrupt */ + if (is_interrupt) { + goto out; + } + + payload.tvalLow = extract64(trap_addr, 0, 32); + payload.tvalHigh = extract64(trap_addr, 32, 32); + + rv_etrace_write_bits(buf, bit_pos, 32, payload.tvalLow); + bit_pos += 32; + rv_etrace_write_bits(buf, bit_pos, 32, payload.tvalHigh); + +out: + return HEADER_SIZE + header.length; +} diff --git a/hw/riscv/rv-trace-messages.h b/hw/riscv/rv-trace-messages.h index aeafea8849..f3e38b571f 100644 --- a/hw/riscv/rv-trace-messages.h +++ b/hw/riscv/rv-trace-messages.h @@ -21,5 +21,10 @@ typedef enum { size_t rv_etrace_gen_encoded_sync_msg(uint8_t *buf, uint64_t pc, TracePrivLevel priv_level); +size_t rv_etrace_gen_encoded_trap_msg(uint8_t *buf, uint64_t trap_addr, + TracePrivLevel priv_level, + uint8_t ecause, + bool is_interrupt, + uint64_t tval); #endif -- 2.51.1
