Skip to content

Commit

Permalink
RISC-V: KVM: Modify SBI extension handler to return SBI error code
Browse files Browse the repository at this point in the history
Currently, the SBI extension handle is expected to return Linux error code.
The top SBI layer converts the Linux error code to SBI specific error code
that can be returned to guest invoking the SBI calls. This model works
as long as SBI error codes have 1-to-1 mappings between them.
However, that may not be true always. This patch attempts to disassociate
both these error codes by allowing the SBI extension implementation to
return SBI specific error codes as well.

The extension will continue to return the Linux error specific code which
will indicate any problem *with* the extension emulation while the
SBI specific error will indicate the problem *of* the emulation.

Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Suggested-by: Andrew Jones <ajones@ventanamicro.com>
Signed-off-by: Atish Patra <atishp@rivosinc.com>
Signed-off-by: Anup Patel <anup@brainfault.org>
  • Loading branch information
Atish Patra authored and Anup Patel committed Feb 7, 2023
1 parent 8cdb8a5 commit bae0dfd
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 97 deletions.
10 changes: 8 additions & 2 deletions arch/riscv/include/asm/kvm_vcpu_sbi.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ struct kvm_vcpu_sbi_context {
int return_handled;
};

struct kvm_vcpu_sbi_return {
unsigned long out_val;
unsigned long err_val;
struct kvm_cpu_trap *utrap;
bool uexit;
};

struct kvm_vcpu_sbi_extension {
unsigned long extid_start;
unsigned long extid_end;
Expand All @@ -27,8 +34,7 @@ struct kvm_vcpu_sbi_extension {
* specific error codes.
*/
int (*handler)(struct kvm_vcpu *vcpu, struct kvm_run *run,
unsigned long *out_val, struct kvm_cpu_trap *utrap,
bool *exit);
struct kvm_vcpu_sbi_return *retdata);

/* Extension specific probe function */
unsigned long (*probe)(struct kvm_vcpu *vcpu);
Expand Down
61 changes: 24 additions & 37 deletions arch/riscv/kvm/vcpu_sbi.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,6 @@
#include <asm/sbi.h>
#include <asm/kvm_vcpu_sbi.h>

static int kvm_linux_err_map_sbi(int err)
{
switch (err) {
case 0:
return SBI_SUCCESS;
case -EPERM:
return SBI_ERR_DENIED;
case -EINVAL:
return SBI_ERR_INVALID_PARAM;
case -EFAULT:
return SBI_ERR_INVALID_ADDRESS;
case -EOPNOTSUPP:
return SBI_ERR_NOT_SUPPORTED;
case -EALREADY:
return SBI_ERR_ALREADY_AVAILABLE;
default:
return SBI_ERR_FAILURE;
};
}

#ifndef CONFIG_RISCV_SBI_V01
static const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_v01 = {
.extid_start = -1UL,
Expand Down Expand Up @@ -125,11 +105,14 @@ int kvm_riscv_vcpu_sbi_ecall(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
int ret = 1;
bool next_sepc = true;
bool userspace_exit = false;
struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
const struct kvm_vcpu_sbi_extension *sbi_ext;
struct kvm_cpu_trap utrap = { 0 };
unsigned long out_val = 0;
struct kvm_cpu_trap utrap = {0};
struct kvm_vcpu_sbi_return sbi_ret = {
.out_val = 0,
.err_val = 0,
.utrap = &utrap,
};
bool ext_is_v01 = false;

sbi_ext = kvm_vcpu_sbi_find_ext(cp->a7);
Expand All @@ -139,42 +122,46 @@ int kvm_riscv_vcpu_sbi_ecall(struct kvm_vcpu *vcpu, struct kvm_run *run)
cp->a7 <= SBI_EXT_0_1_SHUTDOWN)
ext_is_v01 = true;
#endif
ret = sbi_ext->handler(vcpu, run, &out_val, &utrap, &userspace_exit);
ret = sbi_ext->handler(vcpu, run, &sbi_ret);
} else {
/* Return error for unsupported SBI calls */
cp->a0 = SBI_ERR_NOT_SUPPORTED;
goto ecall_done;
}

/*
* When the SBI extension returns a Linux error code, it exits the ioctl
* loop and forwards the error to userspace.
*/
if (ret < 0) {
next_sepc = false;
goto ecall_done;
}

/* Handle special error cases i.e trap, exit or userspace forward */
if (utrap.scause) {
if (sbi_ret.utrap->scause) {
/* No need to increment sepc or exit ioctl loop */
ret = 1;
utrap.sepc = cp->sepc;
kvm_riscv_vcpu_trap_redirect(vcpu, &utrap);
sbi_ret.utrap->sepc = cp->sepc;
kvm_riscv_vcpu_trap_redirect(vcpu, sbi_ret.utrap);
next_sepc = false;
goto ecall_done;
}

/* Exit ioctl loop or Propagate the error code the guest */
if (userspace_exit) {
if (sbi_ret.uexit) {
next_sepc = false;
ret = 0;
} else {
/**
* SBI extension handler always returns an Linux error code. Convert
* it to the SBI specific error code that can be propagated the SBI
* caller.
*/
ret = kvm_linux_err_map_sbi(ret);
cp->a0 = ret;
cp->a0 = sbi_ret.err_val;
ret = 1;
}
ecall_done:
if (next_sepc)
cp->sepc += 4;
if (!ext_is_v01)
cp->a1 = out_val;
/* a1 should only be updated when we continue the ioctl loop */
if (!ext_is_v01 && ret == 1)
cp->a1 = sbi_ret.out_val;

return ret;
}
19 changes: 8 additions & 11 deletions arch/riscv/kvm/vcpu_sbi_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@
#include <asm/kvm_vcpu_sbi.h>

static int kvm_sbi_ext_base_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
unsigned long *out_val,
struct kvm_cpu_trap *trap, bool *exit)
struct kvm_vcpu_sbi_return *retdata)
{
int ret = 0;
struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
const struct kvm_vcpu_sbi_extension *sbi_ext;
unsigned long *out_val = &retdata->out_val;

switch (cp->a6) {
case SBI_EXT_BASE_GET_SPEC_VERSION:
Expand All @@ -43,7 +42,7 @@ static int kvm_sbi_ext_base_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
* forward it to the userspace
*/
kvm_riscv_vcpu_sbi_forward(vcpu, run);
*exit = true;
retdata->uexit = true;
} else {
sbi_ext = kvm_vcpu_sbi_find_ext(cp->a0);
*out_val = sbi_ext && sbi_ext->probe ?
Expand All @@ -60,11 +59,11 @@ static int kvm_sbi_ext_base_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
*out_val = vcpu->arch.mimpid;
break;
default:
ret = -EOPNOTSUPP;
retdata->err_val = SBI_ERR_NOT_SUPPORTED;
break;
}

return ret;
return 0;
}

