Skip to content

Commit f61ce89

Browse files
Andrew Jonesavpatel
authored andcommitted
RISC-V: KVM: Add support for SBI STA registers
KVM userspace needs to be able to save and restore the steal-time shared memory address. Provide the address through the get/set-one-reg interface with two ulong-sized SBI STA extension registers (lo and hi). 64-bit KVM userspace must not set the hi register to anything other than zero and is allowed to completely neglect saving/restoring it. Reviewed-by: Anup Patel <anup@brainfault.org> Signed-off-by: Andrew Jones <ajones@ventanamicro.com> Signed-off-by: Anup Patel <anup@brainfault.org>
1 parent 5b9e413 commit f61ce89

5 files changed

Lines changed: 97 additions & 14 deletions

File tree

arch/riscv/include/asm/kvm_vcpu_sbi.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ bool riscv_vcpu_supports_sbi_ext(struct kvm_vcpu *vcpu, int idx);
7070
int kvm_riscv_vcpu_sbi_ecall(struct kvm_vcpu *vcpu, struct kvm_run *run);
7171
void kvm_riscv_vcpu_sbi_init(struct kvm_vcpu *vcpu);
7272

73+
int kvm_riscv_vcpu_get_reg_sbi_sta(struct kvm_vcpu *vcpu, unsigned long reg_num,
74+
unsigned long *reg_val);
75+
int kvm_riscv_vcpu_set_reg_sbi_sta(struct kvm_vcpu *vcpu, unsigned long reg_num,
76+
unsigned long reg_val);
77+
7378
#ifdef CONFIG_RISCV_SBI_V01
7479
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_v01;
7580
#endif

arch/riscv/include/uapi/asm/kvm.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,12 @@ enum KVM_RISCV_SBI_EXT_ID {
161161
KVM_RISCV_SBI_EXT_MAX,
162162
};
163163

164+
/* SBI STA extension registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */
165+
struct kvm_riscv_sbi_sta {
166+
unsigned long shmem_lo;
167+
unsigned long shmem_hi;
168+
};
169+
164170
/* Possible states for kvm_riscv_timer */
165171
#define KVM_RISCV_TIMER_STATE_OFF 0
166172
#define KVM_RISCV_TIMER_STATE_ON 1
@@ -244,6 +250,9 @@ enum KVM_RISCV_SBI_EXT_ID {
244250

245251
/* Registers for specific SBI extensions are mapped as type 10 */
246252
#define KVM_REG_RISCV_SBI_STATE (0x0a << KVM_REG_RISCV_TYPE_SHIFT)
253+
#define KVM_REG_RISCV_SBI_STA (0x0 << KVM_REG_RISCV_SUBTYPE_SHIFT)
254+
#define KVM_REG_RISCV_SBI_STA_REG(name) \
255+
(offsetof(struct kvm_riscv_sbi_sta, name) / sizeof(unsigned long))
247256

248257
/* Device Control API: RISC-V AIA */
249258
#define KVM_DEV_RISCV_APLIC_ALIGN 0x1000

arch/riscv/kvm/vcpu_onereg.c

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -961,27 +961,36 @@ static unsigned long num_sbi_ext_regs(struct kvm_vcpu *vcpu)
961961
return copy_sbi_ext_reg_indices(vcpu, NULL);
962962
}
963963

