diff --git a/Makefile b/Makefile index ee518b6..ffd676e 100644 --- a/Makefile +++ b/Makefile @@ -35,6 +35,7 @@ DEPS += src/ext-nested-acceleration.adoc DEPS += src/ext-steal-time.adoc DEPS += src/ext-sse.adoc DEPS += src/ext-firmware-features.adoc +DEPS += src/ext-debug-triggers.adoc DEPS += src/ext-experimental.adoc DEPS += src/ext-vendor.adoc DEPS += src/ext-firmware.adoc diff --git a/riscv-sbi.adoc b/riscv-sbi.adoc index dfff40d..04eb0ab 100644 --- a/riscv-sbi.adoc +++ b/riscv-sbi.adoc @@ -101,6 +101,8 @@ include::src/ext-sse.adoc[] include::src/ext-firmware-features.adoc[] +include::src/ext-debug-triggers.adoc[] + include::src/ext-experimental.adoc[] include::src/ext-vendor.adoc[] diff --git a/src/changelog.adoc b/src/changelog.adoc index b625296..8ccd725 100644 --- a/src/changelog.adoc +++ b/src/changelog.adoc @@ -1,6 +1,7 @@ == Change Log === Version 3.0-rc1 +* Added SBI DBTR extension * Added SBI FWFT extension * Added SBI SSE extension * Added error code SBI_ERR_BAD_RANGE diff --git a/src/ext-debug-triggers.adoc b/src/ext-debug-triggers.adoc new file mode 100644 index 0000000..d45564f --- /dev/null +++ b/src/ext-debug-triggers.adoc @@ -0,0 +1,397 @@ +== Debug Triggers Extension (EID #0x44425452 "DBTR") + +The RISC-V Sdtrig extension cite:[debug_v1_0] allows machine-mode software to directly +configure debug triggers which in-turn allows native (or hosted) debugging in machine-mode +without any external debugger. Unfortunately, the debug triggers are only accessible to +the machine-mode. + +The SBI debug trigger extension defines a SBI based abstraction to provide native debugging +for supervisor-mode software such that it is: + +. Suitable for the rich operating systems and hypervisors running in supervisor-mode. +. Allows Guest (VS-mode) and Hypervisor (HS-mode) to share debug triggers on a hart. + +All harts on a RISC-V platform have a fixed number of debug triggers which is referred +to as `trig_max` in this SBI extension. Each debug trigger is assigned a logical index +called `trig_idx` by the SBI implementation where `-1 < trig_idx < trig_max`. + +NOTE: The `trig_max` may vary across harts on a platform with asymmetric harts. + +The configuration of each debug trigger is expressed by three entities `trig_tdata1`, +`trig_tdata2`, and `trig_tdata3` which are encoded in the same way as the `tdata1`, +`tdata2`, and `tdata3` CSRs defined by the RISC-V Sdtrig extension cite:[debug_v1_0] +but with the following additional constraints: + +. The `trig_tdata1.dmode` bit must always be zero. +. The `trig_tdata1.m` bit must always be zero. + +The SBI implementation MUST also maintain an additional software state for each debug +trigger called `trig_state` which is encoded as shown in <> below. + +[#table_dbtr_trig_state] +.Debug Trigger State Fields +[cols="3,4,8", width=95%, align="center", options="header"] +|=== +| Field Name +| Bits +| Description + +| hw_trig_idx +| `trig_state[XLEN-1:8]` +| hardware (or physical) index of the debug rigger. This field must be ignored when + `trig_state.have_hw_trig == 0`. + +| reserved +| `trig_state[7:6]` +| Reserved for future use + +| have_hw_trig +| `trig_state[5:5]` +| When set, the hardware (or physical) debug trigger details are available. + +| vs +| `trig_state[4:4]` +| Saved copy of the `trig_tdata1.vs` bit. + +| vu +| `trig_state[3:3]` +| Saved copy of the `trig_tdata1.vu` bit. + +| s +| `trig_state[2:2]` +| Saved copy of the `trig_tdata1.s` bit. + +| u +| `trig_state[1:1]` +| Saved copy of the `trig_tdata1.u` bit. + +| mapped +| `trig_state[0:0]` +| When set, the trigger has been mapped to some HW debug trigger. +|=== + +=== Function: Get number of triggers (FID #0) + +[source, C] +---- +struct sbiret sbi_debug_num_triggers(unsigned long trig_tdata1) +---- + +Get the number of debug triggers on the calling hart which can support the trigger +configuration specified by `trig_tdata1` parameter. + +This function always returns SBI_SUCCESS in `sbiret.error`. It will return `trig_max` +in `sbiret.value` when `trig_tdata1 == 0` otherwise it will return the number of matching +debug triggers in `sbiret.value`. + +=== Function: Set trigger shared memory (FID #1) + +[source, C] +---- +struct sbiret sbi_debug_set_shmem(unsigned long shmem_phys_lo, + unsigned long shmem_phys_hi, + unsigned long flags) +---- + +Set and enable the shared memory for debug trigger configuration on the calling hart. + +If both `shmem_phys_lo` and `shmem_phys_hi` parameters are not all-ones bitwise then +`shmem_phys_lo` specifies the lower XLEN bits and `shmem_phys_hi` specifies the upper +XLEN bits of the shared memory physical base address. The `shmem_phys_lo` MUST be +`(XLEN / 8)` bytes aligned and the size of shared memory is assumed to be +`trig_max * (XLEN / 2)` bytes. + +If both `shmem_phys_lo` and `shmem_phys_hi` parameters are all-ones bitwise then shared +memory for debug trigger configuration is disabled. + +The `flags` parameter is reserved for future use and MUST be zero. + +The possible error codes returned in `sbiret.error` are shown in +<>. + +[#table_dbtr_set_shmem_errors] +.Debug Triggers Set Shared Memory Errors +[cols="1,2", width=100%, align="center", options="header"] +|=== +| Error code | Description +| SBI_SUCCESS | Shared memory was set or cleared successfully. +| SBI_ERR_INVALID_PARAM | The `flags` parameter is not zero or the `shmem_phys_lo` + parameter is not `(XLEN / 8)` bytes aligned. +| SBI_ERR_INVALID_ADDRESS | The shared memory pointed to by the `shmem_phys_lo` + and `shmem_phys_hi` parameters does not satisfy + the requirements described in + <<_shared_memory_physical_address_range_parameter>>. +|=== + +=== Function: Read triggers (FID #2) + +[source, C] +---- +struct sbiret sbi_debug_read_triggers(unsigned long trig_idx_base, + unsigned long trig_count) +---- + +Read the debug trigger state and configuration into shared memory for a range of debug +triggers specified by the `trig_idx_base` and `trig_count` parameters on the calling hart. + +For each debug trigger with index `trig_idx_base + i` where `-1 < i < trig_count`, the +debug trigger state and configuration consisting of four XLEN-bit words are written in +little-endian format at `offset = i * (XLEN / 2)` of the shared memory as follows: + +[source, C] +---- + word[0] = `trig_state` written by the SBI implementation + word[1] = `trig_tdata1` written by the SBI implementation + word[2] = `trig_tdata2` written by the SBI implementation + word[3] = `trig_tdata3` written by the SBI implementation +---- + +The possible error codes returned in `sbiret.error` are shown in +<>. + +[#table_dbtr_read_triggers_errors] +.Debug Triggers Read Errors +[cols="1,2", width=100%, align="center", options="header"] +|=== +| Error code | Description +| SBI_SUCCESS | State and configuration of triggers read successfully. +| SBI_ERR_NO_SHMEM | Shared memory for debug triggers is disabled. +| SBI_ERR_BAD_RANGE | Either `trig_idx_base >= trig_max` or + `trig_idx_base + trig_count >= trig_max` +|=== + +=== Function: Install triggers (FID #3) + +[source, C] +---- +struct sbiret sbi_debug_install_triggers(unsigned long trig_count) +---- + +Install debug triggers based on an array of trigger configurations in the shared memory +of the calling hart. The `trig_idx` assigned to each installed trigger configuration is +written back in the shared memory. + +The `trig_count` parameter represents the number of trigger configuration entries in +the shared memory at offset `0x0`. + +The i'th trigger configuration at `offset = i * (XLEN / 2)` in the shared memory +consists of four consecutive XLEN-bit words in little-endian format which are +organized as follows: + +[source, C] +---- + word[0] = `trig_idx` written back by the SBI implementation + word[1] = `trig_tdata1` read by the SBI implementation + word[2] = `trig_tdata2` read by the SBI implementation + word[3] = `trig_tdata3` read by the SBI implementation +---- + +The SBI implementation MUST consider trigger configurations in the increasing order of +the array index and starting with array index `0`. To install a debug trigger for the +trigger configuration at array index `i` in the shared memory, the SBI implementation +MUST do the following: + +. Map an unused HW debug trigger which matches the trigger configuration to an + an unused `trig_idx`. +. Save a copy of the `trig_tdata1.vs`, `trig_tdata1.vu`, `trig_tdata1.s`, and + `trig_tdata.u` bits in `trig_state`. +. Update the `tdata1`, `tdata2`, and `tdata3` CSRs of the HW debug trigger. +. Write `trig_idx` at `offset = i * (XLEN / 2)` in the shared memory. + +Additionally for each trigger configuration chain in the shared memory, the SBI +implementation MUST assign contiguous `trig_idx` values and contiguous HW debug +triggers when installing the trigger configuration chain. + +The last trigger configuration in the shared memory MUST not have `trig_tdata1.chain == 1` +for `trig_tdata1.type = 2 or 6` to prevent incomplete trigger configuration chain +in the shared memory. + +The `sbiret.value` is set to zero upon success or if shared memory is disabled whereas +`sbiret.value` is set to the array index `i` of the failing trigger configuration upon +other failures. + +The possible error codes returned in `sbiret.error` are shown in +<>. + +[#table_dbtr_install_triggers_errors] +.Debug Triggers Install Errors +[cols="1,2", width=100%, align="center", options="header"] +|=== +| Error code | Description +| SBI_SUCCESS | Triggers installed successfully. +| SBI_ERR_NO_SHMEM | Shared memory for debug triggers is disabled. +| SBI_ERR_BAD_RANGE | `trig_count >= trig_max` +| SBI_ERR_INVALID_PARAM | One of the trigger configuration words `trig_tdata1`, `trig_tdata2`, + or `trig_tdata3` has an invalid value. +| SBI_ERR_FAILED | Failed to assign `trig_idx` or HW debug trigger for one of the + trigger configurations. +| SBI_ERR_NOT_SUPPORTED | One of the trigger configuration can't be programmed due to + unimplemented optional bits in `tdata1`, `tdata2`, or `tdata3` CSRs. +|=== + +=== Function: Update triggers (FID #4) + +[source, C] +---- +struct sbiret sbi_debug_update_triggers(unsigned long trig_count) +---- + +Update already installed debug triggers based on a trigger configuration array in the +shared memory of the calling hart. + +The `trig_count` parameter represents the number of trigger configuration entries in +the shared memory at offset `0x0`. + +The i'th trigger configuration at `offset = i * (XLEN / 2)` in the shared memory +consists of four consecutive XLEN-bit words in little-endian format as follows: + +[source, C] +---- + word[0] = `trig_idx` read by the SBI implementation + word[1] = `trig_tdata1` read by the SBI implementation + word[2] = `trig_tdata2` read by the SBI implementation + word[3] = `trig_tdata3` read by the SBI implementation +---- + +The SBI implementation MUST consider trigger configurations in the increasing order +of array index and starting with array index `0`. To update a debug trigger based on +trigger configuration at array index `i` in the shared memory, the SBI implementation +MUST do the following: + +. Check and fail if any of the following constraints are not satisfied: +.. `trig_idx` represents logical index of a installed debug trigger +.. `trig_tdata1.type` matches with original installed debug trigger +.. `trig_tdata1.chain` matches with original installed debug trigger +. Save a copy of the `trig_tdata1.vs`, `trig_tdata1.vu`, `trig_tdata1.s`, and + `trig_tdata.u` bits in `trig_state`. +. Update the `tdata1`, `tdata2`, and `tdata3` CSRs of the HW debug trigger. + +The `sbiret.value` is set to zero upon success or if shared memory is disabled whereas +`sbiret.value` is set to the array index `i` of the failing trigger configuration upon +other failures. + +The possible error codes returned in `sbiret.error` are shown in +<>. + +[#table_dbtr_update_triggers_errors] +.Debug Triggers Update Errors +[cols="1,2", width=100%, align="center", options="header"] +|=== +| Error code | Description +| SBI_SUCCESS | Triggers updated successfully. +| SBI_ERR_NO_SHMEM | Shared memory for debug triggers is disabled. +| SBI_ERR_BAD_RANGE | `trig_count >= trig_max` +| SBI_ERR_INVALID_PARAM | One of the trigger configuration in the shared memory has an + invalid of `trig_idx` (i.e. `trig_idx >= trig_max`), `trig_tdata1`, + `trig_tdata2`, or `trig_tdata3`. +| SBI_ERR_FAILED | One of the trigger configurations has valid `trig_idx` but the + corresponding debug trigger is not mapped to any HW debug trigger. +| SBI_ERR_NOT_SUPPORTED | One of the trigger configuration can't be programmed due to + unimplemented optional bits in `tdata1`, `tdata2`, or `tdata3` CSRs. +|=== + +=== Function: Uninstall a set of triggers (FID #5) + +[source, C] +---- +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 MUST: + +. Clear the `tdata1`, `tdata2`, and `tdata3` CSRs of the mapped HW debug trigger. +. Clear the `trig_state` of the debug trigger. +. Unmap and free the HW debug trigger and corresponding `trig_idx` for re-use in + the future trigger installations. + +The possible error codes returned in `sbiret.error` are shown in +<>. + +[#table_dbtr_uninstall_triggers_errors] +.Debug Triggers Uninstall Errors +[cols="1,2", width=100%, align="center", options="header"] +|=== +| Error code | Description +| SBI_SUCCESS | Triggers uninstalled successfully. +| SBI_ERR_INVALID_PARAM | One of the debug trigger with index `trig_idx` in the specified + set of debug triggers either not mapped to any HW debug trigger + OR has `trig_idx` >= `trig_max`. +|=== + +=== Function: Enable a set of triggers (FID #6) + +[source, C] +---- +struct sbiret sbi_debug_enable_triggers(unsigned long trig_idx_base, + unsigned long trig_idx_mask) +---- + +Enable a set of debug triggers specified by the `trig_idx_base` and `trig_idx_mask` +parameters on the calling hart. + +To enable a debug trigger in the specified set of debug triggers, the 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 shown in +<>. + +[#table_dbtr_enable_triggers_errors] +.Debug Triggers Enable Errors +[cols="1,2", width=100%, align="center", options="header"] +|=== +| Error code | Description +| SBI_SUCCESS | Triggers enabled successfully. +| SBI_ERR_INVALID_PARAM | One of the debug trigger with index `trig_idx` in the specified + set of debug triggers either not mapped to any HW debug trigger + OR has `trig_idx` >= `trig_max`. +|=== + +=== Function: Disable a set of triggers (FID #7) + +[source, C] +---- +struct sbiret sbi_debug_disable_triggers(unsigned long trig_idx_base, + unsigned long trig_idx_mask) +---- + +Disable a set of debug triggers specified by the `trig_idx_base` and `trig_idx_mask` +parameters on the calling hart. + +To disable a debug trigger in the specified set of debug triggers, the 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 shown in +<>. + +[#table_dbtr_disable_triggers_errors] +.Debug Triggers Disable Errors +[cols="1,2", width=100%, align="center", options="header"] +|=== +| Error code | Description +| SBI_SUCCESS | Triggers disabled successfully. +| SBI_ERR_INVALID_PARAM | One of the debug trigger with index `trig_idx` in the specified + set of debug triggers either not mapped to any HW debug trigger + OR has `trig_idx` >= `trig_max`. +|=== + +=== Function Listing + +[#table_dbtr_function_list] +.Debug Triggers Function List +[cols="5,2,1,2", width=80%, align="center", options="header"] +|=== +| Function Name | SBI Version | FID | EID +| sbi_debug_num_triggers | 3.0 | 0 | 0x44425452 +| sbi_debug_set_shmem | 3.0 | 1 | 0x44425452 +| sbi_debug_read_triggers | 3.0 | 2 | 0x44425452 +| sbi_debug_install_triggers | 3.0 | 3 | 0x44425452 +| sbi_debug_update_triggers | 3.0 | 4 | 0x44425452 +| sbi_debug_uninstall_triggers | 3.0 | 5 | 0x44425452 +| sbi_debug_enable_triggers | 3.0 | 6 | 0x44425452 +| sbi_debug_disable_triggers | 3.0 | 7 | 0x44425452 +|=== diff --git a/src/references.bib b/src/references.bib index be526a3..9694f5f 100644 --- a/src/references.bib +++ b/src/references.bib @@ -3,3 +3,9 @@ @electronic{priv_v1_12 url = {https://github.com/riscv/riscv-isa-manual/releases/tag/Priv-v1.12}, year = {2021} } + +@electronic{debug_v1_0, + title = {The RISC-V Debug Specification}, + url = {https://github.com/riscv/riscv-debug-spec/releases/tag/1.0.0-rc3}, + year = {2024} +}