const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_base = {
Expand All @@ -74,17 +73,15 @@ const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_base = {
};

static int kvm_sbi_ext_forward_handler(struct kvm_vcpu *vcpu,
struct kvm_run *run,
unsigned long *out_val,
struct kvm_cpu_trap *utrap,
bool *exit)
struct kvm_run *run,
struct kvm_vcpu_sbi_return *retdata)
{
/*
* Both SBI experimental and vendor extensions are
* unconditionally forwarded to userspace.
*/
kvm_riscv_vcpu_sbi_forward(vcpu, run);
*exit = true;
retdata->uexit = true;
return 0;
}

Expand Down
28 changes: 14 additions & 14 deletions arch/riscv/kvm/vcpu_sbi_hsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ static int kvm_sbi_hsm_vcpu_start(struct kvm_vcpu *vcpu)

target_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, target_vcpuid);
if (!target_vcpu)
return -EINVAL;
return SBI_ERR_INVALID_PARAM;
if (!target_vcpu->arch.power_off)
return -EALREADY;
return SBI_ERR_ALREADY_AVAILABLE;

reset_cntx = &target_vcpu->arch.guest_reset_context;
/* start address */
Expand All @@ -42,7 +42,7 @@ static int kvm_sbi_hsm_vcpu_start(struct kvm_vcpu *vcpu)
static int kvm_sbi_hsm_vcpu_stop(struct kvm_vcpu *vcpu)
{
if (vcpu->arch.power_off)
return -EACCES;
return SBI_ERR_FAILURE;

kvm_riscv_vcpu_power_off(vcpu);

Expand All @@ -57,7 +57,7 @@ static int kvm_sbi_hsm_vcpu_get_status(struct kvm_vcpu *vcpu)

target_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, target_vcpuid);
if (!target_vcpu)
return -EINVAL;
return SBI_ERR_INVALID_PARAM;
if (!target_vcpu->arch.power_off)
return SBI_HSM_STATE_STARTED;
else if (vcpu->stat.generic.blocking)
Expand All @@ -67,9 +67,7 @@ static int kvm_sbi_hsm_vcpu_get_status(struct kvm_vcpu *vcpu)
}

