SBI Debug Trigger Extension Proposal (Draft v4)


Anup Patel
 

Hi All,

To support native debugging in S-mode and VS-mode, we need
a SBI Debug Trigger extension which complements the Sdtrig
extension.

Below is the draft proposal of the SBI Debug Trigger Extension...

Many thanks to folks (CC'ed here) who provided early feedback
and helped improve this proposal.

The proposed SBI extension is highly inspired from Linux HW
breakpoint infrastructure which is built on top of the Linux
perf subsystem.

Please review and provide your feedback.

Regards,
Anup

SBI Debug Trigger Extension (EID #0x44425452 "DBTR")
====================================================

The RISC-V Sdtrig ISA extension allows machine-mode software to
directly configure debug triggers which in-turn allows native
(or hosted) debugging without any external debugger.

The SBI debug trigger extension defines a SBI based abstraction to
provide native debugging for supervisor-mode software such that it:
1) Suitable for the rich operating systems and hypervisors running
in supervisor-mode.
2) Allows Guest (VS-mode) and Hypervisor (HS-mode) to share debug
triggers on a HART.

Some of the functions defined by this SBI extension have physical
memory as parameters for input and/or output. This physical memory
parameter MUST satisfy following requirements:
1) The base address of the physical memory MUST be 16-byte aligned
so that it is machine word aligned for RV32, RV64 and RV128.
2) The SBI implementation MUST check that the supervisor-mode
software is allowed to read and write the specified physical
memory on the calling HART.
3) The SBI implementation MUST access the specified physical
memory using the PMA attribute.
Note: If the supervisor-mode software access the same physical
memory using memory type different from PMA then a loss of
coherence or unexpected memory ordering may occur and the
invoking software should follow the rules and sequences defined
in the RISC-V Svpbmt specification to prevent the loss of
coherence and memory ordering.

Each debug trigger is assigned a logical number called `trig_idx`
by the SBI implementation. If total number of debug triggers are
`N` then `0 <= trig_idx < N`.

The configuration of each debug trigger is expressed by three
entities `trig_tdata1`, `trig_tdata2`, and `trig_tdata3` which
are same as the `tdata1`, `tdata2`, and `tdata3` CSRs defined by
the RISC-V Sdtrig specification but with the following additional
constraints:
1) The `trig_tdata1.dmode` bit should always be zero.
2) The `trig_tdata1.m` bit should always be zero.
3) The `trig_tdata1.action` bits should always be zero.

The SBI implementation must also maintain an additional software
state for each debug trigger called `trig_state` which is encoded
as follows:
reserved [XLEN-1:5] - Reserved for future use.
vs [4:4] - Saved copy of the `trig_tdata1.vs` bit.
vu [3:3] - Saved copy of the `trig_tdata1.vu` bit.
s [2:2] - Saved copy of the `trig_tdata1.s` bit.
u [1:1] - Saved copy of the `trig_tdata1.u` bit.
mapped [0:0] - When set, the trigger has been mapped to
some HW debug trigger.

Function: Get number of triggers (FID #0)
-----------------------------------------

struct sbiret sbi_debug_num_triggers(unsigned long trig_tdata1)

Get the number of per-HART debug triggers which can support the
trigger configuration specified by `trig_tdata1` parameter.

The SBI implementation must return the total number of per-HART
debug triggers when `trig_tdata1 == 0`.

Returns the number of per-HART debug triggers in `sbiret.value`
and always returns SBI_SUCCESS in `sbiret.error`.

Function: Read triggers (FID #1)
--------------------------------

struct sbiret sbi_debug_read_triggers(unsigned long trig_idx_base,
unsigned long trig_count,
unsigned long out_addr_div_by_16)

Read the trigger state and configuration for a range of debug triggers
specified by `trig_idx_base` and `trig_count` parameters on the calling
HART.

The state and configuration of triggers will be written to an output
memory of size `trig_count * 4 * (XLEN / 8)` bytes. The base physical
address of the output memory right shifted by 4 is specified by the
`out_addr_div_by_16` parameter.

For i'th debug trigger in the specified range, the trigger configuration
consists of four XLEN-bit words written in little-endian format at
`offset = i * 4 * (XLEN / 8)` of the output memory. The contents of
output trigger configuration words are as follows:
word[0] = trig_state
word[1] = trig_tdata1
word[2] = trig_tdata2
word[3] = trig_tdata3

The possible error codes returned in `sbiret.error` are below.

Errors:
SBI_SUCCESS - Configuration read successfully.
SBI_ERR_INVALID_ADDRESS - The physical memory pointed by the
`out_addr_div_by_16` parameter is not
accessible to supervisor-mode.
SBI_ERR_INVALID_PARAM - Either `trig_idx_base + trig_count` or
`trig_idx_base` is greater than the total
number of triggers.

Function: Install triggers (FID #2)
-----------------------------------

struct sbiret sbi_debug_install_triggers(unsigned long trig_count,
unsigned long in_addr_div_by_16,
unsigned long out_addr_div_by_16)

Install debug triggers based on an array of trigger configurations
specified through an input memory and return the `trig_idx` of each
installed debug trigger in an output memory.

The `trig_count` parameter represents the number of debug triggers
to be installed.

The base physical address of the input memory right shifted by 4
is specified by the `in_addr_div_by_16` parameter and the size of
input memory is `trig_count * 4 * (XLEN / 8)` bytes. The i'th input
trigger configuration is at `offset = i * 4 * (XLEN / 8)` of the
input memory consisting of four consecutive XLEN-bit words in
little-endian format. The contents of each trigger configuration
are follows:
word[0] = Reserved for future use and should be zero
word[1] = trig_tdata1
word[2] = trig_tdata2
word[3] = trig_tdata3

The base physical address of the output memory right shifted by
4 is specified by the `out_addr_div_by_16` parameter and the size
of output memory is `trig_count * (XLEN / 8)` bytes. The `trig_idx`
assigned for the i'th input trigger configuration is written at
`offset = i * (XLEN / 8)` of the output memory in little-endian
format.

For each input trigger configuration in the input memory, the SBI
implementation should:
1) Map a free `trig_idx` with an unused HW debug trigger that
matches the trigger configuration.
2) Save a copy of the `trig_tdata1.vs`, `trig_tdata1.vu`,
`trig_tdata1.s`, and `trig_tdata.u` bits in `trig_state`.
3) Update the `tdata1`, `tdata2`, and `tdata3` CSRs of the
HW debug trigger.