964-
static inline unsigned long num_sbi_regs(struct kvm_vcpu *vcpu)
965-
{
966-
return 0;
967-
}
968-
969964
static int copy_sbi_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
970965
{
971-
int n = num_sbi_regs(vcpu);
966+
struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context;
967+
int total = 0;
972968

973-
for (int i = 0; i < n; i++) {
974-
u64 reg = KVM_REG_RISCV | KVM_REG_SIZE_U64 |
975-
KVM_REG_RISCV_SBI_STATE | i;
969+
if (scontext->ext_status[KVM_RISCV_SBI_EXT_STA] == KVM_RISCV_SBI_EXT_STATUS_ENABLED) {
970+
u64 size = IS_ENABLED(CONFIG_32BIT) ? KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64;
971+
int n = sizeof(struct kvm_riscv_sbi_sta) / sizeof(unsigned long);
976972

977-
if (uindices) {
978-
if (put_user(reg, uindices))
979-
return -EFAULT;
980-
uindices++;
973+
for (int i = 0; i < n; i++) {
974+
u64 reg = KVM_REG_RISCV | size |
975+
KVM_REG_RISCV_SBI_STATE |
976+
KVM_REG_RISCV_SBI_STA | i;
977+
978+
if (uindices) {
979+
if (put_user(reg, uindices))
980+
return -EFAULT;
981+
uindices++;
982+
}
981983
}
984+
985+
total += n;
982986
}
983987

984-
return n;
988+
return total;
989+
}
990+
991+
static inline unsigned long num_sbi_regs(struct kvm_vcpu *vcpu)
992+
{
993+
return copy_sbi_reg_indices(vcpu, NULL);
985994
}
986995

987996
static inline unsigned long num_vector_regs(const struct kvm_vcpu *vcpu)

arch/riscv/kvm/vcpu_sbi.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,8 @@ int kvm_riscv_vcpu_set_reg_sbi(struct kvm_vcpu *vcpu,
345345
reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK;
346346

347347
switch (reg_subtype) {
348+
case KVM_REG_RISCV_SBI_STA:
349+
return kvm_riscv_vcpu_set_reg_sbi_sta(vcpu, reg_num, reg_val);
348350
default:
349351
return -EINVAL;
350352
}
@@ -370,6 +372,9 @@ int kvm_riscv_vcpu_get_reg_sbi(struct kvm_vcpu *vcpu,
370372
reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK;
371373

372374
switch (reg_subtype) {
375+
case KVM_REG_RISCV_SBI_STA:
376+
ret = kvm_riscv_vcpu_get_reg_sbi_sta(vcpu, reg_num, &reg_val);
377+
break;
373378
default:
374379
return -EINVAL;
375380
}

arch/riscv/kvm/vcpu_sbi_sta.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
* Copyright (c) 2023 Ventana Micro Systems Inc.
44
*/
55

6+
#include <linux/kconfig.h>
7+
#include <linux/kernel.h>
68
#include <linux/kvm_host.h>
79

810
#include <asm/kvm_vcpu_sbi.h>
@@ -59,3 +61,56 @@ const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_sta = {
5961
.handler = kvm_sbi_ext_sta_handler,
6062
.probe = kvm_sbi_ext_sta_probe,
6163
};
64+
65+
int kvm_riscv_vcpu_get_reg_sbi_sta(struct kvm_vcpu *vcpu,
66+
unsigned long reg_num,
67+
unsigned long *reg_val)
68+
{
69+
switch (reg_num) {
70+
case KVM_REG_RISCV_SBI_STA_REG(shmem_lo):
71+
*reg_val = (unsigned long)vcpu->arch.sta.shmem;
72+
break;
73+
case KVM_REG_RISCV_SBI_STA_REG(shmem_hi):
74+
if (IS_ENABLED(CONFIG_32BIT))
75+
*reg_val = upper_32_bits(vcpu->arch.sta.shmem);
76+
else
77+
*reg_val = 0;
78+
break;
79+
default:
80+
return -EINVAL;
81+
}
82+
83+
return 0;
84+
}
85+
86+
int kvm_riscv_vcpu_set_reg_sbi_sta(struct kvm_vcpu *vcpu,
87+
unsigned long reg_num,
88+
unsigned long reg_val)
89+
{
90+
switch (reg_num) {
91+
case KVM_REG_RISCV_SBI_STA_REG(shmem_lo):
92+
if (IS_ENABLED(CONFIG_32BIT)) {
93+
gpa_t hi = upper_32_bits(vcpu->arch.sta.shmem);
94+
95+
vcpu->arch.sta.shmem = reg_val;
96+
vcpu->arch.sta.shmem |= hi << 32;
97+
} else {
98+
vcpu->arch.sta.shmem = reg_val;
99+
}
100+
break;
101+
case KVM_REG_RISCV_SBI_STA_REG(shmem_hi):
102+
if (IS_ENABLED(CONFIG_32BIT)) {
103+
gpa_t lo = lower_32_bits(vcpu->arch.sta.shmem);
104+
105+
vcpu->arch.sta.shmem = ((gpa_t)reg_val << 32);
106+
vcpu->arch.sta.shmem |= lo;
107+
} else if (reg_val != 0) {
108+
return -EINVAL;
109+
}
110+
break;
111+
default:
112+
return -EINVAL;
113+
}
114+
115+
return 0;
116+
}

0 commit comments

Comments
 (0)