Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

- Add S-mode debug CSR for debug #60

Merged
merged 6 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions appendix.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,5 @@ Similar to the Debug Module, the trace encoder is controlled by the mtrcen[i] an

image::external_debug_trace.png[title="The security control on trace module",align="center"]




=== Execution Based Implementation with Sdsec
<TBD>
136 changes: 75 additions & 61 deletions chapter2.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ When debug is allowed in supervisor domain, <<dbops, debug operations>> are allo
[[dbgaccpriv]]
==== Debug Access Privilege

The *debug access privilege* is defined as the privilege level granted to the external debugger to access hardware resources with abstract commands or program buffers. Memory and register accesses from Debug Mode also carry *debug access privilege* instead of always with M-mode. The *debug access privilege* is represented by the `prv` and `v` fields in dcsr. The legal privilege levels programmable to `dcsr` in Debug Mode are elaborated in <<prvvacc>>. Debugger accesses to registers and memory will be checked by permission check mechanisms against *debug access privilege*, and trigger traps if they violate corresponding rules.
The *debug access privilege* is defined as the privilege level granted to the external debugger to access hardware resources with abstract commands or program buffers. Memory and register accesses from Debug Mode also carry *debug access privilege* instead of always with M-mode. The *debug access privilege* is represented by the `prv` and `v` fields in `dcsr` or <<ssdextcsr, sdcsr>>. The legal privilege levels programmable to the fields in Debug Mode are elaborated in <<prvvacc>>. Debugger accesses to registers and memory will be checked by permission check mechanisms against *debug access privilege*, and trap if they violate corresponding rules.
AoteJin marked this conversation as resolved.
Show resolved Hide resolved

[[prvvacc]]
===== Configuring dcsr for External Debugger Access Privileges
===== Configuring External Debugger Access Privileges

The dcsr (at 0x7b0) is always accessible in Debug Mode and the `prv` and `v` fields in the dcsr have been modified to authorize privilege for external debug accesses. Upon transitioning into Debug Mode, the `prv` and `v` fields are updated to the privilege level the hart was previously operating in. The maximum debug privilege level that can be configured in `prv` and `v` is determined in <<maxdbgpriv>>. The fields retain legal values when the `prv` and `v` are configured with an illegal privilege level. Illegal privilege levels include unsupported levels and any level higher than the maximum allowed debug privilege. When the hart resumes from Debug Mode, the current privilege mode and virtualization mode are changed to that specified by `prv` and `v`.
The `prv` and `v` fields have been modified to authorize privilege for external debug accesses. Upon transitioning into Debug Mode, the `prv` and `v` fields are updated to the privilege level the hart was previously operating in. The maximum debug privilege level that can be configured in `prv` and `v` is determined in <<maxdbgpriv>>. The fields retain legal values when the `prv` and `v` are configured with an illegal privilege level. Illegal privilege levels include unsupported levels and any level higher than the maximum allowed debug privilege. When the hart resumes from Debug Mode, the current privilege mode and virtualization mode are changed to that specified by `prv` and `v`.

[[maxdbgpriv]]
[options="header"]
Expand All @@ -78,38 +78,36 @@ The dcsr (at 0x7b0) is always accessible in Debug Mode and the `prv` and `v` fie
|=========================================

[NOTE]
As the `prv` and `v` fields in dcsr are Write Any Read Legal (WARL) fields, the external debugger is able to read back the written value to determine the maximum debug privilege level.
As the `prv` and `v` fields are Write Any Read Legal (WARL) fields, the external debugger is able to read back the written value to determine the maximum debug privilege level.

==== Privilege Level Changing Instructions

The RISC-V Debug Specification cite:[dbgspec] defines that the instructions that change the privilege mode have UNSPECIFIED behavior when executed within the Program Buffer, with exception of the ebreak instruction. In Sdsec, those instructions including mret, sret, uret, ecall, must either act as NOP or trigger an exception (stopping execution and setting `cmderr` to 3) in Program Buffer. Notably, these instructions retain their normal functionality during single stepping.

==== Interrupt during Single Stepping

