Skip to content

Commit 6b72fd1

Browse files
clementlegeravpatel
authored andcommitted
RISC-V: KVM: add support for FWFT SBI extension
Add basic infrastructure to support the FWFT extension in KVM. Signed-off-by: Clément Léger <cleger@rivosinc.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Reviewed-by: Atish Patra <atishp@rivosinc.com> Link: https://lore.kernel.org/r/20250523101932.1594077-14-cleger@rivosinc.com Signed-off-by: Anup Patel <anup@brainfault.org>
1 parent 76eeb9b commit 6b72fd1

7 files changed

Lines changed: 256 additions & 0 deletions

File tree

arch/riscv/include/asm/kvm_host.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <asm/kvm_vcpu_fp.h>
2222
#include <asm/kvm_vcpu_insn.h>
2323
#include <asm/kvm_vcpu_sbi.h>
24+
#include <asm/kvm_vcpu_sbi_fwft.h>
2425
#include <asm/kvm_vcpu_timer.h>
2526
#include <asm/kvm_vcpu_pmu.h>
2627

@@ -263,6 +264,9 @@ struct kvm_vcpu_arch {
263264
/* Performance monitoring context */
264265
struct kvm_pmu pmu_context;
265266

267+
/* Firmware feature SBI extension context */
268+
struct kvm_sbi_fwft fwft_context;
269+
266270
/* 'static' configurations which are set only once */
267271
struct kvm_vcpu_config cfg;
268272

arch/riscv/include/asm/kvm_vcpu_sbi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_hsm;
102102
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_dbcn;
103103
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_susp;
104104
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_sta;
105+
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_fwft;
105106
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_experimental;
106107
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_vendor;
107108

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Copyright (c) 2025 Rivos Inc.
4+
*
5+
* Authors:
6+
* Clément Léger <cleger@rivosinc.com>
7+
*/
8+
9+
#ifndef __KVM_VCPU_RISCV_FWFT_H
10+
#define __KVM_VCPU_RISCV_FWFT_H
11+
12+
#include <asm/sbi.h>
13+
14+
struct kvm_sbi_fwft_feature;
15+
16+
struct kvm_sbi_fwft_config {
17+
const struct kvm_sbi_fwft_feature *feature;
18+
bool supported;
19+
unsigned long flags;
20+
};
21+
22+
/* FWFT data structure per vcpu */
23+
struct kvm_sbi_fwft {
24+
struct kvm_sbi_fwft_config *configs;
25+
};
26+
27+
#define vcpu_to_fwft(vcpu) (&(vcpu)->arch.fwft_context)
28+
29+
#endif /* !__KVM_VCPU_RISCV_FWFT_H */

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ enum KVM_RISCV_SBI_EXT_ID {
205205
KVM_RISCV_SBI_EXT_DBCN,
206206
KVM_RISCV_SBI_EXT_STA,
207207
KVM_RISCV_SBI_EXT_SUSP,
208+
KVM_RISCV_SBI_EXT_FWFT,
208209
KVM_RISCV_SBI_EXT_MAX,
209210
};
210211

arch/riscv/kvm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ kvm-y += vcpu_onereg.o
2727
kvm-$(CONFIG_RISCV_PMU_SBI) += vcpu_pmu.o
2828
kvm-y += vcpu_sbi.o
2929
kvm-y += vcpu_sbi_base.o
30+
kvm-y += vcpu_sbi_fwft.o
3031
kvm-y += vcpu_sbi_hsm.o
3132
kvm-$(CONFIG_RISCV_PMU_SBI) += vcpu_sbi_pmu.o
3233
kvm-y += vcpu_sbi_replace.o

arch/riscv/kvm/vcpu_sbi.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ static const struct kvm_riscv_sbi_extension_entry sbi_ext[] = {
7878
.ext_idx = KVM_RISCV_SBI_EXT_STA,
7979
.ext_ptr = &vcpu_sbi_ext_sta,
8080
},
81+
{
82+
.ext_idx = KVM_RISCV_SBI_EXT_FWFT,
83+
.ext_ptr = &vcpu_sbi_ext_fwft,
84+
},
8185
{
8286
.ext_idx = KVM_RISCV_SBI_EXT_EXPERIMENTAL,
8387
.ext_ptr = &vcpu_sbi_ext_experimental,

arch/riscv/kvm/vcpu_sbi_fwft.c

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (c) 2025 Rivos Inc.
4+
*
5+
* Authors:
6+
* Clément Léger <cleger@rivosinc.com>
7+
*/
8+
9+
#include <linux/errno.h>
10+
#include <linux/err.h>
11+
#include <linux/kvm_host.h>
12+
#include <asm/cpufeature.h>
13+
#include <asm/sbi.h>
14+
#include <asm/kvm_vcpu_sbi.h>
15+
#include <asm/kvm_vcpu_sbi_fwft.h>
16+
17+
struct kvm_sbi_fwft_feature {
18+
/**
19+
* @id: Feature ID
20+
*/
21+
enum sbi_fwft_feature_t id;
22+
23+
/**
24+
* @supported: Check if the feature is supported on the vcpu
25+
*
26+
* This callback is optional, if not provided the feature is assumed to
27+
* be supported
28+
*/
29+
bool (*supported)(struct kvm_vcpu *vcpu);
30+
31+
/**
32+
* @set: Set the feature value
33+
*
34+
* Return SBI_SUCCESS on success or an SBI error (SBI_ERR_*)
35+
*
36+
* This callback is mandatory
37+
*/
38+
long (*set)(struct kvm_vcpu *vcpu, struct kvm_sbi_fwft_config *conf, unsigned long value);
39+
40+
/**
41+
* @get: Get the feature current value
42+
*
43+
* Return SBI_SUCCESS on success or an SBI error (SBI_ERR_*)
44+
*
45+
* This callback is mandatory
46+
*/
47+
long (*get)(struct kvm_vcpu *vcpu, struct kvm_sbi_fwft_config *conf, unsigned long *value);
48+
};
49+
50+
static const enum sbi_fwft_feature_t kvm_fwft_defined_features[] = {
51+
SBI_FWFT_MISALIGNED_EXC_DELEG,
52+
SBI_FWFT_LANDING_PAD,
53+
SBI_FWFT_SHADOW_STACK,
54+
SBI_FWFT_DOUBLE_TRAP,
55+
SBI_FWFT_PTE_AD_HW_UPDATING,
56+
SBI_FWFT_POINTER_MASKING_PMLEN,
57+
};
58+
59+
static bool kvm_fwft_is_defined_feature(enum sbi_fwft_feature_t feature)
60+
{
61+
int i;
62+
63+
for (i = 0; i < ARRAY_SIZE(kvm_fwft_defined_features); i++) {
64+
if (kvm_fwft_defined_features[i] == feature)
65+
return true;
66+
}
67+
68+
return false;
69+
}
70+
71+
static const struct kvm_sbi_fwft_feature features[] = {
72+
};
73+
74+
static struct kvm_sbi_fwft_config *
75+
kvm_sbi_fwft_get_config(struct kvm_vcpu *vcpu, enum sbi_fwft_feature_t feature)
76+
{
77+
int i;
78+
struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu);
79+
80+
for (i = 0; i < ARRAY_SIZE(features); i++) {
81+
if (fwft->configs[i].feature->id == feature)
82+
return &fwft->configs[i];
83+
}
84+
85+
return NULL;
86+
}
87+
88+
static int kvm_fwft_get_feature(struct kvm_vcpu *vcpu, u32 feature,
89+
struct kvm_sbi_fwft_config **conf)
90+
{
91+
struct kvm_sbi_fwft_config *tconf;
92+
93+
tconf = kvm_sbi_fwft_get_config(vcpu, feature);
94+
if (!tconf) {
95+
if (kvm_fwft_is_defined_feature(feature))
96+
return SBI_ERR_NOT_SUPPORTED;
97+
98+
return SBI_ERR_DENIED;
99+
}
100+
101+
if (!tconf->supported)
102+
return SBI_ERR_NOT_SUPPORTED;
103+
104+
*conf = tconf;
105+
106+
return SBI_SUCCESS;
107+
}
108+
109+
static int kvm_sbi_fwft_set(struct kvm_vcpu *vcpu, u32 feature,
110+
unsigned long value, unsigned long flags)
111+
{
112+
int ret;
113+
struct kvm_sbi_fwft_config *conf;
114+
115+
ret = kvm_fwft_get_feature(vcpu, feature, &conf);
116+
if (ret)
117+
return ret;
118+
119+
if ((flags & ~SBI_FWFT_SET_FLAG_LOCK) != 0)
120+
return SBI_ERR_INVALID_PARAM;
121+
122+
if (conf->flags & SBI_FWFT_SET_FLAG_LOCK)
123+
return SBI_ERR_DENIED_LOCKED;
124+
125+
conf->flags = flags;
126+
127+
return conf->feature->set(vcpu, conf, value);
128+
}
129+
130+
static int kvm_sbi_fwft_get(struct kvm_vcpu *vcpu, unsigned long feature,
131+
unsigned long *value)
132+
{
133+
int ret;
134+
struct kvm_sbi_fwft_config *conf;
135+
136+
ret = kvm_fwft_get_feature(vcpu, feature, &conf);
137+
if (ret)
138+
return ret;
139+
140+
return conf->feature->get(vcpu, conf, value);
141+
}
142+
143+
static int kvm_sbi_ext_fwft_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
144+
struct kvm_vcpu_sbi_return *retdata)
145+
{
146+
int ret;
147+
struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
148+
unsigned long funcid = cp->a6;
149+
150+
switch (funcid) {
151+
case SBI_EXT_FWFT_SET:
152+
ret = kvm_sbi_fwft_set(vcpu, cp->a0, cp->a1, cp->a2);
153+
break;
154+
case SBI_EXT_FWFT_GET:
155+
ret = kvm_sbi_fwft_get(vcpu, cp->a0, &retdata->out_val);
156+
break;
157+
default:
158+
ret = SBI_ERR_NOT_SUPPORTED;
159+
break;
160+
}
161+
162+
retdata->err_val = ret;
163+
164+
return 0;
165+
}
166+
167+
static int kvm_sbi_ext_fwft_init(struct kvm_vcpu *vcpu)
168+
{
169+
struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu);
170+
const struct kvm_sbi_fwft_feature *feature;
171+
struct kvm_sbi_fwft_config *conf;
172+
int i;
173+
174+
fwft->configs = kcalloc(ARRAY_SIZE(features), sizeof(struct kvm_sbi_fwft_config),
175+
GFP_KERNEL);
176+
if (!fwft->configs)
177+
return -ENOMEM;
178+
179+
for (i = 0; i < ARRAY_SIZE(features); i++) {
180+
feature = &features[i];
181+
conf = &fwft->configs[i];
182+
if (feature->supported)
183+
conf->supported = feature->supported(vcpu);
184+
else
185+
conf->supported = true;
186+
187+
conf->feature = feature;
188+
}
189+
190+
return 0;
191+
}
192+
193+
static void kvm_sbi_ext_fwft_deinit(struct kvm_vcpu *vcpu)
194+
{
195+
struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu);
196+
197+
kfree(fwft->configs);
198+
}
199+
200+
static void kvm_sbi_ext_fwft_reset(struct kvm_vcpu *vcpu)
201+
{
202+
int i;
203+
struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu);
204+
205+
for (i = 0; i < ARRAY_SIZE(features); i++)
206+
fwft->configs[i].flags = 0;
207+
}
208+
209+
const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_fwft = {
210+
.extid_start = SBI_EXT_FWFT,
211+
.extid_end = SBI_EXT_FWFT,
212+
.handler = kvm_sbi_ext_fwft_handler,
213+
.init = kvm_sbi_ext_fwft_init,
214+
.deinit = kvm_sbi_ext_fwft_deinit,
215+
.reset = kvm_sbi_ext_fwft_reset,
216+
};

0 commit comments

Comments
 (0)