aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Léger <cleger@rivosinc.com>2024-06-19 11:42:39 +0200
committerAnup Patel <anup@brainfault.org>2024-06-19 18:09:22 +0530
commitaa5a8593696b39059832d12455c31dcfeb4d9259 (patch)
tree3b73a421929fb9c74b46805e3688341135056731
parent53844c98d082cbba29a6e568196add6de95e858f (diff)
downloadopensbi-aa5a8593696b39059832d12455c31dcfeb4d9259.zip
opensbi-aa5a8593696b39059832d12455c31dcfeb4d9259.tar.gz
opensbi-aa5a8593696b39059832d12455c31dcfeb4d9259.tar.bz2
lib: sbi: add support for firmware features extension
This extension allows the software running in supervisor mode to control the behavior of various features of the SBI [1]. Implement the support for such extension. Link: https://lists.riscv.org/g/tech-prs/message/924 [1] Signed-off-by: Clément Léger <cleger@rivosinc.com> Reviewed-by: Anup Patel <anup@brainfault.org>
-rw-r--r--include/sbi/sbi_ecall_interface.h27
-rw-r--r--include/sbi/sbi_fwft.h23
-rw-r--r--lib/sbi/objects.mk1
-rw-r--r--lib/sbi/sbi_fwft.c178
-rw-r--r--lib/sbi/sbi_init.c11
5 files changed, 240 insertions, 0 deletions
diff --git a/include/sbi/sbi_ecall_interface.h b/include/sbi/sbi_ecall_interface.h
index 2600b66..e9a8167 100644
--- a/include/sbi/sbi_ecall_interface.h
+++ b/include/sbi/sbi_ecall_interface.h
@@ -34,6 +34,7 @@
#define SBI_EXT_CPPC 0x43505043
#define SBI_EXT_DBTR 0x44425452
#define SBI_EXT_SSE 0x535345
+#define SBI_EXT_FWFT 0x46574654
/* SBI function IDs for BASE extension*/
#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
@@ -117,6 +118,32 @@
#define SBI_EXT_DBTR_TRIGGER_ENABLE 0x6
#define SBI_EXT_DBTR_TRIGGER_DISABLE 0x7
+/* SBI function IDs for FW feature extension */
+#define SBI_EXT_FWFT_SET 0x0
+#define SBI_EXT_FWFT_GET 0x1
+
+enum sbi_fwft_feature_t {
+ SBI_FWFT_MISALIGNED_EXC_DELEG = 0x0,
+ SBI_FWFT_LANDING_PAD = 0x1,
+ SBI_FWFT_SHADOW_STACK = 0x2,
+ SBI_FWFT_DOUBLE_TRAP = 0x3,
+ SBI_FWFT_PTE_AD_HW_UPDATING = 0x4,
+ SBI_FWFT_LOCAL_RESERVED_START = 0x5,
+ SBI_FWFT_LOCAL_RESERVED_END = 0x3fffffff,
+ SBI_FWFT_LOCAL_PLATFORM_START = 0x40000000,
+ SBI_FWFT_LOCAL_PLATFORM_END = 0x7fffffff,
+
+ SBI_FWFT_GLOBAL_RESERVED_START = 0x80000000,
+ SBI_FWFT_GLOBAL_RESERVED_END = 0xbfffffff,
+ SBI_FWFT_GLOBAL_PLATFORM_START = 0xc0000000,
+ SBI_FWFT_GLOBAL_PLATFORM_END = 0xffffffff,
+};
+
+#define SBI_FWFT_GLOBAL_FEATURE_BIT (1 << 31)
+#define SBI_FWFT_PLATFORM_FEATURE_BIT (1 << 30)
+
+#define SBI_FWFT_SET_FLAG_LOCK (1 << 0)
+
/** General pmu event codes specified in SBI PMU extension */
enum sbi_pmu_hw_generic_events_t {
SBI_PMU_HW_NO_EVENT = 0,
diff --git a/include/sbi/sbi_fwft.h b/include/sbi/sbi_fwft.h
new file mode 100644
index 0000000..2148820
--- /dev/null
+++ b/include/sbi/sbi_fwft.h
@@ -0,0 +1,23 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Rivos Inc.
+ *
+ * Authors:
+ * Clément Léger <cleger@rivosinc.com>
+ */
+
+#ifndef __SBI_FW_FEATURE_H__
+#define __SBI_FW_FEATURE_H__
+
+#include <sbi/sbi_ecall_interface.h>
+
+struct sbi_scratch;
+
+int sbi_fwft_set(enum sbi_fwft_feature_t feature, unsigned long value,
+ unsigned long flags);
+int sbi_fwft_get(enum sbi_fwft_feature_t feature, unsigned long *out_val);
+
+int sbi_fwft_init(struct sbi_scratch *scratch, bool cold_boot);
+
+#endif
diff --git a/lib/sbi/objects.mk b/lib/sbi/objects.mk
index b1c4a50..221e72c 100644
--- a/lib/sbi/objects.mk
+++ b/lib/sbi/objects.mk
@@ -65,6 +65,7 @@ libsbi-objs-y += sbi_domain_context.o
libsbi-objs-y += sbi_domain.o
libsbi-objs-y += sbi_emulate_csr.o
libsbi-objs-y += sbi_fifo.o
+libsbi-objs-y += sbi_fwft.o
libsbi-objs-y += sbi_hart.o
libsbi-objs-y += sbi_heap.o
libsbi-objs-y += sbi_math.o
diff --git a/lib/sbi/sbi_fwft.c b/lib/sbi/sbi_fwft.c
new file mode 100644
index 0000000..b302b5d
--- /dev/null
+++ b/lib/sbi/sbi_fwft.c
@@ -0,0 +1,178 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Rivos Inc.
+ *
+ * Authors:
+ * Clément Léger <cleger@rivosinc.com>
+ */
+
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_bitmap.h>
+#include <sbi/sbi_ecall_interface.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_heap.h>
+#include <sbi/sbi_scratch.h>
+#include <sbi/sbi_string.h>
+#include <sbi/sbi_types.h>
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+
+/** Offset of pointer to FWFT HART state in scratch space */
+static unsigned long fwft_ptr_offset;
+
+#define fwft_get_hart_state_ptr(__scratch) \
+ sbi_scratch_read_type((__scratch), void *, fwft_ptr_offset)
+
+#define fwft_thishart_state_ptr() \
+ fwft_get_hart_state_ptr(sbi_scratch_thishart_ptr())
+
+#define fwft_set_hart_state_ptr(__scratch, __phs) \
+ sbi_scratch_write_type((__scratch), void *, fwft_ptr_offset, (__phs))
+
+struct fwft_config;
+
+struct fwft_feature {
+ enum sbi_fwft_feature_t id;
+ int (*supported)(struct fwft_config *conf);
+ int (*set)(struct fwft_config *conf, unsigned long value);
+ int (*get)(struct fwft_config *conf, unsigned long *value);
+};
+
+struct fwft_config {
+ const struct fwft_feature *feature;
+ unsigned long flags;
+};
+
+struct fwft_hart_state {
+ unsigned int config_count;
+ struct fwft_config configs[];
+};
+
+static const unsigned long fwft_defined_features[] = {
+ SBI_FWFT_MISALIGNED_EXC_DELEG,
+ SBI_FWFT_LANDING_PAD,
+ SBI_FWFT_SHADOW_STACK,
+ SBI_FWFT_DOUBLE_TRAP,
+ SBI_FWFT_PTE_AD_HW_UPDATING,
+};
+
+static bool fwft_is_defined_feature(enum sbi_fwft_feature_t feature)
+{
+ int i;
+
+ for (i = 0; i < array_size(fwft_defined_features); i++) {
+ if (fwft_defined_features[i] == feature)
+ return true;
+ }
+
+ return false;
+}
+
+static struct fwft_config* get_feature_config(enum sbi_fwft_feature_t feature)
+{
+ int i;
+ struct fwft_hart_state *fhs = fwft_thishart_state_ptr();
+
+ if (feature & SBI_FWFT_GLOBAL_FEATURE_BIT)
+ return NULL;
+
+ for (i = 0; i < fhs->config_count; i++){
+ if (feature == fhs->configs[i].feature->id)
+ return &fhs->configs[i];
+ }
+
+ return NULL;
+}
+
+static int fwft_get_feature(enum sbi_fwft_feature_t feature,
+ struct fwft_config **conf)
+{
+ int ret;
+ struct fwft_config *tconf;
+
+ tconf = get_feature_config(feature);
+ if (!tconf) {
+ if (fwft_is_defined_feature(feature))
+ return SBI_ENOTSUPP;
+
+ return SBI_EDENIED;
+ }
+
+ if (tconf->feature->supported) {
+ ret = tconf->feature->supported(tconf);
+ if (ret)
+ return ret;
+ }
+ *conf = tconf;
+
+ return SBI_SUCCESS;
+}
+
+int sbi_fwft_set(enum sbi_fwft_feature_t feature, unsigned long value,
+ unsigned long flags)
+{
+ int ret;
+ struct fwft_config *conf;
+
+ ret = fwft_get_feature(feature, &conf);
+ if (ret)
+ return ret;
+
+ if ((flags & ~SBI_FWFT_SET_FLAG_LOCK) != 0)
+ return SBI_ERR_INVALID_PARAM;
+
+ if (conf->flags & SBI_FWFT_SET_FLAG_LOCK)
+ return SBI_EDENIED;
+
+ ret = conf->feature->set(conf, value);
+ if (ret)
+ return ret;
+
+ conf->flags = flags;
+
+ return SBI_OK;
+}
+
+int sbi_fwft_get(enum sbi_fwft_feature_t feature, unsigned long *out_val)
+{
+ int ret;
+ struct fwft_config *conf;
+
+ ret = fwft_get_feature(feature, &conf);
+ if (ret)
+ return ret;
+
+ return conf->feature->get(conf, out_val);
+}
+
+static const struct fwft_feature features[] = {};
+
+int sbi_fwft_init(struct sbi_scratch *scratch, bool cold_boot)
+{
+ int i;
+ struct fwft_hart_state *fhs;
+
+ if (cold_boot) {
+ fwft_ptr_offset = sbi_scratch_alloc_type_offset(void *);
+ if (!fwft_ptr_offset)
+ return SBI_ENOMEM;
+ }
+
+ fhs = fwft_get_hart_state_ptr(scratch);
+ if (!fhs) {
+ fhs = sbi_zalloc(sizeof(fhs) + array_size(features) * sizeof(struct fwft_config));
+ if (!fhs)
+ return SBI_ENOMEM;
+
+ fhs->config_count = array_size(features);
+ for (i = 0; i < array_size(features); i++)
+ fhs->configs[i].feature = &features[i];
+
+ fwft_set_hart_state_ptr(scratch, fhs);
+ }
+
+ return 0;
+}
diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c
index 389172a..0f9e14c 100644
--- a/lib/sbi/sbi_init.c
+++ b/lib/sbi/sbi_init.c
@@ -14,6 +14,7 @@
#include <sbi/sbi_cppc.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_ecall.h>
+#include <sbi/sbi_fwft.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_heap.h>
@@ -308,6 +309,12 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_hang();
}
+ rc = sbi_fwft_init(scratch, true);
+ if (rc) {
+ sbi_printf("%s: fwft init failed (error %d)\n", __func__, rc);
+ sbi_hart_hang();
+ }
+
/*
* Note: Finalize domains after HSM initialization so that we
* can startup non-root domains.
@@ -423,6 +430,10 @@ static void __noreturn init_warm_startup(struct sbi_scratch *scratch,
if (rc)
sbi_hart_hang();
+ rc = sbi_fwft_init(scratch, false);
+ if (rc)
+ sbi_hart_hang();
+
rc = sbi_platform_final_init(plat, false);
if (rc)
sbi_hart_hang();