Fast track arch extension proposal for "stateen" CSRs
I have below the latest version of the plan to add optional "stateen"
(State Enable) CSRs to the RISC-V Privileged Architecture, now in the
form of a fast-track extension proposal. Much of this is the same as
The text below mentions henvcfg/henvcfgh and senvcfg. There is a
separate plan being developed for CSRs tentatively called menvcfg,
henvcfg, and senvcfg (Environment Configuration) to be convenient
locations for various other controls that contribute to determining the
execution environment of less-privileged modes. These envcfg CSRs are
being proposed simply to consolidate what would otherwise be multiple
extension-specific CSRs, each containing only a few defined bits.
That's all a separate matter, but I figured I may as well get ahead of
the inevitable questions about those names.
Please review the updated proposal below and report any new problems
- John Hauser
The following is a proposal for a security-related architecture
extension that is using the fast-track process created for
standardizing small targeted extensions that address a clear need.
This extension addresses the potential for the creation of covert
communication channels via RISC-V architecture extensions that add new
state to the architecture, and closes this security hole.
This extension has already been substantially reviewed by the
Privileged ISA Committee chairs and by some in the tech-privileged and
security communities, and is now being put out for the last official
preliminary review ahead of a public review.
Note that, although the description is long, an actual physical
implementation of this extension is fairly straightforward and
The implementation of optional RISC-V extensions has the potential
to open covert channels between separate user threads, or between
separate guest OSes running under a hypervisor. The problem
occurs when an extension adds processor state---usually explicit
registers, but possibly other forms of state---that the main OS
or hypervisor is unaware of (and hence won't context-switch) but
that can be modified/written by one user thread or guest OS and
perceived/examined/read by another.
For example, the proposed Advanced Interrupt Architecture (AIA) for
RISC-V adds to a hart as many as ten supervisor-level CSRs (siselect,
sireg, stopi, sseteipnum, sclreipnum, sseteienum, sclreienum, sclaimei,
sieh, and siph) and provides also the option for hardware to be
backward-compatible with older, pre-AIA software. Because an older
hypervisor that is oblivious to the AIA will not know to swap the
AIA's ten new CSRs on context switches, the registers may then be
used as a covert channel between multiple guest OSes that run atop
this hypervisor. Although traditional practices might consider such
a communication channel harmless, the intense focus on security today
argues that a means be offered to plug such channels.
The F registers of the RISC-V floating-point extensions and the
V registers of the vector extension would similarly be potential covert
channels between user threads, except for the existence of the FS and
VS fields in the sstatus register. Even if an OS is unaware of, say,
the vector extension and its V registers, access to those registers
is blocked when the VS field is initialized to zero, either at machine
level or by the OS itself initializing sstatus.
Obviously, one way to prevent the use of new user-level CSRs as covert
channels would be to add to mstatus or sstatus an "XS" field for each
relevant extension, paralleling the V extension's VS field. However,
this is not considered a general solution to the problem due to the
number of potential future extensions that may add small amounts of
state. Even with a 64-bit sstatus (necessitating adding sstatush for
RV32), it is not certain there are enough remaining bits in sstatus
to accommodate all future user-level extensions. In any event, there
is no need to strain sstatus (and add sstatush) for this purpose.
The "enable" flags that are needed to plug covert channels are not
generally expected to require swapping on context switches of user
threads, making them a less-than-compelling candidate for inclusion in
sstatus. Hence, a new place is proposed for them instead.
For RV64 harts, this extension adds four new 64-bit CSRs at machine
level, listed with their CSR addresses:
0x30C mstateen0 (Machine State Enable 0)
If supervisor mode is implemented, another four CSRs are defined at
And if the hypervisor extension is implemented, another set of CSRs is
For RV32, the registers listed above are 32-bit, and for the
machine-level and hypervisor CSRs there is a corresponding set of
high-half CSRs for the upper 32 bits of each register:
For the supervisor-level sstateen registers, high-half CSRs are not
added at this time because it is expected the upper 32 bits of these
registers will always be zeros, as explained later below.
Each bit of a stateen CSR controls less-privileged access to an
extension's state, for an extension that was not deemed "worthy" of
a full XS field in sstatus like the FS and VS fields for the F and
V extensions. The number of registers provided at each level is
four because it is believed that 4 * 64 = 256 bits for machine and
hypervisor levels, and 4 * 32 = 128 bits for supervisor level, will be
adequate for many years to come, perhaps for as long as the RISC-V ISA
is in use. The exact number four is an attempted compromise between
providing too few bits on the one hand and going overboard with CSRs
that will never be used on the other. A possible future doubling of
the number of stateen CSRs is covered later.
The stateen registers at each level control access to state at all
less-privileged levels, but not at its own level. This is analogous to
how the existing counteren CSRs control access to performance counter
registers. Just as with the counteren CSRs, when a stateen CSR
prevents access to state by less-privileged levels, an attempt in one
of those privilege modes to execute an instruction that would read
or write the protected state raises an illegal instruction exception,
or, if executing in VS or VU mode and the circumstances for a virtual
instruction exception apply, raises a virtual instruction exception
instead of an illegal instruction exception.
When this extension is not implemented, all state added by an extension
is accessible as defined by that extension.
When a stateen CSR prevents access to state for a privilege mode,
attempting to execute in that privilege mode an instruction that
_implicitly_ updates the state without reading it may or may not raise
an illegal instruction or vitual instruction exception. Such cases
must be disambiguated by being explicitly specified one way or the
In some cases, the bits of the stateen CSRs will have a dual purpose as
enables for the ISA extensions that introduce the controlled state.
Each bit of a supervisor-level sstateen CSR controls user-level access
(from U-mode or VU-mode) to an extension's state. The intention is to
allocate the bits of sstateen CSRs starting at the least-significant
end, bit 0, through to bit 31, and then on to the next-higher-numbered
For every bit with a defined purpose in an sstateen CSR, the same bit
is defined in the matching mstateen CSR to control access below machine
level to the same state. The upper 32 bits of an mstateen CSR (or for
RV32, the corresponding high-half CSR) control access to state that is
inherently inaccessible to user level, so no corresponding enable bits
in the supervisor-level sstateen CSR are applicable. The intention is
to allocate bits for this purpose starting at the most-significant end,
bit 63, through to bit 32, and then on to the next-higher mstateen CSR.
If the rate that bits are being allocated from the least-significant
end for sstateen CSRs is sufficiently low, allocation from the
most-significant end of mstateen CSRs may be allowed to encroach on
the lower 32 bits before jumping to the next-higher mstateen CSR. In
that case, the bit positions of "encroaching" bits will remain forever
read-only zeros in the matching sstateen CSRs.
With the hypervisor extension, the hstateen CSRs have identical
encodings to the mstateen CSRs, except controlling accesses for a
virtual machine (from VS and VU modes).
Bits in any stateen CSR that are defined to control state that a hart
doesn't implement are read-only zeros for that hart. Likewise, all
reserved bits not yet given a defined meaning are also read-only zeros.
For every bit in an mstateen CSR that is zero (whether read-only zero
or set to zero), the same bit appears as read-only zero in the matching
hstateen and sstateen CSRs. For every bit in an hstateen CSR that is
zero (whether read-only zero or set to zero), the same bit appears as
read-only zero in sstateen when accessed in VS-mode.
On reset, all mstateen bits are initialized by the hardware to zeros.
If machine-level software changes these values, it is responsible for
initializing the matching hstateen and sstateen CSRs to zeros too.
Software at each privilege level should set its respective stateen CSRs
to indicate the state it is prepared to allow less-privileged software
to access. For OSes and hypervisors, this usually means the state that
the OS or hypervisor is prepared to swap on a context switch, or to
manage in some other way.
For each mstateen and hstateen CSR, bit 63 is defined to control
access to the matching supervisor-level sstateen CSR. That is,
bit 63 of mstateen0 and hstateen0 controls access to sstateen0; bit 63
of mstateen1 and hstateen1 controls access to sstateen1; etc. A
hypervisor may need this control over accesses to the sstateen CSRs
if it ever must emulate for a virtual machine an extension that is
supposed to be affected by a bit in an sstateen CSR. (Even if such
emulation is uncommon, it shouldn't be excluded.) Machine-level
software needs identical control to be able to emulate the hypervisor
extension. (That is, machine level needs control over accesses to the
supervisor-level sstateen CSRs in order to emulate the hstateen CSRs,
which have such control.)
If the hypervisor extension is not implemented and a supervisor-level
sstateen CSR is all read-only zeros, an implementation may make bit 63
of the matching mstateen read-only zero. In that case, machine-level
software should emulate attempts to access the affected sstateen CSR
from S-mode, ignoring writes and returning zero for reads.
Initially, the following bits are proposed to be defined in mstateen0,
hstateen0, and sstateen0:
bit 0 Custom state
bit 1 fcsr for Zfinx and related extensions (Zdinx, etc.)
Bit 0 controls access to any and all custom state.
(Bit 0 of these registers is not custom state itself; it is a standard
field of a standard CSR, either mstateen0, hstateen0, or sstateen0. The
requirements that non-standard extensions must meet to be _conforming_
are not relaxed due solely to changes in the value of this bit. In
particular, if software sets this bit but does not execute any custom
instructions or access any custom state, the software must continue to
execute as specified by all relevant RISC-V standards, or the hardware
is not standard-conforming.)
Bit 1 applies only for the case when floating-point instructions
operate on X registers instead of F registers. Whenever misa.F = 1,
bit 1 of mstateen0 is read-only zero (and hence read-only zero in
hstateen0 and sstateen0 too). For convenience, when the stateen CSRs
are implemented and misa.F = 0, then if bit 1 of a controlling stateen0
CSR is zero, _all_ floating-point instructions cause an illegal
instruction trap (or virtual instruction trap, if relevant), as though
they all access fcsr, regardless of whether they really do.
In addition to the bits listed above for user-accessible state, the
following are also proposed initially for mstateen0:
bit 58 IMSIC state of the Advanced Interrupt Architecture (AIA)
bit 59 Most other registers of the AIA
bit 60 siselect, vsiselect of the AIA
bit 61 Reserved for possible henvcfg2/henvcfg2h, senvcfg2
bit 62 henvcfg/henvcfgh, senvcfg
bit 63 hstateen0/hstateen0h, sstateen0
If a hart has an IMSIC (Incoming Message-Signaled Interrupt Controller)
as defined by the AIA, then bit 57 controls access to the IMSIC's CSRs,
sseteipnum, sclreipnum, sseteienum, sclreienum, sclaimei, vsseteipnum,
vsclreipnum, vsseteienum, vsclreienum, and vsclaimei, and to all IMSIC
registers accessed through siselect + sireg and through vsiselect +
Bit 58 controls access to AIA CSRs hidelegh, hvien/hvienh, hviph,
hvicontrol, hviprio1/hviprio1h, hviprio2/hviprio2h, vsieh, vsiph, sieh,
and siph, as well as the iprio array accessed through siselect + sireg.
The bits defined initially for hstateen0 are the same as those for
mstateen0 except applying only to state that is accessible in VS-mode:
bit 58 IMSIC state of the AIA
bit 59 sieh, siph of the AIA
bit 60 siselect of the AIA
bit 61 Reserved for a possible senvcfg2
bit 62 senvcfg
bit 63 sstateen0
(Setting hstateen0 bit 58 to zero prevents a virtual machine from
accessing the hart's IMSIC the same as setting hstatus.VGEIN = 0.)
After the machine-level mstateen CSRs are initialized to zeros on
reset, machine-level software can set bits in these registers to enable
less-privileged access to the controlled state. This may be either
because machine-level software knows how to swap the state or, more
likely, because machine-level software isn't swapping supervisor-level
environments. (Recall that the main reason the mstateen CSRs must
exist is so machine level can emulate the hypervisor extension. When
machine level isn't emulating the hypervisor extension, it is likely
there will be no need to keep any mstateen bits zero.)
If machine level sets any mstateen bits to nonzero, it must initialize
the matching hstateen CSRs to zeros if the hypervisor extension
is implemented. And if any mstateen bits that are set to one have
matching bits in the sstateen CSRs, machine-level software must also
initialize those sstateen CSRs to zeros. Ordinarily, machine-level
software will want to set bit 63 of all mstateen CSRs, necessitating
that it zero all hstateen CSRs.
Software should ensure the sstateen CSRs are initialized to zeros when
an OS at supervisor level is first entered. The OS can set bits in
these registers to enable user-level access to the controlled state,
presumably because it knows how to context-swap the state.
For the sstateen CSRs whose access by a guest OS is permitted by
bit 63 of the corresponding hstatus CSRs, a hypervisor must include the
sstateen CSRs in the context it swaps for a guest OS. When it starts
a new guest OS, it must ensure those sstateen CSRs are initialized to
zeros, and it must emulate accesses to any other sstateen CSRs.
If software at any privilege level does not support multiple
contexts for less-privilege levels, then it may choose to maximize
less-privileged access to all state by writing a value of all ones to
the stateen CSRs at its level (the mstateen CSRs for machine level,
the sstateen CSRs for an OS, and the hstateen CSRs for a hypervisor),
without knowing all the state to which it is granting access. This
is justified because there is no risk of a covert channel between
execution contexts at the less-privilegeed level when only one
context exists at that level. This situation is expected to be common
for machine level, and it might also arise, for example, for a type-1
hypervisor that hosts only a single guest virtual machine.
If a need is anticipated, the set of stateen CSRs could in the future
be doubled by adding these:
0x38C mstateen4 0x39C mstateen4h
0x38D mstateen5 0x39D mstateen5h
0x38E mstateen6 0x39E mstateen6h
0x38F mstateen7 0x39F mstateen7h
0x68C hstateen4 0x69C hstateen4h
0x68D hstateen5 0x69D hstateen5h
0x68E hstateen6 0x69E hstateen6h
0x68F hstateen7 0x69F hstateen7h
These additional CSRs are not a part of this proposed extension because
it is unclear whether they will ever be needed, and it is believed the
rate of consumption of bits in the first group, registers numbered 0-3,
will be slow enough that any looming shortage will be perceptible many
years in advance. At the moment, it is not known even how many years
it may take to exhaust just mstateen0, sstateen0, and hstateen0.