The interrupt can be disabled by `stepie` in the dcsr during single stepping. When `mdbgen` is 1, `stepie` disables interrupts in all privilege modes for the hart. When `mdbgen` is 0 and `sdedbgalw` is 1, only interrupts delegated to the supervisor domain are disabled, while interrupts that trap to M-mode are not affected.
The interrupt can be disabled by `stepie` in `dcsr` during single stepping. When `mdbgen` is 1, `stepie` disables interrupts in all privilege modes for the hart. When `mdbgen` is 0 and `sdedbgalw` is 1, only interrupts delegated to the supervisor domain are disabled, while interrupts that trap to M-mode are not affected.

[NOTE]
When debugging is only allowed for the supervisor domain, M-mode interrupts must not be disabled. Otherwise, debugging might impact the behavior of other parts of the system. For example, if a context switch for the supervisor domain triggered by a timer interrupt is suppressed, some real-time workloads might not be completed on time, resulting in unexpected errors.

=== Trace
When Sdsec is supported, trace, as a non-intrusive debug method, will be constrained based on RISC-V privilege level. The availability of trace output is indicated through the interface defined in <<<_reference to the trace interface doc_>>> to trace module.

[mtrcctl]
==== M-Mode Trace Control
Each hart must add a new state element, `mtrcen`, which controls the availability of M-mode tracing. Setting `mtrcen` to 1 enables trace for both M-mode and the supervisor domain; setting `mtrcen` to 0 disables trace output when the hart is running in M-mode.

[NOTE]
Similar to M-mode debug control, `mtrcen` may be controlled through various methods, such as a new input port to the hart, a handshake with the system Root of Trust (RoT), or other methods. The implementation may group several harts together and use one signal to drive their `mtrcen` state or assign each hart its own dedicated state.

[sdtrcctl]
==== Supervisor Domain Trace Control
The Smsdetrc extension introduces `sdetrcalw` field (bit 8) in CSR <<Sdseccsr,msdcfg>> within a hart. The trace availability for a hart in supervisor domain is determined by the `sdetrcalw` field and `mtrcen`. If either `sdetrcalw` or `mtrcen` is set to 1, the trace output is allowed when the hart runs in the supervisor domain.

When both `sdetrcalw` and `mtrcen` are set to 0, trace output is inhibited at all privilege levels.

=== Trigger (Sdtrig)

Triggers configured to enter Debug Mode can only fire or match when external debug is allowed, as outlined in <<dbgpriv>>. A trigger enabled for a privilege level higher than debug allowed privilege is not accessible by an external debugger. When this trigger is selected using `tselect`, it always reads as 0, and any writes to it are ignored.
Triggers configured to enter Debug Mode can only fire or match when external debug is allowed, as outlined in <<dbgpriv>>.

[NOTE]
Implementations must ensure that pending triggers intending to enter Debug Mode match or fire only when the hart is in a state where debug is allowed. For example, if an interrupt traps the hart to a debug-disallowed privilege mode, the trigger can only take effect either before the privilege is updated and control flow is transferred to the trap handler, or after the interrupt is completely handled and returns from the trap handler. The implementation must prevent Debug Mode from being entered in an intermediate state where privilege is changed or the PC is updated. This also applies to scenarios where a trigger is configured to enter Debug Mode before instruction execution and an interrupt occurs simultaneously.
Expand All @@ -134,68 +132,84 @@ The privilege level of the trigger chain is determined by the trigger enabled fo
[NOTE]
This represents a balance between usability and hardware complexity. There may be instances where the triggers are linked across different privilege levels (e.g., from S-mode to M-mode), while the external debugger may only have access with S-mode privilege. The external debugger should not modify the chain, because it could be suppressed or incorrectly match or fire in M-mode.

==== Sdtrig CSR
=== CSRs

The CSRs tcontrol, scontext, hcontext, mcontext, and mscontext must follow access rules defined in <<dbgaccpriv, debug access privilege>>. Meanwhile, tselect, tdata1, tdata2, and tdata3 are read/write accessible when debug is allowed. If debug is disallowed, writes to these registers are ignored, and reads return zero. The table below illustrates the access conditions for tselect, tdata1, tdata2, and tdata3.
[[ssdextcsr]]
==== Extension of Sdext CSR

