diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h index bce88c59..dfbe8e4c 100644 --- a/include/sbi/sbi_hart.h +++ b/include/sbi/sbi_hart.h @@ -93,6 +93,14 @@ struct sbi_hart_ext_data { extern const struct sbi_hart_ext_data sbi_hart_ext[]; +/** CSRs should be detected by access and trapping */ +enum sbi_hart_csrs { + SBI_HART_CSR_CYCLE = 0, + SBI_HART_CSR_TIME, + SBI_HART_CSR_INSTRET, + SBI_HART_CSR_MAX, +}; + /* * Smepmp enforces access boundaries between M-mode and * S/U-mode. When it is enabled, the PMPs are programmed @@ -112,6 +120,7 @@ struct sbi_hart_features { bool detected; int priv_version; unsigned long extensions[BITS_TO_LONGS(SBI_HART_EXT_MAX)]; + unsigned long csrs[BITS_TO_LONGS(SBI_HART_CSR_MAX)]; unsigned int pmp_count; unsigned int pmp_addr_bits; unsigned int pmp_log2gran; @@ -150,6 +159,7 @@ bool sbi_hart_has_extension(struct sbi_scratch *scratch, enum sbi_hart_extensions ext); void sbi_hart_get_extensions_str(struct sbi_scratch *scratch, char *extension_str, int nestr); +bool sbi_hart_has_csr(struct sbi_scratch *scratch, enum sbi_hart_csrs csr); void __attribute__((noreturn)) sbi_hart_hang(void); diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c index fc4925b5..74ccdd84 100644 --- a/lib/sbi/sbi_hart.c +++ b/lib/sbi/sbi_hart.c @@ -747,6 +747,20 @@ void sbi_hart_get_extensions_str(struct sbi_scratch *scratch, sbi_strncpy(extensions_str, "none", nestr); } +/** + * Check whether a particular CSR is present on the HART + * + * @param scratch pointer to the HART scratch space + * @param csr the CSR number to check + */ +bool sbi_hart_has_csr(struct sbi_scratch *scratch, enum sbi_hart_csrs csr) +{ + struct sbi_hart_features *hfeatures = + sbi_scratch_offset_ptr(scratch, hart_features_offset); + + return __test_bit(csr, hfeatures->csrs); +} + static unsigned long hart_pmp_get_allowed_addr(void) { unsigned long val = 0; @@ -803,7 +817,6 @@ static int hart_detect_features(struct sbi_scratch *scratch) struct sbi_hart_features *hfeatures = sbi_scratch_offset_ptr(scratch, hart_features_offset); unsigned long val, oldval; - bool has_zicntr = false; int rc; /* If hart features already detected then do nothing */ @@ -812,6 +825,7 @@ static int hart_detect_features(struct sbi_scratch *scratch) /* Clear hart features */ sbi_memset(hfeatures->extensions, 0, sizeof(hfeatures->extensions)); + sbi_memset(hfeatures->csrs, 0, sizeof(hfeatures->csrs)); hfeatures->pmp_count = 0; hfeatures->mhpm_mask = 0; hfeatures->priv_version = SBI_HART_PRIV_VER_UNKNOWN; @@ -938,9 +952,6 @@ __pmp_skip: /* Detect if hart supports sscofpmf */ __check_ext_csr(SBI_HART_PRIV_VER_1_11, CSR_SCOUNTOVF, SBI_HART_EXT_SSCOFPMF); - /* Detect if hart supports time CSR */ - __check_ext_csr(SBI_HART_PRIV_VER_UNKNOWN, - CSR_TIME, SBI_HART_EXT_ZICNTR); /* Detect if hart has AIA local interrupt CSRs */ __check_ext_csr(SBI_HART_PRIV_VER_UNKNOWN, CSR_MTOPI, SBI_HART_EXT_SMAIA); @@ -962,8 +973,16 @@ __pmp_skip: #undef __check_ext_csr - /* Save trap based detection of Zicntr */ - has_zicntr = sbi_hart_has_extension(scratch, SBI_HART_EXT_ZICNTR); +#define __check_csr_existence(__csr, __csr_id) \ + csr_read_allowed(__csr, &trap); \ + if (!trap.cause) \ + __set_bit(__csr_id, hfeatures->csrs); + + __check_csr_existence(CSR_CYCLE, SBI_HART_CSR_CYCLE); + __check_csr_existence(CSR_TIME, SBI_HART_CSR_TIME); + __check_csr_existence(CSR_INSTRET, SBI_HART_CSR_INSTRET); + +#undef __check_csr_existence /* Let platform populate extensions */ rc = sbi_platform_extensions_init(sbi_platform_thishart_ptr(), @@ -973,7 +992,9 @@ __pmp_skip: /* Zicntr should only be detected using traps */ __sbi_hart_update_extension(hfeatures, SBI_HART_EXT_ZICNTR, - has_zicntr); + sbi_hart_has_csr(scratch, SBI_HART_CSR_CYCLE) && + sbi_hart_has_csr(scratch, SBI_HART_CSR_TIME) && + sbi_hart_has_csr(scratch, SBI_HART_CSR_INSTRET)); /* Extensions implied by other extensions and features */ if (hfeatures->mhpm_mask) diff --git a/lib/sbi/sbi_timer.c b/lib/sbi/sbi_timer.c index 998a9a67..4088a597 100644 --- a/lib/sbi/sbi_timer.c +++ b/lib/sbi/sbi_timer.c @@ -185,7 +185,7 @@ int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot) if (!time_delta_off) return SBI_ENOMEM; - if (sbi_hart_has_extension(scratch, SBI_HART_EXT_ZICNTR)) + if (sbi_hart_has_csr(scratch, SBI_HART_CSR_TIME)) get_time_val = get_ticks; ret = sbi_platform_timer_init(plat);