@@ -22,6 +22,11 @@ struct kvm_sbi_fwft_feature {
2222 */
2323 enum sbi_fwft_feature_t id ;
2424
25+ /**
26+ * @first_reg_num: ONE_REG index of the first ONE_REG register
27+ */
28+ unsigned long first_reg_num ;
29+
2530 /**
2631 * @supported: Check if the feature is supported on the vcpu
2732 *
@@ -44,7 +49,8 @@ struct kvm_sbi_fwft_feature {
4449 *
4550 * This callback is mandatory
4651 */
47- long (* set )(struct kvm_vcpu * vcpu , struct kvm_sbi_fwft_config * conf , unsigned long value );
52+ long (* set )(struct kvm_vcpu * vcpu , struct kvm_sbi_fwft_config * conf ,
53+ bool one_reg_access , unsigned long value );
4854
4955 /**
5056 * @get: Get the feature current value
@@ -53,7 +59,8 @@ struct kvm_sbi_fwft_feature {
5359 *
5460 * This callback is mandatory
5561 */
56- long (* get )(struct kvm_vcpu * vcpu , struct kvm_sbi_fwft_config * conf , unsigned long * value );
62+ long (* get )(struct kvm_vcpu * vcpu , struct kvm_sbi_fwft_config * conf ,
63+ bool one_reg_access , unsigned long * value );
5764};
5865
5966static const enum sbi_fwft_feature_t kvm_fwft_defined_features [] = {
@@ -91,16 +98,18 @@ static void kvm_sbi_fwft_reset_misaligned_delegation(struct kvm_vcpu *vcpu)
9198
9299static long kvm_sbi_fwft_set_misaligned_delegation (struct kvm_vcpu * vcpu ,
93100 struct kvm_sbi_fwft_config * conf ,
94- unsigned long value )
101+ bool one_reg_access , unsigned long value )
95102{
96103 struct kvm_vcpu_config * cfg = & vcpu -> arch .cfg ;
97104
98105 if (value == 1 ) {
99106 cfg -> hedeleg |= MIS_DELEG ;
100- csr_set (CSR_HEDELEG , MIS_DELEG );
107+ if (!one_reg_access )
108+ csr_set (CSR_HEDELEG , MIS_DELEG );
101109 } else if (value == 0 ) {
102110 cfg -> hedeleg &= ~MIS_DELEG ;
103- csr_clear (CSR_HEDELEG , MIS_DELEG );
111+ if (!one_reg_access )
112+ csr_clear (CSR_HEDELEG , MIS_DELEG );
104113 } else {
105114 return SBI_ERR_INVALID_PARAM ;
106115 }
@@ -110,10 +119,11 @@ static long kvm_sbi_fwft_set_misaligned_delegation(struct kvm_vcpu *vcpu,
110119
111120static long kvm_sbi_fwft_get_misaligned_delegation (struct kvm_vcpu * vcpu ,
112121 struct kvm_sbi_fwft_config * conf ,
113- unsigned long * value )
122+ bool one_reg_access , unsigned long * value )
114123{
115- * value = ( csr_read ( CSR_HEDELEG ) & MIS_DELEG ) == MIS_DELEG ;
124+ struct kvm_vcpu_config * cfg = & vcpu -> arch . cfg ;
116125
126+ * value = (cfg -> hedeleg & MIS_DELEG ) == MIS_DELEG ;
117127 return SBI_SUCCESS ;
118128}
119129
@@ -145,7 +155,7 @@ static void kvm_sbi_fwft_reset_pointer_masking_pmlen(struct kvm_vcpu *vcpu)
145155
146156static long kvm_sbi_fwft_set_pointer_masking_pmlen (struct kvm_vcpu * vcpu ,
147157 struct kvm_sbi_fwft_config * conf ,
148- unsigned long value )
158+ bool one_reg_access , unsigned long value )
149159{
150160 struct kvm_sbi_fwft * fwft = vcpu_to_fwft (vcpu );
151161 unsigned long pmm ;
@@ -176,14 +186,15 @@ static long kvm_sbi_fwft_set_pointer_masking_pmlen(struct kvm_vcpu *vcpu,
176186 * update here so that VCPU see's pointer masking mode change
177187 * immediately.
178188 */
179- csr_write (CSR_HENVCFG , vcpu -> arch .cfg .henvcfg );
189+ if (!one_reg_access )
190+ csr_write (CSR_HENVCFG , vcpu -> arch .cfg .henvcfg );
180191
181192 return SBI_SUCCESS ;
182193}
183194
184195static long kvm_sbi_fwft_get_pointer_masking_pmlen (struct kvm_vcpu * vcpu ,
185196 struct kvm_sbi_fwft_config * conf ,
186- unsigned long * value )
197+ bool one_reg_access , unsigned long * value )
187198{
188199 switch (vcpu -> arch .cfg .henvcfg & ENVCFG_PMM ) {
189200 case ENVCFG_PMM_PMLEN_0 :
@@ -207,6 +218,8 @@ static long kvm_sbi_fwft_get_pointer_masking_pmlen(struct kvm_vcpu *vcpu,
207218static const struct kvm_sbi_fwft_feature features [] = {
208219 {
209220 .id = SBI_FWFT_MISALIGNED_EXC_DELEG ,
221+ .first_reg_num = offsetof(struct kvm_riscv_sbi_fwft , misaligned_deleg .enable ) /
222+ sizeof (unsigned long ),
210223 .supported = kvm_sbi_fwft_misaligned_delegation_supported ,
211224 .reset = kvm_sbi_fwft_reset_misaligned_delegation ,
212225 .set = kvm_sbi_fwft_set_misaligned_delegation ,
@@ -215,6 +228,8 @@ static const struct kvm_sbi_fwft_feature features[] = {
215228#ifndef CONFIG_32BIT
216229 {
217230 .id = SBI_FWFT_POINTER_MASKING_PMLEN ,
231+ .first_reg_num = offsetof(struct kvm_riscv_sbi_fwft , pointer_masking .enable ) /
232+ sizeof (unsigned long ),
218233 .supported = kvm_sbi_fwft_pointer_masking_pmlen_supported ,
219234 .reset = kvm_sbi_fwft_reset_pointer_masking_pmlen ,
220235 .set = kvm_sbi_fwft_set_pointer_masking_pmlen ,
@@ -223,6 +238,20 @@ static const struct kvm_sbi_fwft_feature features[] = {
223238#endif
224239};
225240
241+ static const struct kvm_sbi_fwft_feature * kvm_sbi_fwft_regnum_to_feature (unsigned long reg_num )
242+ {
243+ const struct kvm_sbi_fwft_feature * feature ;
244+ int i ;
245+
246+ for (i = 0 ; i < ARRAY_SIZE (features ); i ++ ) {
247+ feature = & features [i ];
248+ if (feature -> first_reg_num <= reg_num && reg_num < (feature -> first_reg_num + 3 ))
249+ return feature ;
250+ }
251+
252+ return NULL ;
253+ }
254+
226255static struct kvm_sbi_fwft_config *
227256kvm_sbi_fwft_get_config (struct kvm_vcpu * vcpu , enum sbi_fwft_feature_t feature )
228257{
@@ -250,7 +279,7 @@ static int kvm_fwft_get_feature(struct kvm_vcpu *vcpu, u32 feature,
250279 return SBI_ERR_DENIED ;
251280 }
252281
253- if (!tconf -> supported )
282+ if (!tconf -> supported || ! tconf -> enabled )
254283 return SBI_ERR_NOT_SUPPORTED ;
255284
256285 * conf = tconf ;
@@ -276,7 +305,7 @@ static int kvm_sbi_fwft_set(struct kvm_vcpu *vcpu, u32 feature,
276305
277306 conf -> flags = flags ;
278307
279- return conf -> feature -> set (vcpu , conf , value );
308+ return conf -> feature -> set (vcpu , conf , false, value );
280309}
281310
282311static int kvm_sbi_fwft_get (struct kvm_vcpu * vcpu , unsigned long feature ,
@@ -289,7 +318,7 @@ static int kvm_sbi_fwft_get(struct kvm_vcpu *vcpu, unsigned long feature,
289318 if (ret )
290319 return ret ;
291320
292- return conf -> feature -> get (vcpu , conf , value );
321+ return conf -> feature -> get (vcpu , conf , false, value );
293322}
294323
295324static int kvm_sbi_ext_fwft_handler (struct kvm_vcpu * vcpu , struct kvm_run * run ,
@@ -336,6 +365,7 @@ static int kvm_sbi_ext_fwft_init(struct kvm_vcpu *vcpu)
336365 else
337366 conf -> supported = true;
338367
368+ conf -> enabled = conf -> supported ;
339369 conf -> feature = feature ;
340370 }
341371
@@ -363,11 +393,152 @@ static void kvm_sbi_ext_fwft_reset(struct kvm_vcpu *vcpu)
363393 }
364394}
365395
396+ static unsigned long kvm_sbi_ext_fwft_get_reg_count (struct kvm_vcpu * vcpu )
397+ {
398+ unsigned long max_reg_count = sizeof (struct kvm_riscv_sbi_fwft ) / sizeof (unsigned long );
399+ const struct kvm_sbi_fwft_feature * feature ;
400+ struct kvm_sbi_fwft_config * conf ;
401+ unsigned long reg , ret = 0 ;
402+
403+ for (reg = 0 ; reg < max_reg_count ; reg ++ ) {
404+ feature = kvm_sbi_fwft_regnum_to_feature (reg );
405+ if (!feature )
406+ continue ;
407+
408+ conf = kvm_sbi_fwft_get_config (vcpu , feature -> id );
409+ if (!conf || !conf -> supported )
410+ continue ;
411+
412+ ret ++ ;
413+ }
414+
415+ return ret ;
416+ }
417+
418+ static int kvm_sbi_ext_fwft_get_reg_id (struct kvm_vcpu * vcpu , int index , u64 * reg_id )
419+ {
420+ int reg , max_reg_count = sizeof (struct kvm_riscv_sbi_fwft ) / sizeof (unsigned long );
421+ const struct kvm_sbi_fwft_feature * feature ;
422+ struct kvm_sbi_fwft_config * conf ;
423+ int idx = 0 ;
424+
425+ for (reg = 0 ; reg < max_reg_count ; reg ++ ) {
426+ feature = kvm_sbi_fwft_regnum_to_feature (reg );
427+ if (!feature )
428+ continue ;
429+
430+ conf = kvm_sbi_fwft_get_config (vcpu , feature -> id );
431+ if (!conf || !conf -> supported )
432+ continue ;
433+
434+ if (index == idx ) {
435+ * reg_id = KVM_REG_RISCV |
436+ (IS_ENABLED (CONFIG_32BIT ) ?
437+ KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64 ) |
438+ KVM_REG_RISCV_SBI_STATE |
439+ KVM_REG_RISCV_SBI_FWFT | reg ;
440+ return 0 ;
441+ }
442+
443+ idx ++ ;
444+ }
445+
446+ return - ENOENT ;
447+ }
448+
449+ static int kvm_sbi_ext_fwft_get_reg (struct kvm_vcpu * vcpu , unsigned long reg_num ,
450+ unsigned long reg_size , void * reg_val )
451+ {
452+ const struct kvm_sbi_fwft_feature * feature ;
453+ struct kvm_sbi_fwft_config * conf ;
454+ unsigned long * value ;
455+ int ret = 0 ;
456+
457+ if (reg_size != sizeof (unsigned long ))
458+ return - EINVAL ;
459+ value = reg_val ;
460+
461+ feature = kvm_sbi_fwft_regnum_to_feature (reg_num );
462+ if (!feature )
463+ return - ENOENT ;
464+
465+ conf = kvm_sbi_fwft_get_config (vcpu , feature -> id );
466+ if (!conf || !conf -> supported )
467+ return - ENOENT ;
468+
469+ switch (reg_num - feature -> first_reg_num ) {
470+ case 0 :
471+ * value = conf -> enabled ;
472+ break ;
473+ case 1 :
474+ * value = conf -> flags ;
475+ break ;
476+ case 2 :
477+ ret = conf -> feature -> get (vcpu , conf , true, value );
478+ break ;
479+ default :
480+ return - ENOENT ;
481+ }
482+
483+ return sbi_err_map_linux_errno (ret );
484+ }
485+
486+ static int kvm_sbi_ext_fwft_set_reg (struct kvm_vcpu * vcpu , unsigned long reg_num ,
487+ unsigned long reg_size , const void * reg_val )
488+ {
489+ const struct kvm_sbi_fwft_feature * feature ;
490+ struct kvm_sbi_fwft_config * conf ;
491+ unsigned long value ;
492+ int ret = 0 ;
493+
494+ if (reg_size != sizeof (unsigned long ))
495+ return - EINVAL ;
496+ value = * (const unsigned long * )reg_val ;
497+
498+ feature = kvm_sbi_fwft_regnum_to_feature (reg_num );
499+ if (!feature )
500+ return - ENOENT ;
501+
502+ conf = kvm_sbi_fwft_get_config (vcpu , feature -> id );
503+ if (!conf || !conf -> supported )
504+ return - ENOENT ;
505+
506+ switch (reg_num - feature -> first_reg_num ) {
507+ case 0 :
508+ switch (value ) {
509+ case 0 :
510+ conf -> enabled = false;
511+ break ;
512+ case 1 :
513+ conf -> enabled = true;
514+ break ;
515+ default :
516+ return - EINVAL ;
517+ }
518+ break ;
519+ case 1 :
520+ conf -> flags = value & SBI_FWFT_SET_FLAG_LOCK ;
521+ break ;
522+ case 2 :
523+ ret = conf -> feature -> set (vcpu , conf , true, value );
524+ break ;
525+ default :
526+ return - ENOENT ;
527+ }
528+
529+ return sbi_err_map_linux_errno (ret );
530+ }
531+
366532const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_fwft = {
367533 .extid_start = SBI_EXT_FWFT ,
368534 .extid_end = SBI_EXT_FWFT ,
369535 .handler = kvm_sbi_ext_fwft_handler ,
370536 .init = kvm_sbi_ext_fwft_init ,
371537 .deinit = kvm_sbi_ext_fwft_deinit ,
372538 .reset = kvm_sbi_ext_fwft_reset ,
539+ .state_reg_subtype = KVM_REG_RISCV_SBI_FWFT ,
540+ .get_state_reg_count = kvm_sbi_ext_fwft_get_reg_count ,
541+ .get_state_reg_id = kvm_sbi_ext_fwft_get_reg_id ,
542+ .get_state_reg = kvm_sbi_ext_fwft_get_reg ,
543+ .set_state_reg = kvm_sbi_ext_fwft_set_reg ,
373544};
0 commit comments