[options="header"]
[cols="30%,70%"]
.Tselect, tdata1, tdata2, tdata3 CSR access condition in Debug Mode
|================================================================
| Register | Access condition
| tselect(0x7a0) | mdbgen == 1 \|\| sdedbgalw == 1
| tdata1(0x7a1) | mdbgen == 1 \|\| sdedbgalw == 1
| tdata2(0x7a2) | mdbgen == 1 \|\| sdedbgalw == 1
| tdata3(0x7a3) | mdbgen == 1 \|\| sdedbgalw == 1
| tinfo(0x7a4) | mdbgen == 1 \|\| sdedbgalw == 1
|================================================================

The fields in mcontrol, mcontrol6, icount, itrigger, etrigger, and tmexttrigger are read/write accessible only when the access conditions are met. When access is disallowed, writes to these fields are ignored, and reads return zero.
The `sdcsr` and `sdpc` registers provide supervisor read/write access to the `dcsr` and `dpc` registers respectively. They are only accessible in Debug Mode.

.Allocated addresses for supervisor shadow of Debug Mode CSR
[options="header"]
[cols="20%,80%"]
.Tdata1 fields access condtion against privilege granted to external debugger
|====================================
| Field | Access condition
| m | mdbgen == 1
| s | mdbgen == 1 \|\| sdedbgalw == 1
| u | mdbgen == 1 \|\| sdedbgalw == 1
| vs | mdbgen == 1 \|\| sdedbgalw == 1
| vu | mdbgen == 1 \|\| sdedbgalw == 1
|====================================

=== Other CSR updates

==== Debug Control and Status (dcsr)
[cols="25%,25%,50%"]
|============================================================================================
| Number | Name | Descirption
| 0xaaa | sdcsr | Supervisor debug control and status register.
| 0xaaa | sdpc | Supervisor debug program counter.
|============================================================================================

The dcsr is always accessible in Debug Mode. The access rules for field `prv` and `v` are addressed in subsection <<prvvacc>>. Beside `prv` and `v`, the access condition of remaining fields are listed in the following table.
When the access conditions are met, they are read/write accessible. When access is disallowed, writes to these fields are ignored, and reads return zero.
The `sdcsr` register exposes a subset of `dcsr`, formatted as shown in <<sdcsr32>>, while the `sdpc` register provides full access to `dpc`.

.Dcsr fields access condition against privilege granted to external debugger
[options="header"]
[cols="40%,60%"]
|============================================
| Field | Access condition
| debugver | mdbgen == 1 \|\| sdedbgalw == 1
| extcause | mdbgen == 1 \|\| sdedbgalw == 1
| cetrig | mdbgen == 1
| ebreakvs | mdbgen == 1 \|\| sdedbgalw == 1
| ebreakvu | mdbgen == 1 \|\| sdedbgalw == 1
| ebreakm | mdbgen == 1
| ebreaks | mdbgen == 1 \|\| sdedbgalw == 1
| ebreaku | mdbgen == 1 \|\| sdedbgalw == 1
| stepie | mdbgen == 1 \|\| sdedbgalw == 1
| stoptime | mdbgen == 1
| mprven | mdbgen == 1
| nmip | mdbgen == 1
|============================================
[NOTE]
Unlike `dcsr` and `dpc`, the scratch registers do not have supervisor access, and external debuggers with S-mode privilege cannot not use them as scratch memory.

[caption="Register {counter:rimage}: ", reftext="Register {rimage}"]
[title="Supervisor debug control and status register (sdcsr) for RV32"]
[id=sdcsr32]
[wavedrom, ,svg]
....
{reg: [
{bits: 1, name: 'prv'},
{bits: 1, name: '0'},
{bits: 1, name: 'step'},
{bits: 1, name: '0'},
{bits: 1, name: '0'},
{bits: 1, name: 'v'},
{bits: 3, name: 'cause'},
{bits: 1, name: '0'},
{bits: 1, name: '0'},
{bits: 1, name: 'stepie'},
{bits: 1, name: 'ebreaku'},
{bits: 1, name: 'ebreaks'},
{bits: 1, name: '0'},
{bits: 1, name: '0'},
{bits: 1, name: 'ebreakvu'},
{bits: 1, name: 'ebreakvs'},
{bits: 6, name: '0'},
{bits: 3, name: 'extcause'},
{bits: 1, name: '0'},
{bits: 4, name: 'debugver'}
], config:{lanes: 3, hspace:1024}}
....

