Skip to content

Commit

Permalink
feat(arch/riscv): add SBI hart suspend
Browse files Browse the repository at this point in the history
This commit adds support for the SBI hart suspend.
As specified in the SBI documentation, the suspend call is supported
only from firmware version 0.3 onward.

Signed-off-by: João Peixoto <joaopeixotooficial@gmail.com>
  • Loading branch information
joaopeixoto13 authored and josecm committed Oct 30, 2024
1 parent 179337b commit 6070880
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 8 deletions.
5 changes: 4 additions & 1 deletion src/arch/riscv/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ void cpu_arch_init(cpuid_t cpuid, paddr_t load_addr)

void cpu_arch_idle(void)
{
__asm__ volatile("wfi\n\t" ::: "memory");
struct sbiret ret = sbi_hart_suspend(SBI_HSM_SUSPEND_RET_DEFAULT, 0, 0);
if (ret.error < 0) {
ERROR("failed to suspend hart %d", cpu()->id);
}
__asm__ volatile("mv sp, %0\n\r"
"j cpu_idle_wakeup\n\r" ::"r"(&cpu()->stack[STACK_SIZE]));
ERROR("returned from idle wake up");
Expand Down
18 changes: 11 additions & 7 deletions src/arch/riscv/inc/arch/sbi.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@
* From https://github.com/riscv/riscv-sbi-doc
*/

#define SBI_SUCCESS (0)
#define SBI_ERR_FAILURE (-1)
#define SBI_ERR_NOT_SUPPORTED (-2)
#define SBI_ERR_INVALID_PARAM (-3)
#define SBI_ERR_DENIED (-4)
#define SBI_ERR_INVALID_ADDRESS (-5)
#define SBI_ERR_ALREADY_AVAILABLE (-6)
#define SBI_SUCCESS (0)
#define SBI_ERR_FAILURE (-1)
#define SBI_ERR_NOT_SUPPORTED (-2)
#define SBI_ERR_INVALID_PARAM (-3)
#define SBI_ERR_DENIED (-4)
#define SBI_ERR_INVALID_ADDRESS (-5)
#define SBI_ERR_ALREADY_AVAILABLE (-6)

#define SBI_HSM_SUSPEND_RET_DEFAULT (0x00000000)
#define SBI_HSM_SUSP_NON_RET_BIT (0x80000000)

struct sbiret {
long error;
Expand Down Expand Up @@ -73,5 +76,6 @@ struct sbiret sbi_remote_hfence_vvma(const unsigned long hart_mask, unsigned lon
struct sbiret sbi_hart_start(unsigned long hartid, unsigned long start_addr, unsigned long priv);
struct sbiret sbi_hart_stop(void);
struct sbiret sbi_hart_status(unsigned long hartid);
struct sbiret sbi_hart_suspend(uint32_t suspend_type, unsigned long resume_addr, unsigned long priv);

#endif /* __SBI_H__ */
34 changes: 34 additions & 0 deletions src/arch/riscv/sbi.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#define SBI_HART_START_FID (0)
#define SBI_HART_STOP_FID (1)
#define SBI_HART_STATUS_FID (2)
#define SBI_HART_SUSPEND_FID (3)

#define SBI_EXTID_RFNC (0x52464E43)
#define SBI_REMOTE_FENCE_I_FID (0)
Expand Down Expand Up @@ -170,6 +171,12 @@ struct sbiret sbi_hart_status(unsigned long hartid)
return sbi_ecall(SBI_EXTID_HSM, SBI_HART_STATUS_FID, hartid, 0, 0, 0, 0, 0);
}

struct sbiret sbi_hart_suspend(uint32_t suspend_type, unsigned long resume_addr, unsigned long priv)
{
return sbi_ecall(SBI_EXTID_HSM, SBI_HART_SUSPEND_FID, (unsigned long)suspend_type, resume_addr,
priv, 0, 0, 0);
}

static unsigned long ext_table[] = { SBI_EXTID_BASE, SBI_EXTID_TIME, SBI_EXTID_IPI, SBI_EXTID_RFNC,
SBI_EXTID_HSM };

Expand Down Expand Up @@ -382,6 +389,30 @@ static struct sbiret sbi_hsm_status_handler(void)
return ret;
}

static struct sbiret sbi_hsm_suspend_handler(void)
{
struct sbiret ret;
uint32_t suspend_type = (uint32_t)vcpu_readreg(cpu()->vcpu, REG_A0);

spin_lock(&cpu()->vcpu->arch.sbi_ctx.lock);
if (cpu()->vcpu->arch.sbi_ctx.state != STARTED) {
ret.error = SBI_ERR_FAILURE;
} else {
if (suspend_type & SBI_HSM_SUSP_NON_RET_BIT) {
/*
* TODO: We only need to implement this when we get a real physical platform
* with real non-retentive suspend implementation.
* To support this we will need to save and restore the hart registers and CSRs.
*/
ret.error = SBI_ERR_NOT_SUPPORTED;
} else {
ret = sbi_hart_suspend(suspend_type, 0, 0);
}
}

return ret;
}

static struct sbiret sbi_hsm_handler(unsigned long fid)
{
struct sbiret ret;
Expand All @@ -393,6 +424,9 @@ static struct sbiret sbi_hsm_handler(unsigned long fid)
case SBI_HART_STATUS_FID:
ret = sbi_hsm_status_handler();
break;
case SBI_HART_SUSPEND_FID:
ret = sbi_hsm_suspend_handler();
break;
default:
ret.error = SBI_ERR_NOT_SUPPORTED;
}
Expand Down

0 comments on commit 6070880

Please sign in to comment.