[arch][riscv] Add more defines and optimize fpu context switch
Add a few more #defines for the status register
Tweak the FPU context switch to not rewrite the entire status register,
which may not be a generally safe thing to do.
This commit is contained in:
@@ -63,12 +63,28 @@
|
||||
#define RISCV_CSR_XSTATUS_SPP (1ul << 8)
|
||||
#define RISCV_CSR_XSTATUS_SUM (1ul << 18)
|
||||
#define RISCV_CSR_XSTATUS_MXR (1ul << 19)
|
||||
#define RISCV_CSR_XSTATUS_FS_SHIFT (13)
|
||||
#define RISCV_CSR_XSTATUS_FS_MASK (3ul << RISCV_CSR_XSTATUS_FS_SHIFT)
|
||||
#define RISCV_CSR_XSTATUS_FS_OFF (0ul << RISCV_CSR_XSTATUS_FS_SHIFT)
|
||||
#define RISCV_CSR_XSTATUS_SD (1ul << (__riscv_xlen - 1))
|
||||
// Vector state field
|
||||
#define RISCV_CSR_XSTATUS_VS_SHIFT (9)
|
||||
#define RISCV_CSR_XSTATUS_VS_MASK (3ul << RISCV_CSR_XSTATUS_VS_SHIFT)
|
||||
#define RISCV_CSR_XSTATUS_VS_OFF (0ul << RISCV_CSR_XSTATUS_VS_SHIFT)
|
||||
#define RISCV_CSR_XSTATUS_VS_INITIAL (1ul << RISCV_CSR_XSTATUS_VS_SHIFT)
|
||||
#define RISCV_CSR_XSTATUS_VS_CLEAN (2ul << RISCV_CSR_XSTATUS_VS_SHIFT)
|
||||
#define RISCV_CSR_XSTATUS_VS_DIRTY (3ul << RISCV_CSR_XSTATUS_VS_SHIFT)
|
||||
// Floating point state field
|
||||
#define RISCV_CSR_XSTATUS_FS_SHIFT (13)
|
||||
#define RISCV_CSR_XSTATUS_FS_MASK (3ul << RISCV_CSR_XSTATUS_FS_SHIFT)
|
||||
#define RISCV_CSR_XSTATUS_FS_OFF (0ul << RISCV_CSR_XSTATUS_FS_SHIFT)
|
||||
#define RISCV_CSR_XSTATUS_FS_INITIAL (1ul << RISCV_CSR_XSTATUS_FS_SHIFT)
|
||||
#define RISCV_CSR_XSTATUS_FS_CLEAN (2ul << RISCV_CSR_XSTATUS_FS_SHIFT)
|
||||
#define RISCV_CSR_XSTATUS_FS_DIRTY (3ul << RISCV_CSR_XSTATUS_FS_SHIFT)
|
||||
#define RISCV_CSR_XSTATUS_FS_CLEAN (2ul << RISCV_CSR_XSTATUS_FS_SHIFT)
|
||||
#define RISCV_CSR_XSTATUS_FS_DIRTY (3ul << RISCV_CSR_XSTATUS_FS_SHIFT)
|
||||
// Extended state field
|
||||
#define RISCV_CSR_XSTATUS_XS_SHIFT (15)
|
||||
#define RISCV_CSR_XSTATUS_XS_MASK (3ul << RISCV_CSR_XSTATUS_XS_SHIFT)
|
||||
#define RISCV_CSR_XSTATUS_XS_OFF (0ul << RISCV_CSR_XSTATUS_XS_SHIFT)
|
||||
#define RISCV_CSR_XSTATUS_XS_INITIAL (1ul << RISCV_CSR_XSTATUS_XS_SHIFT)
|
||||
#define RISCV_CSR_XSTATUS_XS_CLEAN (2ul << RISCV_CSR_XSTATUS_XS_SHIFT)
|
||||
#define RISCV_CSR_XSTATUS_XS_DIRTY (3ul << RISCV_CSR_XSTATUS_XS_SHIFT)
|
||||
|
||||
#define RISCV_CSR_XIE_SIE (1ul << (RISCV_XMODE_OFFSET + 0))
|
||||
#define RISCV_CSR_XIE_TIE (1ul << (RISCV_XMODE_OFFSET + 4))
|
||||
|
||||
@@ -68,10 +68,9 @@ void arch_context_switch(thread_t *oldthread, thread_t *newthread) {
|
||||
ulong status = riscv_csr_read(RISCV_CSR_XSTATUS);
|
||||
ulong hw_state = status & RISCV_CSR_XSTATUS_FS_MASK;
|
||||
|
||||
LTRACEF("old fpu dirty %d, new fpu dirty %d, status %#lx\n", oldthread->arch.cs_frame.fpu_dirty, newthread->arch.cs_frame.fpu_dirty,
|
||||
hw_state >> RISCV_CSR_XSTATUS_FS_SHIFT);
|
||||
|
||||
status &= ~(RISCV_CSR_XSTATUS_FS_MASK);
|
||||
LTRACEF("old fpu dirty %d, new fpu dirty %d, status %#lx, sd %d\n", oldthread->arch.cs_frame.fpu_dirty,
|
||||
newthread->arch.cs_frame.fpu_dirty, hw_state >> RISCV_CSR_XSTATUS_FS_SHIFT,
|
||||
(status & RISCV_CSR_XSTATUS_SD) ? 1 : 0);
|
||||
|
||||
/* hardware currently is in the dirty state, so save the state of the fpu regs
|
||||
* and mark the thread as dirty.
|
||||
@@ -93,18 +92,25 @@ void arch_context_switch(thread_t *oldthread, thread_t *newthread) {
|
||||
/* if the new thread has dirty saved state, load it here and mark the cpu as in the
|
||||
* clean state, which will transition to dirty if any regs are modified
|
||||
*/
|
||||
status |= RISCV_CSR_XSTATUS_FS_CLEAN;
|
||||
riscv_fpu_restore(&newthread->arch.cs_frame.fpu);
|
||||
|
||||
/* at this point the FPU hardware should be in the dirty state because of the above routine */
|
||||
|
||||
/* TODO: see if it's totally safe to reduce to a single instruction based on moving from DIRTY -> CLEAN */
|
||||
riscv_csr_clear(RISCV_CSR_XSTATUS, RISCV_CSR_XSTATUS_FS_MASK);
|
||||
riscv_csr_set(RISCV_CSR_XSTATUS, RISCV_CSR_XSTATUS_FS_CLEAN);
|
||||
} else {
|
||||
/* if the thread previously hadn't dirtied the state, zero out the fpu
|
||||
* state and mark hardware as initial.
|
||||
*/
|
||||
status |= RISCV_CSR_XSTATUS_FS_INITIAL;
|
||||
riscv_fpu_zero();
|
||||
}
|
||||
|
||||
/* writeback the modified state to hardware */
|
||||
riscv_csr_write(RISCV_CSR_XSTATUS, status);
|
||||
/* at this point the FPU hardware should be in the dirty state because of the above routine */
|
||||
|
||||
/* TODO: see if it's totally safe to reduce to a single instruction based on moving from DIRTY -> INITIAL */
|
||||
riscv_csr_clear(RISCV_CSR_XSTATUS, RISCV_CSR_XSTATUS_FS_MASK);
|
||||
riscv_csr_set(RISCV_CSR_XSTATUS, RISCV_CSR_XSTATUS_FS_INITIAL);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* integer context switch.
|
||||
|
||||
Reference in New Issue
Block a user