riscv/riscv-isa-manual

Question about `senvcfg` and `henvcfg` when V=1

lfiolhais opened this issue · 2 comments

Hi,

Apologies if this is a duplicated question or an already answer question. I tried to search both the specification, and the closed and open issues of the repo and couldn't find anything.

I'm a bit confused regarding the usage of the CSRs senvcfg and henvcfg when the hart is in V=1 mode.

The H extensions states (as of Release riscv-isa-release-3f725b5-2024-05-31)

Some standard supervisor CSRs (senvcfg, scounteren, and scontext, possibly others) have no matching VS CSR. These supervisor CSRs continue to have their usual function and accessibility even when V=1, except with VS-mode and VU-mode substituting for HS-mode and U-mode. Hypervisor software is expected to manually swap the contents of these registers as needed.

However, H defines a henvcfg which should be used when V=1

The henvcfg CSR is a 64-bit read/write register, formatted as shown in Figure 82, that controls certain
characteristics of the execution environment when virtualization mode V=1.

Since senvcfg and henvcfg can be used when V=1, which should in fact be used for the execution environment? I first assumed that henvcfg had precedence over the definition of senvcfg when V=1, i.e., when V=1 the execution context is taken from henvcfg. With the text in the H extension, it leads to me believe that there are cases where henvcfg is overridden by senvcfg when V=1 and priv=U (or possibly other privilege mode and virtualization combinations?).

Let's consider the that the hart implementes bit FIOM in all *envcfg. Is this the correct behavior for FIOM? P is the privilege and V is the virtualization enable.

  • P = S & V = 0 => FIOM = menvcfg.fiom
  • P = U & V = 0 => FIOM = senvcfg.fiom
  • P = S & V = 1 (really VS) => FIOM = henvcfg.fiom
  • P = U & V = 1 (really VU) => FIOM = senvcfg.fiom (?)

Consider these three statements from the spec literally:

"If bit FIOM is set to one in menvcfg, FENCE instructions executed in modes less privileged than M are modified [...]."

"If bit FIOM is set to one in henvcfg, FENCE instructions executed when V=1 are modified [...]."

"If bit FIOM is set to one in senvcfg, FENCE instructions executed in U-mode are modified [...]."

Note there's no statement that FIOM being set to zero in menvcfg or henvcfg suppresses this behavior: there's only a statement that it being set to one engages it. So each of those statements is sufficient (but not necessary) to engage the behavior.

As for VU-mode, there is a blanket statement makes senvcfg apply to VU-mode:

Some standard supervisor CSRs (`senvcfg`, `scounteren`, and `scontext`,

Taken together, we get:

[H]S-mode FIOM = menvcfg.FIOM
U-mode FIOM = menvcfg.FIOM || senvcfg.FIOM
VS-mode FIOM = menvcfg.FIOM || henvcfg.FIOM
VU-mode FIOM = menvcfg.FIOM || henvcfg.FIOM || senvcfg.FIOM

Got it. That clarifies it. Thanks!