Additionally for each input trigger configuration chain, the
SBI implementation MUST assign contiguous `trig_idx` values
and contiguous HW debug triggers when installing debug triggers.

The last trigger configuration in the input memory MUST not have
`trig_tdata1.chain == 1` for `trig_tdata1.type = 2 or 6` to prevent
incomplete trigger configuration chain in input memory.

This function succeeds and output memory is written with `trig_idx`
values only if the SBI implementation is able to install a debug
trigger for each input trigger configuration.

The possible error codes returned in `sbiret.error` are below.

Errors:
SBI_SUCCESS - Triggers installed successfully. The
`sbiret.value` will be set to zero.
SBI_ERR_INVALID_ADDRESS - The physical memory pointed by the
`in_addr_div_by_16` or `out_addr_div_by_16`
parameter is not accessible to supervisor-mode.
The `sbiret.value` will be set to zero.
SBI_ERR_INVALID_PARAM - One of the input trigger configuration has
an invalid value. The `sbiret.value` will
be set to the array index of failing input
trigger configuration.
SBI_ERR_NOT_SUPPORTED - One of the input trigger configuration can't
be programmed due to unimplemented optional
bits in `tdata1`, `tdata2`, or `tdata3` CSRs.
The `sbiret.value` will be set to the array
index of failing input trigger configuration.
SBI_ERR_FAILED - Failed to assign `trig_idx` or HW debug
trigger for one of the input trigger
configuration. The `sbiret.value` will be
set to the array index of failing input
trigger configuration.

Function: Uninstall a set of triggers (FID #3)
----------------------------------------------

struct sbiret sbi_debug_uninstall_triggers(unsigned long trig_idx_base,
unsigned long trig_idx_mask)

Uninstall a set of debug triggers specified by the `trig_idx_base` and
`trig_idx_mask` parameters on the calling HART.

For each debug trigger in the specified set of debug triggers, the
SBI implementation should:
1) Clear the `tdata1`, `tdata2`, and `tdata3` CSRs of the mapped
HW debug trigger.
2) Clear the `trig_state` of the debug trigger.
3) Unmap the HW debug trigger from `trig_idx` and free both of
them for future trigger installations.

The possible error codes returned in `sbiret.error` are below.

Errors:
SBI_SUCCESS - Trigger uninstalled successfully.
SBI_ERR_INVALID_PARAM - One of the `trig_idx` in the specified set
of debug triggers is either:
1) Greater than the total number of triggers.
2) Represents a debug trigger that is not
mapped to any HW debug trigger.

Function: Enable a set of triggers (FID #4)
-------------------------------------------

struct sbiret sbi_debug_enable_triggers(unsigned long trig_idx_base,
unsigned long trig_idx_mask)

Enable a set of debug triggers specified by `trig_idx_base` and
`trig_idx_mask` parameters on the calling HART.

To enable a debug trigger, SBI implementation MUST restore the
`vs`, `vu`, `s`, and `u` bits of the mapped HW debug trigger
from their saved copy in `trig_state`.

The possible error codes returned in `sbiret.error` are below.

Errors:
SBI_SUCCESS - Trigger enabled successfully.
SBI_ERR_INVALID_PARAM - One of the `trig_idx` in the specified set
of debug triggers is either:
1) Greater than the total number of triggers.
2) Represents a debug trigger that is not
mapped to any HW debug trigger.

Function: Disable a set of triggers (FID #5)
--------------------------------------------

struct sbiret sbi_debug_disable_triggers(unsigned long trig_idx_base,
unsigned long trig_idx_mask)

Disable a set of debug triggers specified by `trig_idx_base` and
`trig_idx_mask` parameters on the calling HART.

To disable a debug trigger, SBI implementation MUST clear the `vs`,
`vu`, `s`, and `u` bits of the mapped HW debug trigger.

The possible error codes returned in `sbiret.error` are below.

Errors:
SBI_SUCCESS - Trigger disabled successfully.
SBI_ERR_INVALID_PARAM - One of the `trig_idx` in the specified set
of debug triggers is either:
1) Greater than the total number of triggers.
2) Represents a debug trigger that is not
mapped to any HW debug trigger.

Join tech-unixplatformspec@lists.riscv.org to automatically receive all group messages.