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 #define MIS_DELEG (BIT_ULL(EXC_LOAD_MISALIGNED) | BIT_ULL(EXC_STORE_MISALIGNED)) 18 19 struct kvm_sbi_fwft_feature { 20 /** 21 * @id: Feature ID 22 */ 23 enum sbi_fwft_feature_t id; 24 25 /** 26 * @first_reg_num: ONE_REG index of the first ONE_REG register 27 */ 28 unsigned long first_reg_num; 29 30 /** 31 * @supported: Check if the feature is supported on the vcpu 32 * 33 * This callback is optional, if not provided the feature is assumed to 34 * be supported 35 */ 36 bool (*supported)(struct kvm_vcpu *vcpu); 37 38 /** 39 * @init: Probe and initialize the feature on the vcpu 40 * 41 * This callback is optional. If provided, it will be called during 42 * vcpu initialization to probe the feature availability and perform 43 * any necessary initialization. Returns true if the feature is supported 44 * and initialized successfully, false otherwise. 45 */ 46 bool (*init)(struct kvm_vcpu *vcpu); 47 48 /** 49 * @reset: Reset the feature value irrespective whether feature is supported or not 50 * 51 * This callback is mandatory 52 */ 53 void (*reset)(struct kvm_vcpu *vcpu); 54 55 /** 56 * @set: Set the feature value 57 * 58 * Return SBI_SUCCESS on success or an SBI error (SBI_ERR_*) 59 * 60 * This callback is mandatory 61 */ 62 long (*set)(struct kvm_vcpu *vcpu, struct kvm_sbi_fwft_config *conf, 63 bool one_reg_access, unsigned long value); 64 65 /** 66 * @get: Get the feature current value 67 * 68 * Return SBI_SUCCESS on success or an SBI error (SBI_ERR_*) 69 * 70 * This callback is mandatory 71 */ 72 long (*get)(struct kvm_vcpu *vcpu, struct kvm_sbi_fwft_config *conf, 73 bool one_reg_access, unsigned long *value); 74 }; 75 76 static const enum sbi_fwft_feature_t kvm_fwft_defined_features[] = { 77 SBI_FWFT_MISALIGNED_EXC_DELEG, 78 SBI_FWFT_LANDING_PAD, 79 SBI_FWFT_SHADOW_STACK, 80 SBI_FWFT_DOUBLE_TRAP, 81 SBI_FWFT_PTE_AD_HW_UPDATING, 82 SBI_FWFT_POINTER_MASKING_PMLEN, 83 }; 84 85 static bool kvm_fwft_is_defined_feature(enum sbi_fwft_feature_t feature) 86 { 87 int i; 88 89 for (i = 0; i < ARRAY_SIZE(kvm_fwft_defined_features); i++) { 90 if (kvm_fwft_defined_features[i] == feature) 91 return true; 92 } 93 94 return false; 95 } 96 97 static bool kvm_sbi_fwft_misaligned_delegation_supported(struct kvm_vcpu *vcpu) 98 { 99 return misaligned_traps_can_delegate(); 100 } 101 102 static void kvm_sbi_fwft_reset_misaligned_delegation(struct kvm_vcpu *vcpu) 103 { 104 struct kvm_vcpu_config *cfg = &vcpu->arch.cfg; 105 106 cfg->hedeleg &= ~MIS_DELEG; 107 } 108 109 static long kvm_sbi_fwft_set_misaligned_delegation(struct kvm_vcpu *vcpu, 110 struct kvm_sbi_fwft_config *conf, 111 bool one_reg_access, unsigned long value) 112 { 113 struct kvm_vcpu_config *cfg = &vcpu->arch.cfg; 114 115 if (value == 1) { 116 cfg->hedeleg |= MIS_DELEG; 117 if (!one_reg_access) 118 csr_set(CSR_HEDELEG, MIS_DELEG); 119 } else if (value == 0) { 120 cfg->hedeleg &= ~MIS_DELEG; 121 if (!one_reg_access) 122 csr_clear(CSR_HEDELEG, MIS_DELEG); 123 } else { 124 return SBI_ERR_INVALID_PARAM; 125 } 126 127 return SBI_SUCCESS; 128 } 129 130 static long kvm_sbi_fwft_get_misaligned_delegation(struct kvm_vcpu *vcpu, 131 struct kvm_sbi_fwft_config *conf, 132 bool one_reg_access, unsigned long *value) 133 { 134 struct kvm_vcpu_config *cfg = &vcpu->arch.cfg; 135 136 *value = (cfg->hedeleg & MIS_DELEG) == MIS_DELEG; 137 return SBI_SUCCESS; 138 } 139 140 #ifndef CONFIG_32BIT 141 142 static bool try_to_set_pmm(unsigned long value) 143 { 144 unsigned long prev; 145 bool ret; 146 147 prev = csr_read_clear(CSR_HENVCFG, ENVCFG_PMM); 148 csr_set(CSR_HENVCFG, value); 149 ret = (csr_read_clear(CSR_HENVCFG, ENVCFG_PMM) & ENVCFG_PMM) == value; 150 csr_write(CSR_HENVCFG, prev); 151 152 return ret; 153 } 154 155 static bool kvm_sbi_fwft_pointer_masking_pmlen_supported(struct kvm_vcpu *vcpu) 156 { 157 return riscv_isa_extension_available(vcpu->arch.isa, SMNPM); 158 } 159 160 static bool kvm_sbi_fwft_pointer_masking_pmlen_init(struct kvm_vcpu *vcpu) 161 { 162 struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); 163 164 preempt_disable(); 165 fwft->have_vs_pmlen_7 = try_to_set_pmm(ENVCFG_PMM_PMLEN_7); 166 fwft->have_vs_pmlen_16 = try_to_set_pmm(ENVCFG_PMM_PMLEN_16); 167 preempt_enable(); 168 169 return fwft->have_vs_pmlen_7 || fwft->have_vs_pmlen_16; 170 } 171 172 static void kvm_sbi_fwft_reset_pointer_masking_pmlen(struct kvm_vcpu *vcpu) 173 { 174 vcpu->arch.cfg.henvcfg &= ~ENVCFG_PMM; 175 } 176 177 static long kvm_sbi_fwft_set_pointer_masking_pmlen(struct kvm_vcpu *vcpu, 178 struct kvm_sbi_fwft_config *conf, 179 bool one_reg_access, unsigned long value) 180 { 181 struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); 182 unsigned long pmm; 183 184 switch (value) { 185 case 0: 186 pmm = ENVCFG_PMM_PMLEN_0; 187 break; 188 case 7: 189 if (!fwft->have_vs_pmlen_7) 190 return SBI_ERR_INVALID_PARAM; 191 pmm = ENVCFG_PMM_PMLEN_7; 192 break; 193 case 16: 194 if (!fwft->have_vs_pmlen_16) 195 return SBI_ERR_INVALID_PARAM; 196 pmm = ENVCFG_PMM_PMLEN_16; 197 break; 198 default: 199 return SBI_ERR_INVALID_PARAM; 200 } 201 202 vcpu->arch.cfg.henvcfg &= ~ENVCFG_PMM; 203 vcpu->arch.cfg.henvcfg |= pmm; 204 205 /* 206 * Instead of waiting for vcpu_load/put() to update HENVCFG CSR, 207 * update here so that VCPU see's pointer masking mode change 208 * immediately. 209 */ 210 if (!one_reg_access) 211 csr_write(CSR_HENVCFG, vcpu->arch.cfg.henvcfg); 212 213 return SBI_SUCCESS; 214 } 215 216 static long kvm_sbi_fwft_get_pointer_masking_pmlen(struct kvm_vcpu *vcpu, 217 struct kvm_sbi_fwft_config *conf, 218 bool one_reg_access, unsigned long *value) 219 { 220 switch (vcpu->arch.cfg.henvcfg & ENVCFG_PMM) { 221 case ENVCFG_PMM_PMLEN_0: 222 *value = 0; 223 break; 224 case ENVCFG_PMM_PMLEN_7: 225 *value = 7; 226 break; 227 case ENVCFG_PMM_PMLEN_16: 228 *value = 16; 229 break; 230 default: 231 return SBI_ERR_FAILURE; 232 } 233 234 return SBI_SUCCESS; 235 } 236 237 #endif 238 239 static const struct kvm_sbi_fwft_feature features[] = { 240 { 241 .id = SBI_FWFT_MISALIGNED_EXC_DELEG, 242 .first_reg_num = offsetof(struct kvm_riscv_sbi_fwft, misaligned_deleg.enable) / 243 sizeof(unsigned long), 244 .supported = kvm_sbi_fwft_misaligned_delegation_supported, 245 .reset = kvm_sbi_fwft_reset_misaligned_delegation, 246 .set = kvm_sbi_fwft_set_misaligned_delegation, 247 .get = kvm_sbi_fwft_get_misaligned_delegation, 248 }, 249 #ifndef CONFIG_32BIT 250 { 251 .id = SBI_FWFT_POINTER_MASKING_PMLEN, 252 .first_reg_num = offsetof(struct kvm_riscv_sbi_fwft, pointer_masking.enable) / 253 sizeof(unsigned long), 254 .supported = kvm_sbi_fwft_pointer_masking_pmlen_supported, 255 .init = kvm_sbi_fwft_pointer_masking_pmlen_init, 256 .reset = kvm_sbi_fwft_reset_pointer_masking_pmlen, 257 .set = kvm_sbi_fwft_set_pointer_masking_pmlen, 258 .get = kvm_sbi_fwft_get_pointer_masking_pmlen, 259 }, 260 #endif 261 }; 262 263 static const struct kvm_sbi_fwft_feature *kvm_sbi_fwft_regnum_to_feature(unsigned long reg_num) 264 { 265 const struct kvm_sbi_fwft_feature *feature; 266 int i; 267 268 for (i = 0; i < ARRAY_SIZE(features); i++) { 269 feature = &features[i]; 270 if (feature->first_reg_num <= reg_num && reg_num < (feature->first_reg_num + 3)) 271 return feature; 272 } 273 274 return NULL; 275 } 276 277 static struct kvm_sbi_fwft_config * 278 kvm_sbi_fwft_get_config(struct kvm_vcpu *vcpu, enum sbi_fwft_feature_t feature) 279 { 280 int i; 281 struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); 282 283 for (i = 0; i < ARRAY_SIZE(features); i++) { 284 if (fwft->configs[i].feature->id == feature) 285 return &fwft->configs[i]; 286 } 287 288 return NULL; 289 } 290 291 static int kvm_fwft_get_feature(struct kvm_vcpu *vcpu, u32 feature, 292 struct kvm_sbi_fwft_config **conf) 293 { 294 struct kvm_sbi_fwft_config *tconf; 295 296 tconf = kvm_sbi_fwft_get_config(vcpu, feature); 297 if (!tconf) { 298 if (kvm_fwft_is_defined_feature(feature)) 299 return SBI_ERR_NOT_SUPPORTED; 300 301 return SBI_ERR_DENIED; 302 } 303 304 if (!tconf->supported || !tconf->enabled) 305 return SBI_ERR_NOT_SUPPORTED; 306 else if (tconf->feature->supported && !tconf->feature->supported(vcpu)) 307 return SBI_ERR_NOT_SUPPORTED; 308 309 *conf = tconf; 310 311 return SBI_SUCCESS; 312 } 313 314 static int kvm_sbi_fwft_set(struct kvm_vcpu *vcpu, u32 feature, 315 unsigned long value, unsigned long flags) 316 { 317 int ret; 318 struct kvm_sbi_fwft_config *conf; 319 320 ret = kvm_fwft_get_feature(vcpu, feature, &conf); 321 if (ret) 322 return ret; 323 324 if ((flags & ~SBI_FWFT_SET_FLAG_LOCK) != 0) 325 return SBI_ERR_INVALID_PARAM; 326 327 if (conf->flags & SBI_FWFT_SET_FLAG_LOCK) 328 return SBI_ERR_DENIED_LOCKED; 329 330 conf->flags = flags; 331 332 return conf->feature->set(vcpu, conf, false, value); 333 } 334 335 static int kvm_sbi_fwft_get(struct kvm_vcpu *vcpu, unsigned long feature, 336 unsigned long *value) 337 { 338 int ret; 339 struct kvm_sbi_fwft_config *conf; 340 341 ret = kvm_fwft_get_feature(vcpu, feature, &conf); 342 if (ret) 343 return ret; 344 345 return conf->feature->get(vcpu, conf, false, value); 346 } 347 348 static int kvm_sbi_ext_fwft_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, 349 struct kvm_vcpu_sbi_return *retdata) 350 { 351 int ret; 352 struct kvm_cpu_context *cp = &vcpu->arch.guest_context; 353 unsigned long funcid = cp->a6; 354 355 switch (funcid) { 356 case SBI_EXT_FWFT_SET: 357 ret = kvm_sbi_fwft_set(vcpu, cp->a0, cp->a1, cp->a2); 358 break; 359 case SBI_EXT_FWFT_GET: 360 ret = kvm_sbi_fwft_get(vcpu, cp->a0, &retdata->out_val); 361 break; 362 default: 363 ret = SBI_ERR_NOT_SUPPORTED; 364 break; 365 } 366 367 retdata->err_val = ret; 368 369 return 0; 370 } 371 372 static int kvm_sbi_ext_fwft_init(struct kvm_vcpu *vcpu) 373 { 374 struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); 375 const struct kvm_sbi_fwft_feature *feature; 376 struct kvm_sbi_fwft_config *conf; 377 int i; 378 379 fwft->configs = kzalloc_objs(struct kvm_sbi_fwft_config, 380 ARRAY_SIZE(features)); 381 if (!fwft->configs) 382 return -ENOMEM; 383 384 for (i = 0; i < ARRAY_SIZE(features); i++) { 385 feature = &features[i]; 386 conf = &fwft->configs[i]; 387 if (feature->supported) 388 conf->supported = feature->supported(vcpu); 389 else 390 conf->supported = true; 391 392 if (conf->supported && feature->init) 393 conf->supported = feature->init(vcpu); 394 395 conf->enabled = conf->supported; 396 conf->feature = feature; 397 } 398 399 return 0; 400 } 401 402 static void kvm_sbi_ext_fwft_deinit(struct kvm_vcpu *vcpu) 403 { 404 struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); 405 406 kfree(fwft->configs); 407 } 408 409 static void kvm_sbi_ext_fwft_reset(struct kvm_vcpu *vcpu) 410 { 411 struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); 412 const struct kvm_sbi_fwft_feature *feature; 413 int i; 414 415 for (i = 0; i < ARRAY_SIZE(features); i++) { 416 fwft->configs[i].flags = 0; 417 feature = &features[i]; 418 if (feature->reset) 419 feature->reset(vcpu); 420 } 421 } 422 423 static unsigned long kvm_sbi_ext_fwft_get_reg_count(struct kvm_vcpu *vcpu) 424 { 425 unsigned long max_reg_count = sizeof(struct kvm_riscv_sbi_fwft) / sizeof(unsigned long); 426 const struct kvm_sbi_fwft_feature *feature; 427 struct kvm_sbi_fwft_config *conf; 428 unsigned long reg, ret = 0; 429 430 for (reg = 0; reg < max_reg_count; reg++) { 431 feature = kvm_sbi_fwft_regnum_to_feature(reg); 432 if (!feature) 433 continue; 434 435 conf = kvm_sbi_fwft_get_config(vcpu, feature->id); 436 if (!conf || !conf->supported) 437 continue; 438 else if (conf->feature->supported && !conf->feature->supported(vcpu)) 439 continue; 440 441 ret++; 442 } 443 444 return ret; 445 } 446 447 static int kvm_sbi_ext_fwft_get_reg_id(struct kvm_vcpu *vcpu, int index, u64 *reg_id) 448 { 449 int reg, max_reg_count = sizeof(struct kvm_riscv_sbi_fwft) / sizeof(unsigned long); 450 const struct kvm_sbi_fwft_feature *feature; 451 struct kvm_sbi_fwft_config *conf; 452 int idx = 0; 453 454 for (reg = 0; reg < max_reg_count; reg++) { 455 feature = kvm_sbi_fwft_regnum_to_feature(reg); 456 if (!feature) 457 continue; 458 459 conf = kvm_sbi_fwft_get_config(vcpu, feature->id); 460 if (!conf || !conf->supported) 461 continue; 462 else if (conf->feature->supported && !conf->feature->supported(vcpu)) 463 continue; 464 465 if (index == idx) { 466 *reg_id = KVM_REG_RISCV | 467 (IS_ENABLED(CONFIG_32BIT) ? 468 KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64) | 469 KVM_REG_RISCV_SBI_STATE | 470 KVM_REG_RISCV_SBI_FWFT | reg; 471 return 0; 472 } 473 474 idx++; 475 } 476 477 return -ENOENT; 478 } 479 480 static int kvm_sbi_ext_fwft_get_reg(struct kvm_vcpu *vcpu, unsigned long reg_num, 481 unsigned long reg_size, void *reg_val) 482 { 483 const struct kvm_sbi_fwft_feature *feature; 484 struct kvm_sbi_fwft_config *conf; 485 unsigned long *value; 486 int ret = 0; 487 488 if (reg_size != sizeof(unsigned long)) 489 return -EINVAL; 490 value = reg_val; 491 492 feature = kvm_sbi_fwft_regnum_to_feature(reg_num); 493 if (!feature) 494 return -ENOENT; 495 496 conf = kvm_sbi_fwft_get_config(vcpu, feature->id); 497 if (!conf || !conf->supported) 498 return -ENOENT; 499 else if (conf->feature->supported && !conf->feature->supported(vcpu)) 500 return -ENOENT; 501 502 switch (reg_num - feature->first_reg_num) { 503 case 0: 504 *value = conf->enabled; 505 break; 506 case 1: 507 *value = conf->flags; 508 break; 509 case 2: 510 ret = conf->feature->get(vcpu, conf, true, value); 511 break; 512 default: 513 return -ENOENT; 514 } 515 516 return sbi_err_map_linux_errno(ret); 517 } 518 519 static int kvm_sbi_ext_fwft_set_reg(struct kvm_vcpu *vcpu, unsigned long reg_num, 520 unsigned long reg_size, const void *reg_val) 521 { 522 const struct kvm_sbi_fwft_feature *feature; 523 struct kvm_sbi_fwft_config *conf; 524 unsigned long value; 525 int ret = 0; 526 527 if (reg_size != sizeof(unsigned long)) 528 return -EINVAL; 529 value = *(const unsigned long *)reg_val; 530 531 feature = kvm_sbi_fwft_regnum_to_feature(reg_num); 532 if (!feature) 533 return -ENOENT; 534 535 conf = kvm_sbi_fwft_get_config(vcpu, feature->id); 536 if (!conf || !conf->supported) 537 return -ENOENT; 538 else if (conf->feature->supported && !conf->feature->supported(vcpu)) 539 return -ENOENT; 540 541 switch (reg_num - feature->first_reg_num) { 542 case 0: 543 switch (value) { 544 case 0: 545 conf->enabled = false; 546 break; 547 case 1: 548 conf->enabled = true; 549 break; 550 default: 551 return -EINVAL; 552 } 553 break; 554 case 1: 555 conf->flags = value & SBI_FWFT_SET_FLAG_LOCK; 556 break; 557 case 2: 558 ret = conf->feature->set(vcpu, conf, true, value); 559 vcpu->arch.csr_dirty = true; 560 break; 561 default: 562 return -ENOENT; 563 } 564 565 return sbi_err_map_linux_errno(ret); 566 } 567 568 const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_fwft = { 569 .extid_start = SBI_EXT_FWFT, 570 .extid_end = SBI_EXT_FWFT, 571 .handler = kvm_sbi_ext_fwft_handler, 572 .init = kvm_sbi_ext_fwft_init, 573 .deinit = kvm_sbi_ext_fwft_deinit, 574 .reset = kvm_sbi_ext_fwft_reset, 575 .state_reg_subtype = KVM_REG_RISCV_SBI_FWFT, 576 .get_state_reg_count = kvm_sbi_ext_fwft_get_reg_count, 577 .get_state_reg_id = kvm_sbi_ext_fwft_get_reg_id, 578 .get_state_reg = kvm_sbi_ext_fwft_get_reg, 579 .set_state_reg = kvm_sbi_ext_fwft_set_reg, 580 }; 581