==== Debug PC (dpc) and Debug Scratch Register (dscratch0 and dscratch1)
[NOTE]
The `nmip`, `mprven`, `stoptime`, `stopcount`, `ebreakm` and `cetrig` fields in `dcsr` are configurable only by M-mode, masked from `sdcsr` while the `prv` field is constrained to 1 bit.

[caption="Register {counter:rimage}: ", reftext="Register {rimage}"]
[title="Supervisor debug program counter (sdpc)"]
[id=sdpc]
[bytefield]
----
(defattrs :plain [:plain { :font-size 24}])
(def row-height 40 )
(def row-header-fn nil)
(def left-margin 30)
(def right-margin 30)
(def boxes-per-row 32)
(draw-column-headers {:height 24 :font-size 24 :labels (reverse ["0" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "DXLEN-1" ""])})
(draw-box "sdpc" {:span 32:text-anchor "middle" :borders {:left :border-unrelated :top :border-unrelated :bottom :border-unrelated :right :border-unrelated}})
(draw-box "DXLEN" {:font-size 24 :span 32 :borders {}})
----
bcstrongx marked this conversation as resolved.
Show resolved Hide resolved

==== Extension of Sdtrig CSR

The Smtdeleg and Sstcfg extensions define the process for delegating triggers to modes with lower privilege than M-mode. The Sdsec requires both extensions to securely delegate Sdtrig triggers to supervisor domain.

Debug PC (at 0x7b1) and Debug Scratch Register (at 0x7b2 and 0x7b3) are not restricted by <<dbgaccpriv, debug access privilege>>, they are always accessible in Debug Mode.
[NOTE]
When M-mode enables debugging for supervisor domain, it can optionally delegate the triggers to the supervisor domain, allowing an external debugger with S-mode privilege to configure these triggers.

[[Sdseccsr]]
==== Sdsec CSR
==== Debug Control CSR

The Sdsec extension does not introduce any new CSR. The CSR control knobs in `msdcfg` for supervisor domain debug and trace are specified in Smsdedbg and Smsdetrc extension respectively in _RISC-V Supervisor Domains Access Protection_ cite:[smmtt]. The Smsdedbg and/or Smsdetrc extension must be implemented to support security control for debugging and/or tracing in supervisor domain.
The CSR holding the debug and trace contol knobs for supervisor domain are specified in Smsdedbg and Smsdetrc extension respectively in _RISC-V Supervisor Domains Access Protection_ cite:[smmtt]. The Smsdedbg and/or Smsdetrc extension must be implemented to support security control for debugging and/or tracing in supervisor domain.
bcstrongx marked this conversation as resolved.
Show resolved Hide resolved

2 changes: 1 addition & 1 deletion chapter3.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Trusted entities like RoT should configure IOPMP or equivalent protection before

=== Security Fault Error Reporting

A dedicated error code, security fault error (cmderr 6), is included in `cmderr` of abstractcs (at 0x16 in Debug Module). Misconfigurations of the dcsr and issuance of abstract commands under disallowed circumstance can signify such an error. Additionally, the bus security fault error (sberror 6) is introduced in `sberror` of sbcs (at 0x38 in Debug Module) to denote errors related to system bus access.
A dedicated error code, security fault error (cmderr 6), is included in `cmderr` of abstractcs (at 0x16 in Debug Module). Issuance of abstract commands under disallowed circumstance sets `cmderr` to 6. Additionally, the bus security fault error (sberror 6) is introduced in `sberror` of sbcs (at 0x38 in Debug Module) to denote errors related to system bus access.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing some backticks on register names (abstractcs, sbcs). CSR field names don't need to be in backticks, they are generally all caps but the debug spec predates this convention. So fine to keep the backticks on those if you prefer that.


The error raised by resethaltreq, reset can be identified through the fields `allsecfault` and `anysecfault` in dmstatus. Error status bits are internally maintained for each hart, with the `allsecfault` and `anysecfault` fields indicating the error status of the currently selected harts. These error statuses are sticky and can only be cleared by writing 1 to `acksecfault` in dmcs2.

Expand Down
Binary file modified external-debug-security.pdf
Binary file not shown.
Loading