lib: Fix CPU capabilities detection function

On some platforms, misa may not be implemented. On such a platform,
reading misa will get 0. At this time, platform is required to
implement a non-standard function to detect the CPU's capabilities.
Therefore, this modification add interfaces for non-standard function.

The MXL field of misa is always at the highest two bits, whether it
is a 32-bit 64-bit or a 128-bit machine. Therefore, this modification
fixes the use of a fixed offset to detect the machine length.

Signed-off-by: Xiang Wang <merle@hardenedlinux.org>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
This commit is contained in:
Xiang Wang 2019-11-26 16:06:29 +05:30 committed by Anup Patel
parent 75f903dd78
commit c96cc03fcc
4 changed files with 89 additions and 12 deletions

View File

@ -159,22 +159,18 @@ void csr_write_num(int csr_num, unsigned long val);
__asm__ __volatile__("wfi" ::: "memory"); \ __asm__ __volatile__("wfi" ::: "memory"); \
} while (0) } while (0)
static inline int misa_extension(char ext) /* Determine CPU extension, return non-zero support */
{ int misa_extension(char ext);
return csr_read(CSR_MISA) & (1 << (ext - 'A'));
}
static inline int misa_xlen(void) /* Get MXL field of misa, return -1 on error */
{ int misa_xlen(void);
return ((long)csr_read(CSR_MISA) < 0) ? 64 : 32;
}
static inline void misa_string(char *out, unsigned int out_sz) static inline void misa_string(char *out, unsigned int out_sz)
{ {
unsigned long i, val = csr_read(CSR_MISA); unsigned long i;
for (i = 0; i < 26; i++) { for (i = 0; i < 26; i++) {
if (val & (1 << i)) { if (misa_extension('A' + i)) {
*out = 'A' + i; *out = 'A' + i;
out++; out++;
} }

View File

@ -76,6 +76,16 @@ struct sbi_platform_operations {
/** Platform final initialization */ /** Platform final initialization */
int (*final_init)(bool cold_boot); int (*final_init)(bool cold_boot);
/** For platforms that do not implement misa, non-standard
* methods are needed to determine cpu extension.
*/
int (*misa_check_extension)(char ext);
/** For platforms that do not implement misa, non-standard
* methods are needed to get MXL field of misa.
*/
int (*misa_get_xlen)(void);
/** Get number of PMP regions for given HART */ /** Get number of PMP regions for given HART */
u32 (*pmp_region_count)(u32 hartid); u32 (*pmp_region_count)(u32 hartid);
/** /**
@ -291,6 +301,36 @@ static inline int sbi_platform_final_init(const struct sbi_platform *plat,
return 0; return 0;
} }
/**
* Check CPU extension in MISA
*
* @param plat pointer to struct sbi_platform
* @param ext shorthand letter for CPU extensions
*
* @return zero for not-supported and non-zero for supported
*/
static inline int sbi_platform_misa_extension(const struct sbi_platform *plat,
char ext)
{
if (plat && sbi_platform_ops(plat)->misa_check_extension)
return sbi_platform_ops(plat)->misa_check_extension(ext);
return 0;
}
/**
* Get MXL field of MISA
*
* @param plat pointer to struct sbi_platform
*
* @return 1/2/3 on success and error code on failure
*/
static inline int sbi_platform_misa_xlen(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->misa_get_xlen)
return sbi_platform_ops(plat)->misa_get_xlen();
return -1;
}
/** /**
* Get the number of PMP regions of a HART * Get the number of PMP regions of a HART
* *

View File

@ -10,6 +10,38 @@
#include <sbi/riscv_asm.h> #include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h> #include <sbi/riscv_encoding.h>
#include <sbi/sbi_error.h> #include <sbi/sbi_error.h>
#include <sbi/sbi_platform.h>
int misa_extension(char ext)
{
unsigned long misa = csr_read(CSR_MISA);
if (misa)
return misa & (1 << (ext - 'A'));
return sbi_platform_misa_extension(sbi_platform_thishart_ptr(), ext);
}
int misa_xlen(void)
{
long r;
if (csr_read(CSR_MISA) == 0)
return sbi_platform_misa_xlen(sbi_platform_thishart_ptr());
__asm__ __volatile__(
"csrr t0, misa\n\t"
"slti t1, t0, 0\n\t"
"slli t1, t1, 1\n\t"
"slli t0, t0, 1\n\t"
"slti t0, t0, 0\n\t"
"add %0, t0, t1"
: "=r"(r)
:
: "t0", "t1");
return r ? r : -1;
}
unsigned long csr_read_num(int csr_num) unsigned long csr_read_num(int csr_num)
{ {

View File

@ -30,10 +30,10 @@
static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid) static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
{ {
int xlen;
char str[64]; char str[64];
const struct sbi_platform *plat = sbi_platform_ptr(scratch); const struct sbi_platform *plat = sbi_platform_ptr(scratch);
misa_string(str, sizeof(str));
#ifdef OPENSBI_VERSION_GIT #ifdef OPENSBI_VERSION_GIT
sbi_printf("\nOpenSBI %s\n", OPENSBI_VERSION_GIT); sbi_printf("\nOpenSBI %s\n", OPENSBI_VERSION_GIT);
#else #else
@ -43,9 +43,18 @@ static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
sbi_printf(BANNER); sbi_printf(BANNER);
/* Determine MISA XLEN and MISA string */
xlen = misa_xlen();
if (xlen < 1) {
sbi_printf("Error %d getting MISA XLEN\n", xlen);
sbi_hart_hang();
}
xlen = 16 * (1 << xlen);
misa_string(str, sizeof(str));
/* Platform details */ /* Platform details */
sbi_printf("Platform Name : %s\n", sbi_platform_name(plat)); sbi_printf("Platform Name : %s\n", sbi_platform_name(plat));
sbi_printf("Platform HART Features : RV%d%s\n", misa_xlen(), str); sbi_printf("Platform HART Features : RV%d%s\n", xlen, str);
sbi_printf("Platform Max HARTs : %d\n", sbi_printf("Platform Max HARTs : %d\n",
sbi_platform_hart_count(plat)); sbi_platform_hart_count(plat));
sbi_printf("Current Hart : %u\n", hartid); sbi_printf("Current Hart : %u\n", hartid);