Skip to content

Commit

Permalink
Merge pull request #274 from KarlK90/risc-v-eclic-fence-fix
Browse files Browse the repository at this point in the history
[RISC-V ECLIC] Add R/W memory and instruction barrier after mstatus access
  • Loading branch information
fpoussin authored Apr 16, 2021
2 parents fe3cdf8 + b875108 commit f8bb6d9
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 13 deletions.
26 changes: 19 additions & 7 deletions os/common/ports/RISCV-ECLIC/chcore.h
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,9 @@ static inline void port_init(void) {}
* @return The interrupts status.
*/
static inline syssts_t port_get_irq_status(void) {
return (syssts_t)__RV_CSR_READ(CSR_MSTATUS);
syssts_t mstatus = __RV_CSR_READ(CSR_MSTATUS);
__RWMB();
return mstatus;
}

/**
Expand All @@ -399,22 +401,32 @@ static inline bool port_irq_enabled(syssts_t sts) { return sts & MSTATUS_MIE; }
* @retval true running in ISR mode.
*/
static inline bool port_is_isr_context(void) {
return __RV_CSR_READ(CSR_MSUBM) & MSUBM_TYP;
bool is_irq_context = (__RV_CSR_READ(CSR_MSUBM) & MSUBM_TYP) != 0;
__RWMB();
return is_irq_context;
}

/**
* @brief Kernel-lock action.
* @details Usually this function just disables interrupts but may perform more
* actions.
*/
static inline void port_lock(void) { __disable_irq(); }
static inline void port_lock(void) {
__disable_irq();
__RWMB();
__FENCE_I();
}

/**
* @brief Kernel-unlock action.
* @details Usually this function just enables interrupts but may perform more
* actions.
*/
static inline void port_unlock(void) { __enable_irq(); }
static inline void port_unlock(void) {
__enable_irq();
__RWMB();
__FENCE_I();
}

/**
* @brief Kernel-lock action from an interrupt handler.
Expand All @@ -436,18 +448,18 @@ static inline void port_unlock_from_isr(void) { port_unlock(); }
* @brief Disables all the interrupt sources.
* @note Of course non-maskable interrupt sources are not included.
*/
static inline void port_disable(void) { __disable_irq(); }
static inline void port_disable(void) { port_lock(); }

/**
* @brief Disables the interrupt sources below kernel-level priority.
* @note Interrupt sources above kernel level remains enabled.
*/
static inline void port_suspend(void) { __disable_irq(); }
static inline void port_suspend(void) { port_lock(); }

/**
* @brief Enables all the interrupt sources.
*/
static inline void port_enable(void) { __enable_irq(); }
static inline void port_enable(void) { port_unlock(); }

/**
* @details The function is meant to return when an interrupt becomes pending.
Expand Down
20 changes: 14 additions & 6 deletions os/common/ports/RISCV-ECLIC/compilers/GCC/chcoreasm.S
Original file line number Diff line number Diff line change
Expand Up @@ -56,26 +56,34 @@

# Disable Interrupts globally.
.macro DISABLE_MIE
csrc CSR_MSTATUS, MSTATUS_MIE
csrc CSR_MSTATUS, MSTATUS_MIE
fence iorw, iorw
fence.i
.endm

# Enable Interrupts globally.
.macro ENABLE_MIE
csrs CSR_MSTATUS, MSTATUS_MIE
csrs CSR_MSTATUS, MSTATUS_MIE
fence iorw, iorw
fence.i
.endm

# Clear previous machine interrupt enable bit in mstatus (mstatus.mpie).
# On machine return (mret) mstatus.mie is assigned this value.
# Clearing this bit disables interrupts when leaving interrupt processing mode.
.macro DISABLE_MPIE
li a0, MSTATUS_MPIE
csrc CSR_MSTATUS, a0
li a0, MSTATUS_MPIE
csrc CSR_MSTATUS, a0
fence iorw, iorw
fence.i
.endm

# Set previous machine interrupt enable bit in mstatus (mstatus.mpie).
.macro ENABLE_MPIE
li a0, MSTATUS_MPIE
csrs CSR_MSTATUS, a0
li a0, MSTATUS_MPIE
csrs CSR_MSTATUS, a0
fence iorw, iorw
fence.i
.endm

# --------------------------------------------------------------------------
Expand Down

0 comments on commit f8bb6d9

Please sign in to comment.