static int kvm_sbi_ext_hsm_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
unsigned long *out_val,
struct kvm_cpu_trap *utrap,
bool *exit)
struct kvm_vcpu_sbi_return *retdata)
{
int ret = 0;
struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
Expand All @@ -88,27 +86,29 @@ static int kvm_sbi_ext_hsm_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
case SBI_EXT_HSM_HART_STATUS:
ret = kvm_sbi_hsm_vcpu_get_status(vcpu);
if (ret >= 0) {
*out_val = ret;
ret = 0;
retdata->out_val = ret;
retdata->err_val = 0;
}
break;
return 0;
case SBI_EXT_HSM_HART_SUSPEND:
switch (cp->a0) {
case SBI_HSM_SUSPEND_RET_DEFAULT:
kvm_riscv_vcpu_wfi(vcpu);
break;
case SBI_HSM_SUSPEND_NON_RET_DEFAULT:
ret = -EOPNOTSUPP;
ret = SBI_ERR_NOT_SUPPORTED;
break;
default:
ret = -EINVAL;
ret = SBI_ERR_INVALID_PARAM;
}
break;
default:
ret = -EOPNOTSUPP;
ret = SBI_ERR_NOT_SUPPORTED;
}

return ret;
retdata->err_val = ret;

return 0;
}

const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_hsm = {
Expand Down
43 changes: 20 additions & 23 deletions arch/riscv/kvm/vcpu_sbi_replace.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@
#include <asm/kvm_vcpu_sbi.h>

static int kvm_sbi_ext_time_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
unsigned long *out_val,
struct kvm_cpu_trap *utrap, bool *exit)
struct kvm_vcpu_sbi_return *retdata)
{
int ret = 0;
struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
u64 next_cycle;

if (cp->a6 != SBI_EXT_TIME_SET_TIMER)
return -EINVAL;
if (cp->a6 != SBI_EXT_TIME_SET_TIMER) {
retdata->err_val = SBI_ERR_INVALID_PARAM;
return 0;
}

#if __riscv_xlen == 32
next_cycle = ((u64)cp->a1 << 32) | (u64)cp->a0;
Expand All @@ -31,7 +31,7 @@ static int kvm_sbi_ext_time_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
#endif
kvm_riscv_vcpu_timer_next_event(vcpu, next_cycle);

return ret;
return 0;
}

const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_time = {
Expand All @@ -41,8 +41,7 @@ const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_time = {
};

static int kvm_sbi_ext_ipi_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
unsigned long *out_val,
struct kvm_cpu_trap *utrap, bool *exit)
struct kvm_vcpu_sbi_return *retdata)
{
int ret = 0;
unsigned long i;
Expand All @@ -51,8 +50,10 @@ static int kvm_sbi_ext_ipi_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
unsigned long hmask = cp->a0;
unsigned long hbase = cp->a1;

if (cp->a6 != SBI_EXT_IPI_SEND_IPI)
return -EINVAL;
if (cp->a6 != SBI_EXT_IPI_SEND_IPI) {
retdata->err_val = SBI_ERR_INVALID_PARAM;
return 0;
}

kvm_for_each_vcpu(i, tmp, vcpu->kvm) {
if (hbase != -1UL) {
Expand All @@ -76,10 +77,8 @@ const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_ipi = {
};

static int kvm_sbi_ext_rfence_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
unsigned long *out_val,
struct kvm_cpu_trap *utrap, bool *exit)
struct kvm_vcpu_sbi_return *retdata)
{
int ret = 0;
struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
unsigned long hmask = cp->a0;
unsigned long hbase = cp->a1;
Expand Down Expand Up @@ -116,10 +115,10 @@ static int kvm_sbi_ext_rfence_handler(struct kvm_vcpu *vcpu, struct kvm_run *run
*/
break;
default:
ret = -EOPNOTSUPP;
retdata->err_val = SBI_ERR_NOT_SUPPORTED;
}

return ret;
return 0;
}

const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_rfence = {
Expand All @@ -130,14 +129,12 @@ const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_rfence = {

static int kvm_sbi_ext_srst_handler(struct kvm_vcpu *vcpu,
struct kvm_run *run,
unsigned long *out_val,
struct kvm_cpu_trap *utrap, bool *exit)
struct kvm_vcpu_sbi_return *retdata)
{
struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
unsigned long funcid = cp->a6;
u32 reason = cp->a1;
u32 type = cp->a0;
int ret = 0;

switch (funcid) {
case SBI_EXT_SRST_RESET:
Expand All @@ -146,24 +143,24 @@ static int kvm_sbi_ext_srst_handler(struct kvm_vcpu *vcpu,
kvm_riscv_vcpu_sbi_system_reset(vcpu, run,
KVM_SYSTEM_EVENT_SHUTDOWN,
reason);
*exit = true;
retdata->uexit = true;
break;
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
kvm_riscv_vcpu_sbi_system_reset(vcpu, run,
KVM_SYSTEM_EVENT_RESET,
reason);
*exit = true;
retdata->uexit = true;
break;
default:
ret = -EOPNOTSUPP;
retdata->err_val = SBI_ERR_NOT_SUPPORTED;
}
break;
default:
ret = -EOPNOTSUPP;
retdata->err_val = SBI_ERR_NOT_SUPPORTED;
}

return ret;
return 0;
}

const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_srst = {
Expand Down
Loading

0 comments on commit bae0dfd

Please sign in to comment.