diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c index 2ded1d2d..3d28a804 100644 --- a/lib/sbi/sbi_hart.c +++ b/lib/sbi/sbi_hart.c @@ -843,6 +843,41 @@ static int hart_mhpm_get_allowed_bits(void) return num_bits; } +struct hart_ext_validate_entry { + enum sbi_hart_extensions ext; + bool (*validate)(void); +}; + +static bool hart_ext_smepmp_validate(void) +{ + struct sbi_trap_info trap = {0}; + unsigned long oldval; + + oldval = csr_read_allowed(CSR_MSECCFG, &trap); + if (trap.cause) + return false; + + csr_write_allowed(CSR_MSECCFG, &trap, oldval | MSECCFG_RLB); + if (trap.cause) + return false; + + return (csr_swap(CSR_MSECCFG, oldval) & MSECCFG_RLB) == MSECCFG_RLB; +} + +static const struct hart_ext_validate_entry hart_ext_validators[] = { + { SBI_HART_EXT_SMEPMP, hart_ext_smepmp_validate }, +}; + +static void hart_ext_validate(struct sbi_hart_features *hfeatures) +{ + for (int i = 0; i < (int)array_size(hart_ext_validators); i++) { + const struct hart_ext_validate_entry *v = &hart_ext_validators[i]; + + if (__test_bit(v->ext, hfeatures->extensions) && !v->validate()) + __sbi_hart_update_extension(hfeatures, v->ext, false); + } +} + static int hart_detect_features(struct sbi_scratch *scratch) { struct sbi_trap_info trap = {0}; @@ -1022,6 +1057,9 @@ static int hart_detect_features(struct sbi_scratch *scratch) if (rc) return rc; + /* Validate DT-claimed extensions against actual hardware */ + hart_ext_validate(hfeatures); + /* Zicntr should only be detected using traps */ __sbi_hart_update_extension(hfeatures, SBI_HART_EXT_ZICNTR, sbi_hart_has_csr(scratch, SBI_HART_CSR_CYCLE) && diff --git a/lib/utils/fdt/fdt_fixup.c b/lib/utils/fdt/fdt_fixup.c index ac75bfef..104153ae 100644 --- a/lib/utils/fdt/fdt_fixup.c +++ b/lib/utils/fdt/fdt_fixup.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -19,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -126,8 +128,29 @@ static bool isa_ext_zicbom_validate(void *fdt, int cpu_offset) return fdt_parse_cbom_block_size(fdt, cpu_offset, &block_size) == 0; } +static bool isa_ext_smepmp_validate(void *fdt, int cpu_offset) +{ + struct sbi_trap_info trap = {0}; + unsigned long oldval; + + (void)fdt; + (void)cpu_offset; + + oldval = csr_read_allowed(CSR_MSECCFG, &trap); + if (trap.cause) + return false; + + /* Probe Smepmp-specific RLB bit via write-readback */ + csr_write_allowed(CSR_MSECCFG, &trap, oldval | MSECCFG_RLB); + if (trap.cause) + return false; + + return (csr_swap(CSR_MSECCFG, oldval) & MSECCFG_RLB) == MSECCFG_RLB; +} + static const struct isa_ext_validate_entry isa_ext_validators[] = { { "h", isa_ext_h_validate }, + { "smepmp", isa_ext_smepmp_validate }, { "zicbom", isa_ext_zicbom_validate }, };