diff options
author | Anup Patel <anup.patel@wdc.com> | 2020-05-18 12:04:18 +0530 |
---|---|---|
committer | Anup Patel <anup@brainfault.org> | 2020-05-19 09:19:48 +0530 |
commit | a38bea9341a2da29bec00d5253ac71da8ca06bab (patch) | |
tree | 167a46716be4bd24d36b64c50412d11c63a15ce1 /lib/sbi/sbi_hart.c | |
parent | 2966510eedf03e47e13f3e1a88039bd4199c1085 (diff) |
lib: sbi_hart: Detect number of supported PMP regions
It is not mandatory for a RISC-V systems to implement all PMP
regions so we have to check all PMPADDRx CSRs to determine excat
number of supported PMP regions.
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Diffstat (limited to 'lib/sbi/sbi_hart.c')
-rw-r--r-- | lib/sbi/sbi_hart.c | 116 |
1 files changed, 80 insertions, 36 deletions
diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c index e62992d..5fa30f3 100644 --- a/lib/sbi/sbi_hart.c +++ b/lib/sbi/sbi_hart.c @@ -24,6 +24,11 @@ extern void __sbi_expected_trap(void); extern void __sbi_expected_trap_hext(void); void (*sbi_hart_expected_trap)(void) = &__sbi_expected_trap; + +struct hart_features { + unsigned long features; + unsigned int pmp_count; +}; static unsigned long hart_features_offset; static void mstatus_init(struct sbi_scratch *scratch, u32 hartid) @@ -125,15 +130,34 @@ void sbi_hart_delegation_dump(struct sbi_scratch *scratch) #endif } +unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch) +{ + struct hart_features *hfeatures = + sbi_scratch_offset_ptr(scratch, hart_features_offset); + + return hfeatures->pmp_count; +} + +int sbi_hart_pmp_get(struct sbi_scratch *scratch, unsigned int n, + unsigned long *prot_out, unsigned long *addr_out, + unsigned long *size) +{ + if (sbi_hart_pmp_count(scratch) <= n) + return SBI_EINVAL; + + return pmp_get(n, prot_out, addr_out, size); +} + void sbi_hart_pmp_dump(struct sbi_scratch *scratch) { unsigned long prot, addr, size; - unsigned int i; + unsigned int i, pmp_count; if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP)) return; - for (i = 0; i < PMP_COUNT; i++) { + pmp_count = sbi_hart_pmp_count(scratch); + for (i = 0; i < pmp_count; i++) { pmp_get(i, &prot, &addr, &size); if (!(prot & PMP_A)) continue; @@ -158,12 +182,14 @@ void sbi_hart_pmp_dump(struct sbi_scratch *scratch) int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long addr, unsigned long attr) { - unsigned long prot, size, i, tempaddr; + unsigned long prot, size, tempaddr; + unsigned int i, pmp_count; if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP)) return SBI_OK; - for (i = 0; i < PMP_COUNT; i++) { + pmp_count = sbi_hart_pmp_count(scratch); + for (i = 0; i < pmp_count; i++) { pmp_get(i, &prot, &tempaddr, &size); if (!(prot & PMP_A)) continue; @@ -177,7 +203,7 @@ int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long addr, static int pmp_init(struct sbi_scratch *scratch, u32 hartid) { - u32 i, pmp_idx = 0, count; + u32 i, pmp_idx = 0, pmp_count, count; unsigned long fw_start, fw_size_log2; ulong prot, addr, log2size; const struct sbi_platform *plat = sbi_platform_ptr(scratch); @@ -192,7 +218,8 @@ static int pmp_init(struct sbi_scratch *scratch, u32 hartid) /* Platform specific PMP regions */ count = sbi_platform_pmp_region_count(plat, hartid); - for (i = 0; i < count && pmp_idx < (PMP_COUNT - 1); i++) { + pmp_count = sbi_hart_pmp_count(scratch); + for (i = 0; i < count && pmp_idx < (pmp_count - 1); i++) { if (sbi_platform_pmp_region_info(plat, hartid, i, &prot, &addr, &log2size)) continue; @@ -219,11 +246,10 @@ static int pmp_init(struct sbi_scratch *scratch, u32 hartid) */ bool sbi_hart_has_feature(struct sbi_scratch *scratch, unsigned long feature) { - unsigned long *hart_features; + struct hart_features *hfeatures = + sbi_scratch_offset_ptr(scratch, hart_features_offset); - hart_features = sbi_scratch_offset_ptr(scratch, hart_features_offset); - - if (*hart_features & feature) + if (hfeatures->features & feature) return true; else return false; @@ -231,11 +257,10 @@ bool sbi_hart_has_feature(struct sbi_scratch *scratch, unsigned long feature) static unsigned long hart_get_features(struct sbi_scratch *scratch) { - unsigned long *hart_features; - - hart_features = sbi_scratch_offset_ptr(scratch, hart_features_offset); + struct hart_features *hfeatures = + sbi_scratch_offset_ptr(scratch, hart_features_offset); - return *hart_features; + return hfeatures->features; } static inline char *sbi_hart_feature_id2string(unsigned long feature) @@ -311,65 +336,84 @@ done: static void hart_detect_features(struct sbi_scratch *scratch) { struct sbi_trap_info trap = {0}; - unsigned long *hart_features; - unsigned long csr_val; + struct hart_features *hfeatures; + unsigned long val; - hart_features = sbi_scratch_offset_ptr(scratch, hart_features_offset); + /* Reset hart features */ + hfeatures = sbi_scratch_offset_ptr(scratch, hart_features_offset); + hfeatures->features = 0; + hfeatures->pmp_count = 0; /* Detect if hart supports PMP feature */ - csr_val = csr_read_allowed(CSR_PMPCFG0, (unsigned long)&trap); - if (!trap.cause) { - csr_write_allowed(CSR_PMPCFG0, (unsigned long)&trap, csr_val); - if (!trap.cause) - *hart_features |= SBI_HART_HAS_PMP; +#define __detect_pmp(__pmp_csr) \ + val = csr_read_allowed(__pmp_csr, (ulong)&trap); \ + if (!trap.cause) { \ + csr_write_allowed(__pmp_csr, (ulong)&trap, val);\ + if (!trap.cause) \ + hfeatures->pmp_count++; \ } + __detect_pmp(CSR_PMPADDR0); + __detect_pmp(CSR_PMPADDR1); + __detect_pmp(CSR_PMPADDR2); + __detect_pmp(CSR_PMPADDR3); + __detect_pmp(CSR_PMPADDR4); + __detect_pmp(CSR_PMPADDR5); + __detect_pmp(CSR_PMPADDR6); + __detect_pmp(CSR_PMPADDR7); + __detect_pmp(CSR_PMPADDR8); + __detect_pmp(CSR_PMPADDR9); + __detect_pmp(CSR_PMPADDR10); + __detect_pmp(CSR_PMPADDR11); + __detect_pmp(CSR_PMPADDR12); + __detect_pmp(CSR_PMPADDR13); + __detect_pmp(CSR_PMPADDR14); + __detect_pmp(CSR_PMPADDR15); +#undef __detect_pmp + + /* Set hart PMP feature if we have at least one PMP region */ + if (hfeatures->pmp_count) + hfeatures->features |= SBI_HART_HAS_PMP; /* Detect if hart supports SCOUNTEREN feature */ trap.cause = 0; - csr_val = csr_read_allowed(CSR_SCOUNTEREN, (unsigned long)&trap); + val = csr_read_allowed(CSR_SCOUNTEREN, (unsigned long)&trap); if (!trap.cause) { - csr_write_allowed(CSR_SCOUNTEREN, (unsigned long)&trap, - csr_val); + csr_write_allowed(CSR_SCOUNTEREN, (unsigned long)&trap, val); if (!trap.cause) - *hart_features |= SBI_HART_HAS_SCOUNTEREN; + hfeatures->features |= SBI_HART_HAS_SCOUNTEREN; } /* Detect if hart supports MCOUNTEREN feature */ trap.cause = 0; - csr_val = csr_read_allowed(CSR_MCOUNTEREN, (unsigned long)&trap); + val = csr_read_allowed(CSR_MCOUNTEREN, (unsigned long)&trap); if (!trap.cause) { - csr_write_allowed(CSR_MCOUNTEREN, (unsigned long)&trap, - csr_val); + csr_write_allowed(CSR_MCOUNTEREN, (unsigned long)&trap, val); if (!trap.cause) - *hart_features |= SBI_HART_HAS_MCOUNTEREN; + hfeatures->features |= SBI_HART_HAS_MCOUNTEREN; } /* Detect if hart supports time CSR */ trap.cause = 0; csr_read_allowed(CSR_TIME, (unsigned long)&trap); if (!trap.cause) - *hart_features |= SBI_HART_HAS_TIME; + hfeatures->features |= SBI_HART_HAS_TIME; } int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot) { int rc; - unsigned long *hart_features; if (cold_boot) { if (misa_extension('H')) sbi_hart_expected_trap = &__sbi_expected_trap_hext; hart_features_offset = sbi_scratch_alloc_offset( - sizeof(*hart_features), + sizeof(struct hart_features), "HART_FEATURES"); if (!hart_features_offset) return SBI_ENOMEM; } - hart_features = sbi_scratch_offset_ptr(scratch, hart_features_offset); - *hart_features = 0; - hart_detect_features(scratch); mstatus_init(scratch, hartid); |