new file mode 100644
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _ASMRISCV_ISA_H_
+#define _ASMRISCV_ISA_H_
+#include <bitops.h>
+#include <asm/setup.h>
+
+/*
+ * We assume and use several extensions, such as Zicsr and Zifencei.
+ * Here we only track extensions which we don't assume and the
+ * framework may want to use. Unit tests may check for extensions
+ * by name not tracked here with cpu_has_extension_name()
+ */
+enum {
+ ISA_SSTC,
+ ISA_MAX,
+};
+_Static_assert(ISA_MAX <= __riscv_xlen, "Need to increase thread_info.isa");
+
+static inline bool cpu_has_extension(int cpu, int ext)
+{
+ return test_bit(ext, cpus[cpu].isa);
+}
+
+bool cpu_has_extension_name(int cpu, const char *ext);
+
+static inline bool has_ext(const char *ext)
+{
+ return cpu_has_extension_name(current_thread_info()->cpu, ext);
+}
+
+void isa_init(struct thread_info *info);
+
+#endif /* _ASMRISCV_ISA_H_ */
@@ -11,6 +11,7 @@ typedef void (*exception_fn)(struct pt_regs *);
struct thread_info {
int cpu;
unsigned long hartid;
+ unsigned long isa[1];
exception_fn exception_handlers[EXCEPTION_CAUSE_MAX];
};
new file mode 100644
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023, Ventana Micro Systems Inc., Andrew Jones <ajones@ventanamicro.com>
+ */
+#include <libcflat.h>
+#include <bitops.h>
+#include <devicetree.h>
+#include <string.h>
+#include <asm/isa.h>
+#include <asm/setup.h>
+
+typedef void (*isa_func_t)(const char *, int, void *);
+
+struct isa_info {
+ unsigned long hartid;
+ isa_func_t func;
+ void *data;
+};
+
+static bool isa_match(const char *ext, const char *name, int len)
+{
+ return len == strlen(ext) && !strncasecmp(name, ext, len);
+}
+
+struct isa_check {
+ const char *ext;
+ bool found;
+};
+
+static void isa_name(const char *name, int len, void *data)
+{
+ struct isa_check *check = (struct isa_check *)data;
+
+ if (isa_match(check->ext, name, len))
+ check->found = true;
+}
+
+static void isa_bit(const char *name, int len, void *data)
+{
+ struct thread_info *info = (struct thread_info *)data;
+
+ if (isa_match("sstc", name, len))
+ set_bit(ISA_SSTC, info->isa);
+}
+
+static void isa_parse(const char *isa_string, int len, struct isa_info *info)
+{
+ assert(isa_string[0] == 'r' && isa_string[1] == 'v');
+#if __riscv_xlen == 32
+ assert(isa_string[2] == '3' && isa_string[3] == '2');
+#else
+ assert(isa_string[2] == '6' && isa_string[3] == '4');
+#endif
+
+ for (int i = 4; i < len; ++i) {
+ if (isa_string[i] == '_') {
+ const char *multi = &isa_string[++i];
+ int start = i;
+
+ while (i < len - 1 && isa_string[i] != '_')
+ ++i;
+ info->func(multi, i - start, info->data);
+ if (i < len - 1)
+ --i;
+ } else {
+ info->func(&isa_string[i], 1, info->data);
+ }
+ }
+}
+
+static void isa_parse_fdt(int cpu_node, u64 hartid, void *data)
+{
+ struct isa_info *info = (struct isa_info *)data;
+ const struct fdt_property *prop;
+ int len;
+
+ if (hartid != info->hartid)
+ return;
+
+ prop = fdt_get_property(dt_fdt(), cpu_node, "riscv,isa", &len);
+ assert(prop);
+
+ isa_parse(prop->data, len, info);
+}
+
+static void isa_init_acpi(void)
+{
+ assert_msg(false, "ACPI not available");
+}
+
+void isa_init(struct thread_info *ti)
+{
+ struct isa_info info = {
+ .hartid = ti->hartid,
+ .func = isa_bit,
+ .data = ti,
+ };
+ int ret;
+
+ if (dt_available()) {
+ ret = dt_for_each_cpu_node(isa_parse_fdt, &info);
+ assert(ret == 0);
+ } else {
+ isa_init_acpi();
+ }
+}
+
+bool cpu_has_extension_name(int cpu, const char *ext)
+{
+ struct isa_info info = {
+ .hartid = cpus[cpu].hartid,
+ .func = isa_name,
+ .data = &(struct isa_check){ .ext = ext, },
+ };
+ struct isa_check *check = info.data;
+ int ret;
+
+ if (dt_available()) {
+ ret = dt_for_each_cpu_node(isa_parse_fdt, &info);
+ assert(ret == 0);
+ } else {
+ assert_msg(false, "ACPI not available");
+ }
+
+ return check->found;
+}
@@ -4,6 +4,7 @@
*/
#include <libcflat.h>
#include <asm/csr.h>
+#include <asm/isa.h>
#include <asm/processor.h>
#include <asm/setup.h>
@@ -58,5 +59,6 @@ void thread_info_init(void)
unsigned long hartid = csr_read(CSR_SSCRATCH);
int cpu = hartid_to_cpu(hartid);
+ isa_init(&cpus[cpu]);
csr_write(CSR_SSCRATCH, &cpus[cpu]);
}
@@ -30,6 +30,7 @@ cflatobjs += lib/on-cpus.o
cflatobjs += lib/vmalloc.o
cflatobjs += lib/riscv/bitops.o
cflatobjs += lib/riscv/io.o
+cflatobjs += lib/riscv/isa.o
cflatobjs += lib/riscv/mmu.o
cflatobjs += lib/riscv/processor.o
cflatobjs += lib/riscv/sbi.o