Conversation
| enabled_ints = ~a.read_mideleg(); | ||
| } | ||
| break; | ||
| auto mstatus = a.read_mstatus(); |
There was a problem hiding this comment.
I miss the comments explaining what was going on that you added and were lost here.
There was a problem hiding this comment.
yeah I'll do this after we settle on the final decision regarding this discussion
src/interpret.cpp
Outdated
| static inline uint32_t get_enabled_irq_mask_HS(STATE_ACCESS &a, uint64_t sie, uint8_t priv) { | ||
| uint32_t deleg = a.read_mideleg() & ~a.read_hideleg(); | ||
| uint32_t enabled_HS = is_virtual_mode(a) || priv < PRV_HS || (priv == PRV_HS && sie); | ||
| return (deleg & -enabled_HS); |
There was a problem hiding this comment.
Shouldn't you do an & sie in the final return? Checking just if sie has any bit set feels odd for me, actually it should check if the corresponding deleg and sie is bits are enabled. Same apply for other get_enabled_irq_mask_* functions. I think these functions may need some rewriting considering this and the previous comments.
There was a problem hiding this comment.
this is done at the end of the get_pending_irq_mask method here. maybe the naming of those methods is misleading, do you have any ideas what would be a better naming here?
src/riscv-constants.h
Outdated
| PRV_HS = 2, ///< Hypervisor-extended supervisor mode | ||
| PRV_M = 3 ///< Machine mode | ||
| PRV_U = 0, ///< User mode | ||
| PRV_HS = 1, ///< Supervisor mode |
There was a problem hiding this comment.
After reading the spec and the code, I feel that PRV_HS should be renamed back to PRV_S. Because when VRT is 1, we are in VS mode, and the checks have HS in them, so it is misleading.
edubart
left a comment
There was a problem hiding this comment.
I commented on things that may have to be improved after reading the spec. Despite having some issues this is already working well, most issues commented are edge cases or minor details. Great work @alexmikhalevich !
src/interpret.cpp
Outdated
|
|
||
| template <typename STATE_ACCESS> | ||
| static execute_status write_csr_vsstatus(STATE_ACCESS &a, uint64_t val) { | ||
| a.write_vsstatus(val); |
There was a problem hiding this comment.
A write filter is missing here, we should not allow to writes to WPRI fields of vsstatus to preserve backward compability.
There was a problem hiding this comment.
FS and SD fields are not being handled here, they should be handled is similar way to mstatus. While it was handled in write_csr_sstatus, I think you should move the vsstatus related logic from write_csr_sstatus to here and call this function.
When doing this, FS field should always mark state as dirty, like is done in write_csr_mstatus and according to the spec for both mstatus and vsstatus:
Modifying the floating-point state when V=1 causes both fields to be set to 3 (Dirty).
Meaning if vsstatus.FS is set as dirty, then mstatus.FS will also be set as dirty, and both vsstatus.SD and mstatus.SD must also be set.
src/interpret.cpp
Outdated
| if (is_virtual_mode(a)) { | ||
| uint64_t vsstatus = a.read_vsstatus() & VSSTATUS_R_MASK; | ||
| vsstatus = (vsstatus & ~VSSTATUS_W_MASK) | (val & VSSTATUS_W_MASK); | ||
| if ((vsstatus & MSTATUS_FS_MASK) == MSTATUS_FS_MASK) { |
There was a problem hiding this comment.
Despite MSTATUS_FS_MASK being set, it's not ever read. You will find multiple of the following checks in the code:
// If FS is OFF, attempts to read or write the float state will cause an illegal instruction exception.
if (unlikely((mstatus & MSTATUS_FS_MASK) == MSTATUS_FS_OFF)) {
return execute_status::failure;
}They all should be extended taking this in consideration:
When V=1, both vsstatus.FS and the HS-level sstatus.FS are in effect. Attempts to execute a
floating-point instruction when either field is 0 (Off) raise an illegal-instruction exception.
This mean a exception should be raised if either mstatus.FS is OFF, or vsstatus.FS is Off while in virtual mode.
src/interpret.cpp
Outdated
| return execute_HSV_H(a, pc, mcycle, insn); | ||
| case insn_privileged_funct7::HSV_W: | ||
| return execute_HSV_W(a, pc, mcycle, insn); | ||
| // case insn_privileged_funct7::HLV_WU: // TODO |
There was a problem hiding this comment.
This needs to be implemented.
There was a problem hiding this comment.
The case still commented.
There was a problem hiding this comment.
right, that's because this insn is processed in another switch. I removed this comment.
e49b5a3 to
3b25b67
Compare
9b9d7cd to
ac02322
Compare
| // hgatp can only be changed when virtual mode is off, and when virtual mode is off | ||
| // the address translation function will not use it. Enabling virtual mode will trigger | ||
| // a TLB shootdown. | ||
|
|
There was a problem hiding this comment.
This is missing:
When mstatus.TVM=1, attempts to read or write hgatp while executing
in HS-mode will raise an illegal instruction exception.
Setting TVM=1 prevents HS-mode from accessing hgatp or executing HFENCE.GVMA or HIN-
VAL.GVMA
The above is also missing in read_csr_hgatp.
src/interpret.cpp
Outdated
| // a TLB shootdown. | ||
|
|
||
| auto mode = val >> 60; | ||
| if (mode == 0 || (mode >= 8 && mode <= 10)) { |
There was a problem hiding this comment.
You can use the enums SATP_MODE_BARE, SATP_MODE_SV39 and SATP_MODE_SV57 instead of these constants here.
And SATP_MODE_SHIFT for the 60 above.
I also think a switch makes the code more clear, like in write_csr_satp. Same applies to write_csr_vsatp, it could have used a switch.
src/interpret.cpp
Outdated
| @@ -1975,7 +2687,10 @@ static NO_INLINE execute_status write_csr_satp(STATE_ACCESS &a, uint64_t val) { | |||
| } | |||
|
|
|||
| uint64_t old_satp = a.read_satp(); | |||
There was a problem hiding this comment.
There is an extra unnecessary read of satp here when read_iflags_VRT is true, you could move this read in the else of the bellow if.
src/interpret.cpp
Outdated
| @@ -1975,7 +2687,10 @@ static NO_INLINE execute_status write_csr_satp(STATE_ACCESS &a, uint64_t val) { | |||
| } | |||
There was a problem hiding this comment.
The TSR and TVM fields of mstatus affect execution only in HS-mode, not in VS-mode. The TW
field affects execution in all modes except M-mode.
This is not respected here, TVM is affecting VS-mode.
src/interpret.cpp
Outdated
| auto mode = current_mode(a); | ||
| auto priv = (mode & ACCESS_MODE_PRV_MASK) >> ACCESS_MODE_PRV_SHIFT; | ||
| uint64_t mstatus = a.read_mstatus(); | ||
| if (unlikely(priv == PRV_U || (priv == PRV_S && (mstatus & MSTATUS_TVM_MASK)))) { |
There was a problem hiding this comment.
The TSR and TVM fields of mstatus affect execution only in HS-mode, not in VS-mode.
setting TVM=1 does not cause traps for accesses to vsatp or instructions
HFENCE.VVMA or HINVAL.VVMA, or for any actions taken in VS-mode
This is not respected here, TVM is affecting VS-mode.
src/interpret.cpp
Outdated
| uint64_t old_vsstatus = a.read_vsstatus() & VSSTATUS_R_MASK; | ||
| uint64_t vsstatus = (old_vsstatus & ~VSSTATUS_W_MASK) | (val & VSSTATUS_W_MASK); | ||
| auto mstatus = a.read_mstatus(); | ||
| if ((vsstatus & MSTATUS_FS_MASK) == MSTATUS_FS_MASK) { |
There was a problem hiding this comment.
I think this if should have been (vsstatus & MSTATUS_FS_MASK) != MSTATUS_FS_OFF.
src/interpret.cpp
Outdated
| vsstatus |= MSTATUS_FS_DIRTY; | ||
| vsstatus |= MSTATUS_SD_MASK; | ||
| } else { | ||
| mstatus &= ~MSTATUS_SD_MASK; |
There was a problem hiding this comment.
The MSTATUS_FS_MASK could still be dirty, and SD cannot be cleared in this case. So I think this line should be removed.
| @@ -2198,6 +2924,12 @@ static inline execute_status write_csr_fflags(STATE_ACCESS &a, uint64_t val) { | |||
| if (unlikely((mstatus & MSTATUS_FS_MASK) == MSTATUS_FS_OFF)) { | |||
| return execute_status::failure; | |||
| } | |||
| if (a.read_iflags_VRT()) { | |||
| auto vsstatus = a.read_vsstatus(); | |||
| if (unlikely((vsstatus & MSTATUS_FS_MASK) == MSTATUS_FS_OFF)) { | |||
There was a problem hiding this comment.
This check is correct, however there are other places missing the same check, such as:
- read_csr_fflags
- read_csr_frm
- read_csr_fcsr
- the two switches in execute_insn
src/interpret.cpp
Outdated
| @@ -5407,17 +6608,22 @@ template <typename STATE_ACCESS> | |||
| static FORCE_INLINE fetch_status fetch_translate_pc_slow(STATE_ACCESS &a, uint64_t &pc, uint64_t vaddr, | |||
| unsigned char **phptr) { | |||
| uint64_t paddr{}; | |||
| MODE_constants access_mode = get_current_memory_access_mode(a); | |||
There was a problem hiding this comment.
When MPRV=1, load
and store memory addresses are translated and protected, and endianness is applied, as though
the current privilege mode were set to MPP. Instruction address-translation and protection are
unaffected by the setting of MPRV.
get_current_memory_access_mode will always consider MRPV, but for fetch MRPV should be ignored.
Our old code respected this, with this (in translate_virtual_address):
// When MPRV is set, data loads and stores use privilege in MPP
// instead of the current privilege level (code access is unaffected)
if (xwr_shift != PTE_XWR_X_SHIFT && (mstatus & MSTATUS_MPRV_MASK)) {
priv = (mstatus & MSTATUS_MPP_MASK) >> MSTATUS_MPP_SHIFT;
}
src/translate-virtual-address.h
Outdated
| } | ||
|
|
||
| // when checking the U bit for G translation, the current privilege mode is always taken to be U-mode | ||
| if constexpr (TRANSLATION_MODE == TRANSLATION_G) { |
There was a problem hiding this comment.
After making all G translations to use priv=PRV_U, this if could just be removed to simplify this code. The else branch already has the same logic.
23c19c1 to
e08cc68
Compare
e08cc68 to
ef476ff
Compare
4c72df3 to
f3cd606
Compare
2f9548f to
aeef15b
Compare
aeef15b to
c287764
Compare
48d0559 to
9e21789
Compare
Hypervisor extension implementation.