mirror of
https://github.com/riscv-software-src/opensbi.git
synced 2025-08-24 23:41:23 +01:00
Compare commits
344 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a98258d0b5 | ||
![]() |
2314101989 | ||
![]() |
9bd5f8f17d | ||
![]() |
db56ef367c | ||
![]() |
637b348224 | ||
![]() |
d5725c24c6 | ||
![]() |
518e85cccb | ||
![]() |
6966ad0abe | ||
![]() |
e2c3f01af4 | ||
![]() |
32f87e5a86 | ||
![]() |
980290651f | ||
![]() |
106b888e20 | ||
![]() |
79bfd67f9a | ||
![]() |
1b8c0128f1 | ||
![]() |
51f0e4a053 | ||
![]() |
72019ee202 | ||
![]() |
4e3876d5be | ||
![]() |
c6c65ee861 | ||
![]() |
86ec5341e4 | ||
![]() |
4ce6b7a82a | ||
![]() |
64f140830d | ||
![]() |
30b60401e1 | ||
![]() |
a63f05f3de | ||
![]() |
6956e83a94 | ||
![]() |
569dd64b72 | ||
![]() |
a9a9751185 | ||
![]() |
d30bb68448 | ||
![]() |
2c685c214f | ||
![]() |
446a9c6d1e | ||
![]() |
73d6ef3b29 | ||
![]() |
89ba63493c | ||
![]() |
a38bea9341 | ||
![]() |
2966510eed | ||
![]() |
63b0f5f71a | ||
![]() |
3a8fc81357 | ||
![]() |
3aa1036f91 | ||
![]() |
49841832b8 | ||
![]() |
28b4052849 | ||
![]() |
38a4b54cdc | ||
![]() |
36833abfbb | ||
![]() |
22c4334f5c | ||
![]() |
1f235ec47f | ||
![]() |
ec0d2a7d7d | ||
![]() |
4938024420 | ||
![]() |
b2df751acf | ||
![]() |
6a053f6e6c | ||
![]() |
79d0fadb06 | ||
![]() |
13ca20d8df | ||
![]() |
aef9a60d52 | ||
![]() |
63a513edec | ||
![]() |
7be75f519f | ||
![]() |
c2286b6f04 | ||
![]() |
dfd9dd67dc | ||
![]() |
b4efa70d12 | ||
![]() |
433bac7242 | ||
![]() |
dc38929dfb | ||
![]() |
5338679ff0 | ||
![]() |
7993ca2c8e | ||
![]() |
d626037258 | ||
![]() |
65c06b026d | ||
![]() |
13717a8e53 | ||
![]() |
4f18c6e550 | ||
![]() |
2ba7087b09 | ||
![]() |
1f21b99ff0 | ||
![]() |
f1aa9e54e0 | ||
![]() |
4d063538f0 | ||
![]() |
7cc6fa4d8a | ||
![]() |
76a89403c8 | ||
![]() |
75322a634b | ||
![]() |
76f0f81407 | ||
![]() |
8ff2b94ea1 | ||
![]() |
1ac794cb61 | ||
![]() |
f0eb503db4 | ||
![]() |
44dd7be3b2 | ||
![]() |
19e966b862 | ||
![]() |
66185b3ec9 | ||
![]() |
dd33b9e0a1 | ||
![]() |
a39cd6fe4c | ||
![]() |
e3ad7c13a0 | ||
![]() |
243b0d0c0c | ||
![]() |
0a0093b0bc | ||
![]() |
01a8c8eebb | ||
![]() |
e6c1345f89 | ||
![]() |
5bdf022d07 | ||
![]() |
3a326af9be | ||
![]() |
4781545512 | ||
![]() |
6585fabbcc | ||
![]() |
a9eac67ad0 | ||
![]() |
1bb00ab3ae | ||
![]() |
9f1b72ce66 | ||
![]() |
66d018499c | ||
![]() |
615587c336 | ||
![]() |
6c7922e23b | ||
![]() |
f281de885e | ||
![]() |
e5a7f556ce | ||
![]() |
648507a867 | ||
![]() |
0a28ea54dc | ||
![]() |
ec0d80f5b4 | ||
![]() |
9e52a45f4b | ||
![]() |
54b2779cfe | ||
![]() |
dd0f21c560 | ||
![]() |
5b6957eed7 | ||
![]() |
7b211ff924 | ||
![]() |
40b221baff | ||
![]() |
7487116b41 | ||
![]() |
fe37d7da29 | ||
![]() |
5a7bd0c88d | ||
![]() |
d11c79cd97 | ||
![]() |
cb78a48231 | ||
![]() |
626467cfd9 | ||
![]() |
1de66d170e | ||
![]() |
160c88535f | ||
![]() |
550ba88db1 | ||
![]() |
4d93586bfa | ||
![]() |
4c374511fd | ||
![]() |
040e4e2ec2 | ||
![]() |
d1d6560a87 | ||
![]() |
fb84879e66 | ||
![]() |
ed265b4498 | ||
![]() |
5968894842 | ||
![]() |
9a74a64ae0 | ||
![]() |
a0c88ddb31 | ||
![]() |
315a87710f | ||
![]() |
c51f02cf14 | ||
![]() |
75eec9dd3f | ||
![]() |
814f38dc1d | ||
![]() |
db187d616c | ||
![]() |
680b09872d | ||
![]() |
c9f60fc6b7 | ||
![]() |
bd6ef02d47 | ||
![]() |
209134d8f9 | ||
![]() |
3ebfe0ec5d | ||
![]() |
19bd531a15 | ||
![]() |
e23d3ba936 | ||
![]() |
87a7ef7659 | ||
![]() |
3f8d754c2c | ||
![]() |
db6a2b5c68 | ||
![]() |
3f1c847d1f | ||
![]() |
dd9439fbac | ||
![]() |
1071f05663 | ||
![]() |
6f9bb83c1f | ||
![]() |
c9a526877c | ||
![]() |
8135520e6f | ||
![]() |
e846ce1681 | ||
![]() |
6af55769eb | ||
![]() |
666be6d62b | ||
![]() |
fcb1dedb2d | ||
![]() |
dce88467af | ||
![]() |
5fbcd625bc | ||
![]() |
327ba36211 | ||
![]() |
72a0628c7e | ||
![]() |
2343efd040 | ||
![]() |
9275ed3949 | ||
![]() |
9aabba2665 | ||
![]() |
823345ecae | ||
![]() |
16e7071f6d | ||
![]() |
eeae3d9582 | ||
![]() |
f92147c2b2 | ||
![]() |
baac7e066d | ||
![]() |
0cfe49ad63 | ||
![]() |
4b2f594b85 | ||
![]() |
ffdc858f72 | ||
![]() |
86d37bbd7d | ||
![]() |
757bb44e6e | ||
![]() |
eede1aa7c7 | ||
![]() |
9aad831e87 | ||
![]() |
466fecb957 | ||
![]() |
61f776861f | ||
![]() |
2db381fc74 | ||
![]() |
44ce5b99e9 | ||
![]() |
2b945fc180 | ||
![]() |
71d2b837c4 | ||
![]() |
d96316481d | ||
![]() |
a4a6a81b7d | ||
![]() |
d6d7e18d1d | ||
![]() |
c741abcd40 | ||
![]() |
3226bd93ce | ||
![]() |
078686d75c | ||
![]() |
650c0e525c | ||
![]() |
6e87507db6 | ||
![]() |
2abc55bb39 | ||
![]() |
678c3c3655 | ||
![]() |
4a603eb6dc | ||
![]() |
a148996a7f | ||
![]() |
00d332bbe7 | ||
![]() |
8c83fb2fc8 | ||
e1a5b737ef | |||
![]() |
82ae8e8fe2 | ||
![]() |
6704216732 | ||
![]() |
e3f69fc1e9 | ||
![]() |
5b4824082f | ||
![]() |
b677a9b8d6 | ||
![]() |
f64f4b92e4 | ||
![]() |
ac5e821d50 | ||
![]() |
f8b3bb826d | ||
![]() |
393624377a | ||
![]() |
c3b3b8f43b | ||
![]() |
3e7d666d7c | ||
![]() |
66fb729a1e | ||
![]() |
24c3082ea4 | ||
![]() |
bc874e34ce | ||
![]() |
c66543d049 | ||
![]() |
0b414532c4 | ||
![]() |
27a5c7f3c8 | ||
![]() |
f8ce996d90 | ||
![]() |
82fd42fcce | ||
![]() |
a8ef0b5d53 | ||
![]() |
44d1296018 | ||
![]() |
fdfb5332f3 | ||
![]() |
892e87998c | ||
![]() |
48b06ad16e | ||
![]() |
29bb2a6835 | ||
![]() |
c03c8a1e2c | ||
![]() |
a062200b89 | ||
![]() |
c2f23cc6ed | ||
![]() |
c2bfa2bff3 | ||
![]() |
1a8ca08cc0 | ||
![]() |
897b8fbdd9 | ||
![]() |
179eddeb9c | ||
![]() |
d6fa7f95bb | ||
![]() |
9a717ec12e | ||
![]() |
6d0b4c520d | ||
![]() |
5ff1ab0ed8 | ||
![]() |
2c2bbe7374 | ||
![]() |
d79173b4b7 | ||
![]() |
ac1c229b61 | ||
![]() |
85647a1a76 | ||
![]() |
021b9e7c76 | ||
![]() |
43ac621ecb | ||
![]() |
161b348e7e | ||
![]() |
766850222a | ||
![]() |
37923c4a66 | ||
![]() |
0a411bf717 | ||
![]() |
84cd4fc913 | ||
![]() |
817d50d0d4 | ||
![]() |
5f762d14f0 | ||
![]() |
a8b4b83b7f | ||
![]() |
da9b76b957 | ||
![]() |
3d2aaac69a | ||
![]() |
046cc16e8b | ||
![]() |
0492c5d92b | ||
![]() |
30cdf00655 | ||
![]() |
a73d45ccac | ||
![]() |
7daccaeebd | ||
![]() |
6ffe1bed09 | ||
![]() |
f95dd39ab6 | ||
![]() |
adf8b73675 | ||
![]() |
b28b8ac0d2 | ||
![]() |
e340bbf7b5 | ||
![]() |
049ad0b387 | ||
![]() |
a67fd68cbf | ||
![]() |
73c19e69f3 | ||
![]() |
15ed1e7452 | ||
![]() |
b0c9787435 | ||
![]() |
2aa43a13cd | ||
![]() |
1993182f03 | ||
![]() |
b325f6baef | ||
![]() |
6469ed101c | ||
![]() |
55e191e3b0 | ||
![]() |
c3e406f160 | ||
![]() |
e746673a79 | ||
![]() |
c0849cd731 | ||
![]() |
46a90d90e7 | ||
![]() |
fc6bd90457 | ||
![]() |
9beb57362f | ||
![]() |
c7d1b12199 | ||
![]() |
86a31f5437 | ||
![]() |
331ff6a162 | ||
![]() |
9407202532 | ||
![]() |
9777aeef41 | ||
![]() |
109266397a | ||
![]() |
aa0ed1d733 | ||
![]() |
b8732feaf7 | ||
![]() |
7219477f7b | ||
![]() |
2be424bd28 | ||
![]() |
086dbdfc92 | ||
![]() |
4370f18f34 | ||
![]() |
6590a7dab9 | ||
![]() |
bd732ae612 | ||
![]() |
dc40042322 | ||
![]() |
813f7f4c25 | ||
![]() |
ab14f94a8c | ||
![]() |
c96cc03fcc | ||
![]() |
75f903dd78 | ||
![]() |
0e1322bacb | ||
![]() |
b1d8c988bc | ||
![]() |
838657c052 | ||
![]() |
215421ca61 | ||
![]() |
7a13beb213 | ||
![]() |
18897aaf5d | ||
![]() |
f728a0be42 | ||
![]() |
98f4a20899 | ||
![]() |
dd8ef28b27 | ||
![]() |
be92da280d | ||
![]() |
30f09fbfd1 | ||
![]() |
0790be0f2c | ||
![]() |
848ed4f644 | ||
![]() |
26aec6afed | ||
![]() |
3d335bc54b | ||
![]() |
8925e3865c | ||
![]() |
e561c63036 | ||
![]() |
2c7bab76a2 | ||
![]() |
1e9f88889f | ||
![]() |
7d4420bd69 | ||
![]() |
a14e7ee82c | ||
![]() |
bbeb8e619d | ||
![]() |
1a5614e971 | ||
![]() |
0089897d41 | ||
![]() |
1ed9eb255d | ||
![]() |
0a482e2edb | ||
![]() |
190e3f4bd9 | ||
![]() |
8853758268 | ||
![]() |
98ee15ca3a | ||
![]() |
f2e82c3d79 | ||
![]() |
144acef684 | ||
![]() |
9dfe720579 | ||
![]() |
fca8c3be01 | ||
![]() |
6ed2bc154f | ||
![]() |
7b7690ed9c | ||
![]() |
6bd1512024 | ||
![]() |
2e5cc9051b | ||
![]() |
ffa6c5f457 | ||
![]() |
3cbb419def | ||
![]() |
a2a7763ac7 | ||
![]() |
75229705a0 | ||
![]() |
897a97a6af | ||
![]() |
f6e13e0dd3 | ||
![]() |
a88e424f6c | ||
![]() |
2e0f3ac758 | ||
![]() |
6c24193293 | ||
![]() |
5e4021a2f5 | ||
![]() |
6ddf71e6e9 | ||
![]() |
3f738f5897 | ||
![]() |
88c87f0af4 | ||
![]() |
dbff3e9f12 | ||
![]() |
b1318e578b | ||
![]() |
446b6f30a4 | ||
![]() |
c1b9dd3ab5 | ||
![]() |
0f18b3fe0a | ||
![]() |
85546a5477 | ||
![]() |
c90009aa20 | ||
![]() |
bf2ee7bcdc | ||
![]() |
e3f743339a | ||
![]() |
e7456399e4 |
114
Makefile
114
Makefile
@@ -12,29 +12,37 @@
|
||||
# o Do not print "Entering directory ...";
|
||||
MAKEFLAGS += -r --no-print-directory
|
||||
|
||||
# Readlink -f requires GNU readlink
|
||||
ifeq ($(shell uname -s),Darwin)
|
||||
READLINK ?= greadlink
|
||||
else
|
||||
READLINK ?= readlink
|
||||
endif
|
||||
|
||||
# Find out source, build, and install directories
|
||||
src_dir=$(CURDIR)
|
||||
ifdef O
|
||||
build_dir=$(shell readlink -f $(O))
|
||||
build_dir=$(shell $(READLINK) -f $(O))
|
||||
else
|
||||
build_dir=$(CURDIR)/build
|
||||
endif
|
||||
ifeq ($(build_dir),$(CURDIR))
|
||||
$(error Build directory is same as source directory.)
|
||||
endif
|
||||
install_root_dir_default=$(CURDIR)/install
|
||||
ifdef I
|
||||
install_dir=$(shell readlink -f $(I))
|
||||
install_root_dir=$(shell $(READLINK) -f $(I))
|
||||
else
|
||||
install_dir=$(CURDIR)/install
|
||||
install_root_dir=$(install_root_dir_default)/usr
|
||||
endif
|
||||
ifeq ($(install_dir),$(CURDIR))
|
||||
$(error Install directory is same as source directory.)
|
||||
ifeq ($(install_root_dir),$(CURDIR))
|
||||
$(error Install root directory is same as source directory.)
|
||||
endif
|
||||
ifeq ($(install_dir),$(build_dir))
|
||||
$(error Install directory is same as build directory.)
|
||||
ifeq ($(install_root_dir),$(build_dir))
|
||||
$(error Install root directory is same as build directory.)
|
||||
endif
|
||||
ifdef PLATFORM_DIR
|
||||
platform_dir_path=$(shell readlink -f $(PLATFORM_DIR))
|
||||
platform_dir_path=$(shell $(READLINK) -f $(PLATFORM_DIR))
|
||||
ifdef PLATFORM
|
||||
platform_parent_dir=$(platform_dir_path)
|
||||
else
|
||||
@@ -65,6 +73,7 @@ export firmware_dir=$(CURDIR)/firmware
|
||||
# Find library version
|
||||
OPENSBI_VERSION_MAJOR=`grep "define OPENSBI_VERSION_MAJOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MAJOR.*\([0-9][0-9]*\)/\1/'`
|
||||
OPENSBI_VERSION_MINOR=`grep "define OPENSBI_VERSION_MINOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MINOR.*\([0-9][0-9]*\)/\1/'`
|
||||
OPENSBI_VERSION_GIT=$(shell if [ -d $(src_dir)/.git ]; then git describe 2> /dev/null; fi)
|
||||
|
||||
# Setup compilation commands
|
||||
ifdef CROSS_COMPILE
|
||||
@@ -121,7 +130,6 @@ libsbi-objs-path-y=$(foreach obj,$(libsbi-objs-y),$(build_dir)/lib/sbi/$(obj))
|
||||
libsbiutils-objs-path-y=$(foreach obj,$(libsbiutils-objs-y),$(build_dir)/lib/utils/$(obj))
|
||||
ifdef PLATFORM
|
||||
platform-objs-path-y=$(foreach obj,$(platform-objs-y),$(platform_build_dir)/$(obj))
|
||||
platform-dtb-path-y=$(foreach obj,$(platform-dtb-y),$(platform_build_dir)/$(obj))
|
||||
firmware-bins-path-y=$(foreach bin,$(firmware-bins-y),$(platform_build_dir)/firmware/$(bin))
|
||||
endif
|
||||
firmware-elfs-path-y=$(firmware-bins-path-y:.bin=.elf)
|
||||
@@ -148,14 +156,44 @@ ifndef PLATFORM_RISCV_CODE_MODEL
|
||||
PLATFORM_RISCV_CODE_MODEL = medany
|
||||
endif
|
||||
|
||||
# Setup install directories
|
||||
ifdef INSTALL_INCLUDE_PATH
|
||||
install_include_path=$(INSTALL_INCLUDE_PATH)
|
||||
else
|
||||
install_include_path=include
|
||||
endif
|
||||
ifdef INSTALL_LIB_PATH
|
||||
install_lib_path=$(INSTALL_LIB_PATH)
|
||||
else
|
||||
ifneq ($(origin INSTALL_LIB_SUBDIR), undefined)
|
||||
install_lib_subdir=$(INSTALL_LIB_SUBDIR)
|
||||
else
|
||||
install_lib_subdir=$(PLATFORM_RISCV_ABI)
|
||||
endif
|
||||
install_lib_path=lib$(subst 32,,$(PLATFORM_RISCV_XLEN))/$(install_lib_subdir)
|
||||
endif
|
||||
ifdef INSTALL_FIRMWARE_PATH
|
||||
install_firmware_path=$(INSTALL_FIRMWARE_PATH)
|
||||
else
|
||||
install_firmware_path=share/opensbi/$(PLATFORM_RISCV_ABI)
|
||||
endif
|
||||
ifdef INSTALL_DOCS_PATH
|
||||
install_docs_path=$(INSTALL_DOCS_PATH)
|
||||
else
|
||||
install_docs_path=share/opensbi/docs
|
||||
endif
|
||||
|
||||
# Setup compilation commands flags
|
||||
GENFLAGS = -I$(platform_src_dir)/include
|
||||
GENFLAGS += -I$(include_dir)
|
||||
ifneq ($(OPENSBI_VERSION_GIT),)
|
||||
GENFLAGS += -DOPENSBI_VERSION_GIT="\"$(OPENSBI_VERSION_GIT)\""
|
||||
endif
|
||||
GENFLAGS += $(libsbiutils-genflags-y)
|
||||
GENFLAGS += $(platform-genflags-y)
|
||||
GENFLAGS += $(firmware-genflags-y)
|
||||
|
||||
CFLAGS = -g -Wall -Werror -nostdlib -fno-strict-aliasing -O2
|
||||
CFLAGS = -g -Wall -Werror -ffreestanding -nostdlib -fno-strict-aliasing -O2
|
||||
CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
|
||||
CFLAGS += -mno-save-restore -mstrict-align
|
||||
CFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
|
||||
@@ -188,7 +226,7 @@ MERGEFLAGS += -r
|
||||
MERGEFLAGS += -b elf$(PLATFORM_RISCV_XLEN)-littleriscv
|
||||
MERGEFLAGS += -m elf$(PLATFORM_RISCV_XLEN)lriscv
|
||||
|
||||
DTCFLAGS = -O dtb
|
||||
DTSCPPFLAGS = $(CPPFLAGS) -nostdinc -nostdlib -fno-builtin -D__DTS__ -x assembler-with-cpp
|
||||
|
||||
# Setup functions for compilation
|
||||
define dynamic_flags
|
||||
@@ -204,12 +242,12 @@ copy_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
||||
echo " COPY $(subst $(build_dir)/,,$(1))"; \
|
||||
cp -f $(2) $(1)
|
||||
inst_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
||||
echo " INSTALL $(subst $(install_dir)/,,$(1))"; \
|
||||
echo " INSTALL $(subst $(install_root_dir)/,,$(1))"; \
|
||||
cp -f $(2) $(1)
|
||||
inst_file_list = $(CMD_PREFIX)if [ ! -z "$(4)" ]; then \
|
||||
mkdir -p $(1)/$(3); \
|
||||
for file in $(4) ; do \
|
||||
rel_file=`echo $$file | sed -e 's@$(2)/$(3)/@@'`; \
|
||||
rel_file=`echo $$file | sed -e 's@$(2)/$(subst $(install_firmware_path),platform,$(3))@@'`; \
|
||||
dest_file=$(1)"/"$(3)"/"`echo $$rel_file`; \
|
||||
dest_dir=`dirname $$dest_file`; \
|
||||
echo " INSTALL "$(3)"/"`echo $$rel_file`; \
|
||||
@@ -218,7 +256,7 @@ inst_file_list = $(CMD_PREFIX)if [ ! -z "$(4)" ]; then \
|
||||
done \
|
||||
fi
|
||||
inst_header_dir = $(CMD_PREFIX)mkdir -p $(1); \
|
||||
echo " INSTALL $(subst $(install_dir)/,,$(1))"; \
|
||||
echo " INSTALL $(subst $(install_root_dir)/,,$(1))"; \
|
||||
cp -rf $(2) $(1)
|
||||
compile_cpp = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
||||
echo " CPP $(subst $(build_dir)/,,$(1))"; \
|
||||
@@ -250,13 +288,18 @@ compile_objcopy = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
||||
$(OBJCOPY) -S -O binary $(2) $(1)
|
||||
compile_dts = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
||||
echo " DTC $(subst $(build_dir)/,,$(1))"; \
|
||||
$(DTC) $(DTCFLAGS) -o $(1) $(2)
|
||||
$(CPP) $(DTSCPPFLAGS) $(2) | $(DTC) -O dtb -i `dirname $(2)` -o $(1)
|
||||
compile_d2c = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
||||
echo " D2C $(subst $(build_dir)/,,$(1))"; \
|
||||
$(src_dir)/scripts/d2c.sh -i $(4) -a $(3) -p $(2) > $(1)
|
||||
compile_gen_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
||||
echo " GEN-DEP $(subst $(build_dir)/,,$(1))"; \
|
||||
echo "$(1:.dep=$(2)): $(3)" >> $(1)
|
||||
|
||||
targets-y = $(build_dir)/lib/libsbi.a
|
||||
targets-y += $(build_dir)/lib/libsbiutils.a
|
||||
ifdef PLATFORM
|
||||
targets-y += $(platform_build_dir)/lib/libplatsbi.a
|
||||
targets-y += $(platform-dtb-path-y)
|
||||
endif
|
||||
targets-y += $(firmware-bins-path-y)
|
||||
|
||||
@@ -303,12 +346,26 @@ $(platform_build_dir)/%.dep: $(platform_src_dir)/%.c
|
||||
$(platform_build_dir)/%.o: $(platform_src_dir)/%.c
|
||||
$(call compile_cc,$@,$<)
|
||||
|
||||
$(platform_build_dir)/%.o: $(platform_build_dir)/%.c
|
||||
$(call compile_cc,$@,$<)
|
||||
|
||||
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.S
|
||||
$(call compile_as_dep,$@,$<)
|
||||
|
||||
$(platform_build_dir)/%.o: $(platform_src_dir)/%.S
|
||||
$(call compile_as,$@,$<)
|
||||
|
||||
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.dts
|
||||
$(call compile_gen_dep,$@,.dtb,$<)
|
||||
$(call compile_gen_dep,$@,.c,$(@:.dep=.dtb))
|
||||
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
|
||||
|
||||
$(platform_build_dir)/%.c: $(platform_build_dir)/%.dtb
|
||||
$(call compile_d2c,$@,$(platform-varprefix-$(subst .dtb,.o,$(subst /,-,$(subst $(platform_build_dir)/,,$<)))),16,$<)
|
||||
|
||||
$(platform_build_dir)/%.dtb: $(platform_src_dir)/%.dts
|
||||
$(call compile_dts,$@,$<)
|
||||
|
||||
$(platform_build_dir)/%.dep: $(src_dir)/%.c
|
||||
$(call compile_cc_dep,$@,$<)
|
||||
|
||||
@@ -321,9 +378,6 @@ $(platform_build_dir)/%.dep: $(src_dir)/%.S
|
||||
$(platform_build_dir)/%.o: $(src_dir)/%.S
|
||||
$(call compile_as,$@,$<)
|
||||
|
||||
$(build_dir)/%.dtb: $(src_dir)/%.dts
|
||||
$(call compile_dts,$@,$<)
|
||||
|
||||
# Rule for "make docs"
|
||||
$(build_dir)/docs/latex/refman.pdf: $(build_dir)/docs/latex/refman.tex
|
||||
$(CMD_PREFIX)mkdir -p $(build_dir)/docs
|
||||
@@ -374,26 +428,26 @@ install: $(install_targets-y)
|
||||
|
||||
.PHONY: install_libsbi
|
||||
install_libsbi: $(build_dir)/lib/libsbi.a
|
||||
$(call inst_header_dir,$(install_dir)/include,$(include_dir)/sbi)
|
||||
$(call inst_file,$(install_dir)/lib/libsbi.a,$(build_dir)/lib/libsbi.a)
|
||||
$(call inst_header_dir,$(install_root_dir)/$(install_include_path),$(include_dir)/sbi)
|
||||
$(call inst_file,$(install_root_dir)/$(install_lib_path)/libsbi.a,$(build_dir)/lib/libsbi.a)
|
||||
|
||||
.PHONY: install_libsbiutils
|
||||
install_libsbiutils: $(build_dir)/lib/libsbiutils.a
|
||||
$(call inst_header_dir,$(install_dir)/include,$(include_dir)/sbi_utils)
|
||||
$(call inst_file,$(install_dir)/lib/libsbiutils.a,$(build_dir)/lib/libsbiutils.a)
|
||||
$(call inst_header_dir,$(install_root_dir)/$(install_include_path),$(include_dir)/sbi_utils)
|
||||
$(call inst_file,$(install_root_dir)/$(install_lib_path)/libsbiutils.a,$(build_dir)/lib/libsbiutils.a)
|
||||
|
||||
.PHONY: install_libplatsbi
|
||||
install_libplatsbi: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(build_dir)/lib/libsbiutils.a
|
||||
$(call inst_file,$(install_dir)/platform/$(platform_subdir)/lib/libplatsbi.a,$(platform_build_dir)/lib/libplatsbi.a)
|
||||
$(call inst_file,$(install_root_dir)/$(install_lib_path)/opensbi/$(platform_subdir)/lib/libplatsbi.a,$(platform_build_dir)/lib/libplatsbi.a)
|
||||
|
||||
.PHONY: install_firmwares
|
||||
install_firmwares: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(build_dir)/lib/libsbiutils.a $(firmware-bins-path-y)
|
||||
$(call inst_file_list,$(install_dir),$(build_dir),platform/$(platform_subdir)/firmware,$(firmware-elfs-path-y))
|
||||
$(call inst_file_list,$(install_dir),$(build_dir),platform/$(platform_subdir)/firmware,$(firmware-bins-path-y))
|
||||
$(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-elfs-path-y))
|
||||
$(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-bins-path-y))
|
||||
|
||||
.PHONY: install_docs
|
||||
install_docs: $(build_dir)/docs/latex/refman.pdf
|
||||
$(call inst_file,$(install_dir)/docs/refman.pdf,$(build_dir)/docs/latex/refman.pdf)
|
||||
$(call inst_file,$(install_root_dir)/$(install_docs_path)/refman.pdf,$(build_dir)/docs/latex/refman.pdf)
|
||||
|
||||
# Rule for "make clean"
|
||||
.PHONY: clean
|
||||
@@ -418,7 +472,7 @@ ifeq ($(build_dir),$(CURDIR)/build)
|
||||
$(if $(V), @echo " RM $(build_dir)")
|
||||
$(CMD_PREFIX)rm -rf $(build_dir)
|
||||
endif
|
||||
ifeq ($(install_dir),$(CURDIR)/install)
|
||||
$(if $(V), @echo " RM $(install_dir)")
|
||||
$(CMD_PREFIX)rm -rf $(install_dir)
|
||||
ifeq ($(install_root_dir),$(install_root_dir_default)/usr)
|
||||
$(if $(V), @echo " RM $(install_root_dir_default)")
|
||||
$(CMD_PREFIX)rm -rf $(install_root_dir_default)
|
||||
endif
|
||||
|
105
README.md
105
README.md
@@ -1,9 +1,41 @@
|
||||
Copyright (c) 2019 Western Digital Corporation or its affiliates
|
||||
and other contributors.
|
||||
|
||||
RISC-V Open Source Supervisor Binary Interface (OpenSBI)
|
||||
========================================================
|
||||
|
||||
Copyright and License
|
||||
---------------------
|
||||
|
||||
The OpenSBI project is copyright (c) 2019 Western Digital Corporation
|
||||
or its affiliates and other contributors.
|
||||
|
||||
It is distributed under the terms of the BSD 2-clause license
|
||||
("Simplified BSD License" or "FreeBSD License", SPDX: *BSD-2-Clause*).
|
||||
A copy of this license with OpenSBI copyright can be found in the file
|
||||
[COPYING.BSD].
|
||||
|
||||
All source files in OpenSBI contain the 2-Clause BSD license SPDX short
|
||||
identifier in place of the full license text.
|
||||
|
||||
```
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
```
|
||||
|
||||
This enables machine processing of license information based on the SPDX
|
||||
License Identifiers that are available on the [SPDX] web site.
|
||||
|
||||
OpenSBI source code also contains code reused from other projects as listed
|
||||
below. The original license text of these projects is included in the source
|
||||
files where the reused code is present.
|
||||
|
||||
* The libfdt source code is disjunctively dual licensed
|
||||
(GPL-2.0+ OR BSD-2-Clause). Some of this project code is used in OpenSBI
|
||||
under the terms of the BSD 2-Clause license. Any contributions to this
|
||||
code must be made under the terms of both licenses.
|
||||
|
||||
See also the [third party notices] file for more information.
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
The **RISC-V Supervisor Binary Interface (SBI)** is the recommended interface
|
||||
between:
|
||||
|
||||
@@ -39,6 +71,27 @@ OpenSBI also provides several runtime firmware examples built using the platform
|
||||
*riscv-pk* bootloader (aka BBL) and enable the use of well-known bootloaders
|
||||
such as [U-Boot] (https://git.denx.de/u-boot.git).
|
||||
|
||||
Supported SBI version
|
||||
---------------------
|
||||
Currently, OpenSBI fully supports SBI specification *v0.2*. OpenSBI also
|
||||
supports Hart State Management (HSM) SBI extension starting from OpenSBI v0.7.
|
||||
HSM extension allows S-mode software to boot all the harts a defined order
|
||||
rather than legacy method of random booting of harts. As a result, many
|
||||
required features such as CPU hotplug, kexec/kdump can also be supported easily
|
||||
in S-mode. HSM extension in OpenSBI is implemented in a non-backward compatible
|
||||
manner to reduce the maintenance burden and avoid confusion. That's why, any
|
||||
S-mode software using OpenSBI will not be able to boot more than 1 hart if HSM
|
||||
extension is not supported in S-mode.
|
||||
|
||||
Linux kernel already supports SBI v0.2 and HSM SBI extension starting from
|
||||
**v5.7-rc1**. If you are using an Linux kernel older than **5.7-rc1** or any
|
||||
other S-mode software without HSM SBI extension, you should stick to OpenSBI
|
||||
v0.6 to boot all the harts. For a UMP systems, it doesn't matter.
|
||||
|
||||
N.B. Any S-mode boot loader (i.e. U-Boot) doesn't need to support HSM extension,
|
||||
as it doesn't need to boot all the harts. The operating system should be
|
||||
capable enough to bring up all other non-booting harts using HSM extension.
|
||||
|
||||
Required Toolchain
|
||||
------------------
|
||||
|
||||
@@ -47,7 +100,7 @@ cross-compilation, you can build your own toolchain or just download
|
||||
a prebuilt one from the
|
||||
[Bootlin toolchain repository] (https://toolchains.bootlin.com/).
|
||||
|
||||
Please note that only a 64bit version of the toolchain is available in
|
||||
Please note that only a 64-bit version of the toolchain is available in
|
||||
the Bootlin toolchain repository for now.
|
||||
|
||||
Building and Installing the OpenSBI Platform-Independent Library
|
||||
@@ -94,7 +147,7 @@ line, the platform-specific static library *libplatsbi.a* and firmware examples
|
||||
are built for the platform *<platform_subdir>* present in the directory
|
||||
*platform* in the OpenSBI top directory. For example, to compile the platform
|
||||
library and the firmware examples for the QEMU RISC-V *virt* machine,
|
||||
*<platform_subdir>* should be *qemu/virt*.
|
||||
*<platform_subdir>* should be *generic*.
|
||||
|
||||
To build *libsbi.a*, *libplatsbi.a* and the firmware for one of the supported
|
||||
platforms, run:
|
||||
@@ -131,38 +184,24 @@ top-level make command line. These options, such as *PLATFORM_<xyz>* or
|
||||
*docs/platform/<platform_name>.md* files and
|
||||
*docs/firmware/<firmware_name>.md* files.
|
||||
|
||||
License
|
||||
-------
|
||||
Building 32-bit / 64-bit OpenSBI Images
|
||||
---------------------------------------
|
||||
By default, building OpenSBI generates 32-bit or 64-bit images based on the
|
||||
supplied RISC-V cross-compile toolchain. For example if *CROSS_COMPILE* is set
|
||||
to *riscv64-unknown-elf-*, 64-bit OpenSBI images will be generated. If building
|
||||
32-bit OpenSBI images, *CROSS_COMPILE* should be set to a toolchain that is
|
||||
pre-configured to generate 32-bit RISC-V codes, like *riscv32-unknown-elf-*.
|
||||
|
||||
OpenSBI is distributed under the terms of the BSD 2-clause license
|
||||
("Simplified BSD License" or "FreeBSD License", SPDX: *BSD-2-Clause*).
|
||||
A copy of this license with OpenSBI copyright can be found in the file
|
||||
[COPYING.BSD].
|
||||
|
||||
All source files in OpenSBI contain the 2-Clause BSD license SPDX short
|
||||
identifier in place of the full license text.
|
||||
However it's possible to explicitly specify the image bits we want to build with
|
||||
a given RISC-V toolchain. This can be done by setting the environment variable
|
||||
*PLATFORM_RISCV_XLEN* to the desired width, for example:
|
||||
|
||||
```
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
export CROSS_COMPILE=riscv64-unknown-elf-
|
||||
export PLATFORM_RISCV_XLEN=32
|
||||
```
|
||||
|
||||
This enables machine processing of license information based on the SPDX
|
||||
License Identifiers that are available on the [SPDX] web site.
|
||||
|
||||
OpenSBI source code also contains code reused from other projects as listed
|
||||
below. The original license text of these projects is included in the source
|
||||
files where the reused code is present.
|
||||
|
||||
1. The libfdt source code is disjunctively dual licensed
|
||||
(GPL-2.0+ OR BSD-2-Clause). Some of this project code is used in OpenSBI
|
||||
under the terms of the BSD 2-Clause license. Any contributions to this
|
||||
code must be made under the terms of both licenses.
|
||||
2. Some source file for the Kendryte/k210 platform code are based on code from
|
||||
the [Kendryte standalone SDK] available on github. These files retain the
|
||||
original copyright and license of the Kendryte standalone SDK project and
|
||||
are licensed under the terms of the Apache License, Version 2.0.
|
||||
|
||||
See also the [third party notices] file for more information.
|
||||
will generate 32-bit OpenSBI images. And vice vesa.
|
||||
|
||||
Contributing to OpenSBI
|
||||
-----------------------
|
||||
@@ -182,6 +221,7 @@ Detailed documentation of various aspects of OpenSBI can be found under the
|
||||
|
||||
* [Contribution Guideline]: Guideline for contributing code to OpenSBI project
|
||||
* [Library Usage]: API documentation of OpenSBI static library *libsbi.a*
|
||||
* [Platform Requirements]: Requirements for using OpenSBI on a platform
|
||||
* [Platform Support Guide]: Guideline for implementing support for new platforms
|
||||
* [Platform Documentation]: Documentation of the platforms currently supported.
|
||||
* [Firmware Documentation]: Documentation for the different types of firmware
|
||||
@@ -234,6 +274,7 @@ make I=<install_directory> install_docs
|
||||
[Contribution Guideline]: docs/contributing.md
|
||||
[Contributors List]: CONTRIBUTORS.md
|
||||
[Library Usage]: docs/library_usage.md
|
||||
[Platform Requirements]: docs/platform_requirements.md
|
||||
[Platform Support Guide]: docs/platform_guide.md
|
||||
[Platform Documentation]: docs/platform/platform.md
|
||||
[Firmware Documentation]: docs/firmware/fw.md
|
||||
|
@@ -16,192 +16,3 @@ The libfdt source code is disjunctively dual licensed (GPL-2.0+ or
|
||||
BSD-2-Clause). Some of this project code is used in OpenSBI under the terms of
|
||||
the BSD 2-Clause license. The full text of this license can be found in the
|
||||
file [COPYING.BSD](COPYING.BSD).
|
||||
|
||||
Kendryte Standalone SDK
|
||||
-----------------------
|
||||
|
||||
Copyright 2018 Canaan Inc.
|
||||
|
||||
The Kendryte K210 platform code reuses some code from Kendryte standalone SDK
|
||||
licensed under the terms of the Apache License, Version 2.0. The full text of
|
||||
this license is available at http://www.apache.org/licenses/LICENSE-2.0 and
|
||||
included below.
|
||||
|
||||
```
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
```
|
||||
|
@@ -793,6 +793,7 @@ WARN_LOGFILE =
|
||||
INPUT = @@SRC_DIR@@/README.md \
|
||||
@@SRC_DIR@@/docs/contributing.md \
|
||||
@@SRC_DIR@@/docs/platform_guide.md \
|
||||
@@SRC_DIR@@/docs/platform_requirements.md \
|
||||
@@SRC_DIR@@/docs/library_usage.md \
|
||||
@@SRC_DIR@@/docs/firmware \
|
||||
@@SRC_DIR@@/docs/platform \
|
||||
@@ -948,7 +949,7 @@ FILTER_SOURCE_PATTERNS =
|
||||
# (index.html). This can be useful if you have a project on for instance GitHub
|
||||
# and want to reuse the introduction page also for the doxygen output.
|
||||
|
||||
USE_MDFILE_AS_MAINPAGE =
|
||||
USE_MDFILE_AS_MAINPAGE = README.md
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to source browsing
|
||||
@@ -1444,7 +1445,7 @@ DISABLE_INDEX = NO
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
GENERATE_TREEVIEW = NO
|
||||
GENERATE_TREEVIEW = YES
|
||||
|
||||
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
|
||||
# doxygen will group on one line in the generated HTML documentation.
|
||||
|
14
docs/external/coreboot.md
vendored
14
docs/external/coreboot.md
vendored
@@ -1,7 +1,10 @@
|
||||
OpenSBI as coreboot payload
|
||||
==============================
|
||||
===========================
|
||||
|
||||
[coreboot](https://www.coreboot.org/) is a free/libre and open source firmware platform support multiple hardware architectures( x86, ARMv7, arm64, PowerPC64, MIPS and RISC-V) and diverse hardware models. In RISC-V world, coreboot currently support HiFive Unleashed with OpenSBI as a payload to boot GNU/Linux:
|
||||
[coreboot] is a free/libre and open source firmware platform support multiple
|
||||
hardware architectures(x86, ARMv7, arm64, PowerPC64, MIPS and RISC-V) and
|
||||
diverse hardware models. In RISC-V world, coreboot currently support HiFive
|
||||
Unleashed with OpenSBI as a payload to boot GNU/Linux:
|
||||
|
||||
```
|
||||
SiFive HiFive unleashed's original firmware boot process:
|
||||
@@ -21,4 +24,9 @@ coreboot boot process:
|
||||
+---------------------------------------------+-------------+-------+-+
|
||||
```
|
||||
|
||||
The upstreaming work is still in progress. There's a [documentation](https://github.com/hardenedlinux/embedded-iot_profile/blob/master/docs/riscv/hifiveunleashed_coreboot_notes-en.md) about how to build [out-of-tree code](https://github.com/hardenedlinux/coreboot-HiFiveUnleashed) to load OpenSBI.
|
||||
The upstreaming work is still in progress. There's a [documentation] about how
|
||||
to build [out-of-tree code] to load OpenSBI.
|
||||
|
||||
[coreboot]: https://www.coreboot.org/
|
||||
[documentation]: https://github.com/hardenedlinux/embedded-iot_profile/blob/master/docs/riscv/hifiveunleashed_coreboot_notes-en.md
|
||||
[out-of-tree code]: https://github.com/hardenedlinux/coreboot-HiFiveUnleashed
|
||||
|
@@ -1,4 +1,4 @@
|
||||
OpenSBI Firmware with Dynamic Information *FW_DYNAMIC*
|
||||
OpenSBI Firmware with Dynamic Information (FW_DYNAMIC)
|
||||
======================================================
|
||||
|
||||
OpenSBI **firmware with dynamic info (FW_DYNAMIC)** is a firmware which gets
|
||||
|
@@ -1,4 +1,4 @@
|
||||
OpenSBI Firmware with Jump Address *FW_JUMP*
|
||||
OpenSBI Firmware with Jump Address (FW_JUMP)
|
||||
============================================
|
||||
|
||||
OpenSBI **firmware with Jump Address (FW_JUMP)** is a firmware which only
|
||||
@@ -38,15 +38,14 @@ follows:
|
||||
* **FW_JUMP_FDT_ADDR** - Address where the *flattened device tree (FDT file)*
|
||||
passed by the prior booting stage will be placed in memory before executing
|
||||
the booting stage following the OpenSBI firmware. If this option is not
|
||||
provided, then the OpenSBI firmware will pass zero as the FDT address to the
|
||||
following booting stage.
|
||||
provided, then the OpenSBI firmware will pass the FDT address passed by the
|
||||
previous booting stage to the next booting stage.
|
||||
|
||||
*FW_JUMP* Example
|
||||
-----------------
|
||||
|
||||
The *[qemu/virt]* and *[qemu/sifive_u]* platforms illustrate how to configure
|
||||
and use a *FW_JUMP* firmware. Detailed information regarding these platforms
|
||||
can be found in the platform documentation files.
|
||||
The *[qemu/virt]* platform illustrates how to configure and use a *FW_JUMP*
|
||||
firmware. Detailed information regarding these platforms can be found in the
|
||||
platform documentation files.
|
||||
|
||||
[qemu/virt]: ../platform/qemu_virt.md
|
||||
[qemu/sifive_u]: ../platform/qemu_sifive_u.md
|
||||
|
@@ -1,4 +1,4 @@
|
||||
OpenSBI Firmware with Payload *FW_PAYLOAD*
|
||||
OpenSBI Firmware with Payload (FW_PAYLOAD)
|
||||
==========================================
|
||||
|
||||
OpenSBI **firmware with Payload (FW_PAYLOAD)** is a firmware which directly
|
||||
@@ -57,33 +57,21 @@ file. The parameters currently defined are as follows:
|
||||
|
||||
* **FW_PAYLOAD_FDT_PATH** - Path to an external flattened device tree binary
|
||||
file to be embedded in the *.text* section of the final firmware. If this
|
||||
option is not provided and no internal device tree file is specified by the
|
||||
platform (c.f. *FW_PAYLOAD_FDT*), then the firmware will expect the FDT to
|
||||
be passed as an argument by the prior booting stage.
|
||||
|
||||
* **FW_PAYLOAD_FDT** - Path to an internal flattened device tree binary file
|
||||
defined by the platform code. The file name must match the DTB file name
|
||||
specified in the platform *objects.mk* file with the *platform-dtb-y* entry.
|
||||
This option results in *FW_PAYLOAD_FDT_PATH* to be automatically set.
|
||||
Specifying *FW_PAYLOAD_FDT_PATH* on the `make` command line disables
|
||||
*FW_PAYLOAD_FDT* and the command line specified device tree binary file is
|
||||
used for building the final firmware.
|
||||
option is not provided then the firmware will expect the FDT to be passed
|
||||
as an argument by the prior booting stage.
|
||||
|
||||
* **FW_PAYLOAD_FDT_ADDR** - Address where the FDT passed by the prior booting
|
||||
stage or specified by the *FW_PAYLOAD_FDT_PATH* parameter and embedded in
|
||||
the *.text* section will be placed before executing the next booting stage,
|
||||
that is, the payload firmware. If this option is not provided, then the
|
||||
firmware will pass zero as the FDT address to the next booting stage.
|
||||
firmware will pass the FDT address passed by the previous booting stage
|
||||
to the next booting stage.
|
||||
|
||||
*FW_PAYLOAD* Example
|
||||
--------------------
|
||||
|
||||
The *[qemu/virt]* and *[qemu/sifive_u]* platforms illustrate how to configure
|
||||
and use a *FW_PAYLOAD* firmware. Detailed information regarding these platforms
|
||||
can be found in the platform documentation files.
|
||||
|
||||
The *kendryte/k210* platform also enables a build of a *FW_PAYLOAD* using an
|
||||
internally defined device tree file (*FW_PAYLOAD_FDT*).
|
||||
The *[qemu/virt]* platforms illustrate how to configure and use a *FW_PAYLOAD*
|
||||
firmware. Detailed information regarding these platforms can be found in the
|
||||
platform documentation files.
|
||||
|
||||
[qemu/virt]: ../platform/qemu_virt.md
|
||||
[qemu/sifive_u]: ../platform/qemu_sifive_u.md
|
||||
|
@@ -7,4 +7,3 @@ provided as a payload to OpenSBI.
|
||||
|
||||
Detailed examples can be found in both the [QEMU](../platform/qemu_virt.md)
|
||||
and the [HiFive Unleashed](../platform/sifive_fu540.md) platform guides.
|
||||
|
||||
|
@@ -7,34 +7,9 @@ environment. In the context of OpenSBI, U-Boot can be specified as a payload to
|
||||
the OpenSBI firmware, becoming the boot stage following the OpenSBI firmware
|
||||
execution.
|
||||
|
||||
The current stable upstream code of U-Boot does not yet include all patches
|
||||
necessary to fully support OpenSBI. To use U-Boot as an OpenSBI payload, the
|
||||
following out-of-tree patch series must be applied to the upstream U-Boot source
|
||||
code:
|
||||
|
||||
HiFive Unleashed support for U-Boot
|
||||
|
||||
https://lists.denx.de/pipermail/u-boot/2019-February/358058.html
|
||||
|
||||
This patch series enables a single CPU to execute U-Boot. As a result, the next
|
||||
stage boot code such as a Linux kernel can also only execute on a single CPU.
|
||||
U-Boot SMP support for RISC-V can be enabled with the following additional
|
||||
patches:
|
||||
|
||||
https://lists.denx.de/pipermail/u-boot/2019-February/358393.html
|
||||
|
||||
Building and Generating U-Boot images
|
||||
=====================================
|
||||
Please refer to the U-Boot build documentation for detailed instructions on
|
||||
how to build U-Boot images.
|
||||
how to build U-Boot image and boot high level operating systems from U-Boot
|
||||
prompt.
|
||||
|
||||
Once U-Boot images are built, the Linux kernel image needs to be converted
|
||||
into a format that U-Boot understands:
|
||||
|
||||
```
|
||||
<uboot-dir>/tools/mkimage -A riscv -O linux -T kernel -C none -a 0x80200000 -e 0x80200000 -n Linux -d \
|
||||
<linux_build_directory>arch/riscv/boot/Image \
|
||||
<linux_build_directory>/arch/riscv/boot/uImage
|
||||
```
|
||||
|
||||
Copy the uImage to your tftpboot server path if network boot is required.
|
||||
|
@@ -66,3 +66,24 @@ bootloader to service the following interrupts and traps:
|
||||
|
||||
**Note:** external firmwares or bootloaders can be more conservative by
|
||||
forwarding all traps and interrupts to *sbi_trap_handler()*.
|
||||
|
||||
Definitions of OpenSBI Data Types for the External Firmware
|
||||
-----------------------------------------------------------
|
||||
|
||||
OpenSBI can be built as library using external firmware build system such as EDK2
|
||||
code base (The open source of UEFI firmware implementation) and linked with external
|
||||
firmware drivers based on the external firmware architecture.
|
||||
|
||||
**OPENSBI_EXTERNAL_SBI_TYPES** identifier is introduced to *sbi_types.h* for selecting
|
||||
external header file during the build preprocess in order to define OpensSBI data types
|
||||
based on external firmware data type binding.
|
||||
For example, *bool* is declared as *int* in sbi_types.h. However in EDK2 build system,
|
||||
*bool* is declared as *BOOLEAN* which is defined as *unsigned char* data type.
|
||||
|
||||
External firmware can define **OPENSBI_EXTERNAL_SBI_TYPES** in CFLAGS and specify it to the
|
||||
header file maintained in its code tree. However, the external build system has to address
|
||||
the additional include directory for the external header file based on its own build system.
|
||||
For example,
|
||||
*-D***OPENSBI_EXTERNAL_SBI_TYPES***=OpensbiTypes.h*
|
||||
Above tells *sbi_types.h* to refer to *OpensbiTypes.h* instead of using original definitions of
|
||||
data types.
|
||||
|
30
docs/platform/andes-ae350.md
Normal file
30
docs/platform/andes-ae350.md
Normal file
@@ -0,0 +1,30 @@
|
||||
Andes AE350 SoC Platform
|
||||
========================
|
||||
The AE350 AXI/AHB-based platform N25(F)/NX25(F)/D25F/A25/AX25 CPU with level-one
|
||||
memories,interrupt controller, debug module, AXI and AHB Bus Matrix Controller,
|
||||
AXI-to-AHB Bridge and a collection of fundamentalAHB/APB bus IP components
|
||||
pre-integrated together as a system design.The high-quality and configurable
|
||||
AHB/APB IPs suites a majority embedded systems, and the verified platform serves
|
||||
as a starting point to jump start SoC designs.
|
||||
|
||||
To build platform specific library and firmwares, provide the
|
||||
*PLATFORM=andes/ae350* parameter to the top level make command.
|
||||
|
||||
Platform Options
|
||||
----------------
|
||||
|
||||
The Andes AE350 platform does not have any platform-specific options.
|
||||
|
||||
Building Andes AE350 Platform
|
||||
-----------------------------
|
||||
|
||||
To use Linux v5.2 should be used to build Andes AE350 OpenSBI binaries by using
|
||||
the compile time option FW_PAYLOAD_FDT_PATH.
|
||||
|
||||
AE350's dts is included in https://github.com/andestech/linux/tree/ast-v3_2_0-release-public
|
||||
|
||||
**Linux Kernel Payload**
|
||||
|
||||
```
|
||||
make PLATFORM=andes/ae350 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_PAYLOAD_FDT_PATH=<ae350.dtb path>
|
||||
```
|
@@ -1,9 +1,11 @@
|
||||
Ariane FPGA SoC Platform
|
||||
==========================
|
||||
Ariane is a 6-stage, single issue, in-order CPU which implements the 64-bit RISC-V instruction set.
|
||||
The Ariane FPGA development platform is based on FPGA FPGA SoC(which currently supports only Genesys 2 board) and is capable
|
||||
of running Linux.
|
||||
The FPGA SoC currently contains the following peripherals:
|
||||
========================
|
||||
Ariane is a 6-stage, single issue, in-order CPU which implements the 64-bit
|
||||
RISC-V instruction set. The Ariane FPGA development platform is based on FPGA
|
||||
SoC (which currently supports only Genesys 2 board) and is capable of running
|
||||
Linux.
|
||||
|
||||
The FPGA SoC currently contains the following peripherals:
|
||||
- DDR3 memory controller
|
||||
- SPI controller to conncet to an SDCard
|
||||
- Ethernet controller
|
||||
@@ -11,27 +13,26 @@ of running Linux.
|
||||
- Bootrom containing zero stage bootloader and device tree.
|
||||
|
||||
To build platform specific library and firmwares, provide the
|
||||
*PLATFORM=ariane-fpga* parameter to the top level `make` command.
|
||||
*PLATFORM=fpga/ariane* parameter to the top level `make` command.
|
||||
|
||||
Platform Options
|
||||
----------------
|
||||
|
||||
The *Ariane FPGA* platform does not have any platform-specific
|
||||
options.
|
||||
The *Ariane FPGA* platform does not have any platform-specific options.
|
||||
|
||||
Building Ariane FPGA Platform
|
||||
-----------------------------
|
||||
|
||||
**Linux Kernel Payload**
|
||||
|
||||
|
||||
```
|
||||
make PLATFORM=ariane-fpga FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
||||
make PLATFORM=fpga/ariane FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
||||
```
|
||||
|
||||
Booting Ariane FPGA Platform
|
||||
-----------------------------
|
||||
----------------------------
|
||||
|
||||
**Linux Kernel Payload**
|
||||
|
||||
As Linux kernel image is embedded in the OpenSBI firmware binary, Ariane will directly
|
||||
boot into Linux directly after powered on.
|
||||
As Linux kernel image is embedded in the OpenSBI firmware binary, Ariane will
|
||||
directly boot into Linux directly after powered on.
|
33
docs/platform/fpga-openpiton.md
Normal file
33
docs/platform/fpga-openpiton.md
Normal file
@@ -0,0 +1,33 @@
|
||||
OpenPiton FPGA SoC Platform
|
||||
========================
|
||||
OpenPiton is the world's first open source, general purpose, multithreaded
|
||||
manycore processor. It is a tiled manycore framework scalable from one to
|
||||
1/2 billion cores. Currently, OpenPiton supports the 64bit Ariane RISC-V
|
||||
processor from ETH Zurich. To this end, Ariane has been equipped with a
|
||||
different L1 cache subsystem that follows a write-through protocol and that has
|
||||
support for cache invalidations and atomics.
|
||||
|
||||
To build platform specific library and firmwares, provide the
|
||||
*PLATFORM=fpga/openpiton* parameter to the top level `make` command.
|
||||
|
||||
Platform Options
|
||||
----------------
|
||||
|
||||
The *OpenPiton* platform does not have any platform-specific options.
|
||||
|
||||
Building Ariane FPGA Platform
|
||||
-----------------------------
|
||||
|
||||
**Linux Kernel Payload**
|
||||
|
||||
```
|
||||
make PLATFORM=fpga/openpiton FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
||||
```
|
||||
|
||||
Booting Ariane FPGA Platform
|
||||
----------------------------
|
||||
|
||||
**Linux Kernel Payload**
|
||||
|
||||
As Linux kernel image is embedded in the OpenSBI firmware binary, Ariane will
|
||||
directly boot into Linux directly after powered on.
|
54
docs/platform/generic.md
Normal file
54
docs/platform/generic.md
Normal file
@@ -0,0 +1,54 @@
|
||||
Generic Platform
|
||||
================
|
||||
|
||||
The **Generic** platform is a flattened device tree (FDT) based platform
|
||||
where all platform specific functionality is provided based on FDT passed
|
||||
by previous booting stage. The **Generic** platform allows us to use same
|
||||
OpenSBI firmware binaries on various emulators, simulators, FPGAs, and
|
||||
boards.
|
||||
|
||||
By default, the generic FDT platform makes following assumptions:
|
||||
|
||||
1. platform FW_TEXT_START is 0x80000000
|
||||
2. platform features are default
|
||||
3. platform stack size is default
|
||||
4. platform has no quirks or work-arounds
|
||||
|
||||
The above assumptions (except 1) can be overridden by adding special platform
|
||||
callbacks which will be called based on FDT root node compatible string.
|
||||
|
||||
Users of the generic FDT platform will have to ensure that:
|
||||
|
||||
1. Various FDT based drivers under lib/utils directory are upto date
|
||||
based on their platform requirements
|
||||
2. The FDT passed by previous booting stage has DT compatible strings and
|
||||
DT properties in sync with the FDT based drivers under lib/utils directory
|
||||
3. The FDT must have "stdout-path" DT property in the "/chosen" DT node when
|
||||
a platform has multiple serial ports or consoles
|
||||
4. On multi-HART platform, the FDT must have a DT node for IPI device and
|
||||
lib/utils/ipi directory must have corresponding FDT based IPI driver
|
||||
5. The FDT must have a DT node for timer device and lib/utils/timer directory
|
||||
must have corresponding FDT based timer driver
|
||||
|
||||
To build the platform-specific library and firmware images, provide the
|
||||
*PLATFORM=generic* parameter to the top level `make` command.
|
||||
|
||||
For custom FW_TEXT_START, we can build the platform-specific library and
|
||||
firmware images by passing *PLATFORM=generic FW_TEXT_START=<custom_text_start>*
|
||||
parameter to the top level `make` command.
|
||||
|
||||
Platform Options
|
||||
----------------
|
||||
|
||||
The *Generic* platform does not have any platform-specific options.
|
||||
|
||||
RISC-V Platforms Using Generic Platform
|
||||
---------------------------------------
|
||||
|
||||
* **QEMU RISC-V Virt Machine** (*[qemu_virt.md]*)
|
||||
* **Spike** (*[spike.md]*)
|
||||
* **Shakti C-class SoC Platform** (*[shakti_cclass.md]*)
|
||||
|
||||
[qemu_virt.md]: qemu_virt.md
|
||||
[spike.md]: spike.md
|
||||
[shakti_cclass.md]: shakti_cclass.md
|
22
docs/platform/nuclei_ux600.md
Normal file
22
docs/platform/nuclei_ux600.md
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
Nuclei UX600 Platform
|
||||
=====================
|
||||
|
||||
The **Nuclei UX600** is a 64-bit RISC-V Core which is capable of running Linux.
|
||||
|
||||
> Nuclei UX600: single core, pipeline as single-issue and 6~9 variable stages, in-order dispatch and out-of-order write-back, running up to >1.2GHz
|
||||
|
||||
To build the platform-specific library and firmware images, provide the
|
||||
*PLATFORM=nuclei/ux600* parameter to the top level `make` command.
|
||||
|
||||
Platform Options
|
||||
----------------
|
||||
|
||||
The *Nuclei UX600* platform does not have any platform-specific options.
|
||||
|
||||
Building Nuclei UX600 Platform
|
||||
------------------------------
|
||||
|
||||
```
|
||||
make PLATFORM=nuclei/ux600 clean all
|
||||
```
|
@@ -3,26 +3,44 @@ OpenSBI Supported Platforms
|
||||
|
||||
OpenSBI currently supports the following virtual and hardware platforms:
|
||||
|
||||
* **Generic**: Flattened device tree (FDT) based platform where platform
|
||||
specific functionality is provided based on the FDT passed by previous
|
||||
booting stage. More details on this platform can be found in the file
|
||||
*[generic.md]*.
|
||||
|
||||
* **QEMU RISC-V Virt Machine**: Platform support for the QEMU *virt* virtual
|
||||
RISC-V machine. This virtual machine is intended for RISC-V software
|
||||
development and tests. More details on this platform can be found in the
|
||||
file *[qemu_virt.md]*.
|
||||
|
||||
* **QEMU SiFive Unleashed Machine**: Platform support for the *sifive_u* QEMU
|
||||
virtual RISC-V machine. This is an emulation machine of the HiFive Unleashed
|
||||
board by SiFive. More details on this platform can be found in the file
|
||||
*[qemu_sifive_u.md]*.
|
||||
|
||||
* **SiFive FU540 SoC**: Platform support for SiFive FU540 SoC used on the
|
||||
HiFive Unleashed board. This platform is very similar to the *QEMU sifive_u*
|
||||
platform. More details on this platform can be found in the file
|
||||
HiFive Unleashed board, as well as the *sifive_u* QEMU virtual RISC-V
|
||||
machine. More details on this platform can be found in the file
|
||||
*[sifive_fu540.md]*.
|
||||
|
||||
* **Kendryte K210 SoC**: Platform support for the Kendryte K210 SoC used on
|
||||
boards such as the Kendryte KD233 or the Sipeed MAIX Dock.
|
||||
|
||||
* **Ariane FPGA SoC**: Platform support for the Ariane FPGA SoC used on
|
||||
Genesys 2 board.
|
||||
Genesys 2 board. More details on this platform can be found in the file
|
||||
*[fpga-ariane.md]*.
|
||||
|
||||
* **Andes AE350 SoC**: Platform support for the Andes's SoC (AE350). More
|
||||
details on this platform can be found in the file *[andes-ae350.md]*.
|
||||
|
||||
* **T-HEAD C910**: Platform support for the T-HEAD C910 Processor. More
|
||||
details on this platform can be found in the file *[thead-c910.md]*.
|
||||
|
||||
* **Spike**: Platform support for the Spike emulator. More
|
||||
details on this platform can be found in the file *[spike.md]*.
|
||||
|
||||
* **OpenPiton FPGA SoC**: Platform support OpenPiton research platform based
|
||||
on ariane core. More details on this platform can be found in the file
|
||||
*[fpga_openpiton.md]*.
|
||||
|
||||
* **Shakti C-class SoC Platform**: Platform support for Shakti C-class
|
||||
processor based SOCs. More details on this platform can be found in the
|
||||
file *[shakti_cclass.md]*.
|
||||
|
||||
The code for these supported platforms can be used as example to implement
|
||||
support for other platforms. The *platform/template* directory also provides
|
||||
@@ -30,7 +48,12 @@ template files for implementing support for a new platform. The *object.mk*,
|
||||
*config.mk* and *platform.c* template files provides enough comments to
|
||||
facilitate the implementation.
|
||||
|
||||
[generic.md]: generic.md
|
||||
[qemu_virt.md]: qemu_virt.md
|
||||
[qemu_sifive_u.md]: qemu_sifive_u.md
|
||||
[sifive_fu540.md]: sifive_fu540.md
|
||||
[ariane-fpga.md]: ariane-fpga.md
|
||||
[fpga-ariane.md]: fpga-ariane.md
|
||||
[andes-ae350.md]: andes-ae350.md
|
||||
[thead-c910.md]: thead-c910.md
|
||||
[spike.md]: spike.md
|
||||
[fpga_openpiton.md]: fpga_openpiton.md
|
||||
[shakti_cclass.md]: shakti_cclass.md
|
||||
|
@@ -1,52 +0,0 @@
|
||||
QEMU SiFive Unleashed Machine Platform
|
||||
======================================
|
||||
|
||||
The **QEMU SiFive Unleashed Machine** is an emulation of the SiFive Unleashed
|
||||
platform.
|
||||
|
||||
To build this platform specific library and firmwares, provide the
|
||||
*PLATFORM=qemu/sifive_u* parameter to the top level `make` command line.
|
||||
|
||||
Platform Options
|
||||
----------------
|
||||
|
||||
The *QEMU SiFive Unleashed Machine* platform does not have any platform specific
|
||||
options.
|
||||
|
||||
Executing on QEMU RISC-V 64bit
|
||||
------------------------------
|
||||
|
||||
**No Payload Case**
|
||||
|
||||
Build:
|
||||
```
|
||||
make PLATFORM=qemu/sifive_u
|
||||
```
|
||||
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv64 -M sifive_u -m 256M -display none -serial stdio \
|
||||
-kernel build/platform/qemu/sifive_u/firmware/fw_payload.elf
|
||||
```
|
||||
|
||||
**U-Boot as a Payload**
|
||||
|
||||
Note: the command line examples here assume that U-Boot was compiled using
|
||||
the `sifive_fu540_defconfig` configuration.
|
||||
|
||||
Build:
|
||||
```
|
||||
make PLATFORM=qemu/sifive_u FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
|
||||
```
|
||||
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv64 -M sifive_u -m 256M -display none -serial stdio \
|
||||
-kernel build/platform/qemu/sifive_u/firmware/fw_payload.elf
|
||||
```
|
||||
or
|
||||
```
|
||||
qemu-system-riscv64 -M sifive_u -m 256M -display none -serial stdio \
|
||||
-kernel build/platform/qemu/sifive_u/firmware/fw_jump.elf \
|
||||
-device loader,file=<uboot_build_directory>/u-boot.bin,addr=0x80200000
|
||||
```
|
@@ -7,7 +7,7 @@ software development and testing. It is also referred to as
|
||||
storage, and other types of IO.
|
||||
|
||||
To build the platform-specific library and firmware images, provide the
|
||||
*PLATFORM=qemu/virt* parameter to the top level `make` command.
|
||||
*PLATFORM=generic* parameter to the top level `make` command.
|
||||
|
||||
Platform Options
|
||||
----------------
|
||||
@@ -15,20 +15,20 @@ Platform Options
|
||||
The *QEMU RISC-V Virt Machine* platform does not have any platform-specific
|
||||
options.
|
||||
|
||||
Execution on QEMU RISC-V 64bit
|
||||
------------------------------
|
||||
Execution on QEMU RISC-V 64-bit
|
||||
-------------------------------
|
||||
|
||||
**No Payload Case**
|
||||
|
||||
Build:
|
||||
```
|
||||
make PLATFORM=qemu/virt
|
||||
make PLATFORM=generic
|
||||
```
|
||||
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv64 -M virt -m 256M -nographic \
|
||||
-kernel build/platform/qemu/virt/firmware/fw_payload.elf
|
||||
-kernel build/platform/generic/firmware/fw_payload.bin
|
||||
```
|
||||
|
||||
**U-Boot Payload**
|
||||
@@ -38,19 +38,19 @@ the `qemu-riscv64_smode_defconfig` configuration.
|
||||
|
||||
Build:
|
||||
```
|
||||
make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
|
||||
make PLATFORM=generic FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
|
||||
```
|
||||
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv64 -M virt -m 256M -nographic \
|
||||
-kernel build/platform/qemu/virt/firmware/fw_payload.elf
|
||||
-kernel build/platform/generic/firmware/fw_payload.elf
|
||||
```
|
||||
or
|
||||
```
|
||||
qemu-system-riscv64 -M virt -m 256M -nographic \
|
||||
-kernel build/platform/qemu/virt/firmware/fw_jump.elf \
|
||||
-device loader,file=<uboot_build_directory>/u-boot.bin,addr=0x80200000
|
||||
-bios build/platform/generic/firmware/fw_jump.bin \
|
||||
-kernel <uboot_build_directory>/u-boot.bin
|
||||
```
|
||||
|
||||
**Linux Kernel Payload**
|
||||
@@ -60,13 +60,13 @@ Note: We assume that the Linux kernel is compiled using
|
||||
|
||||
Build:
|
||||
```
|
||||
make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
||||
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
||||
```
|
||||
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv64 -M virt -m 256M -nographic \
|
||||
-kernel build/platform/qemu/virt/firmware/fw_payload.elf \
|
||||
-kernel build/platform/generic/firmware/fw_payload.elf \
|
||||
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
|
||||
-device virtio-blk-device,drive=hd0 \
|
||||
-append "root=/dev/vda rw console=ttyS0"
|
||||
@@ -74,28 +74,28 @@ qemu-system-riscv64 -M virt -m 256M -nographic \
|
||||
or
|
||||
```
|
||||
qemu-system-riscv64 -M virt -m 256M -nographic \
|
||||
-kernel build/platform/qemu/virt/firmware/fw_jump.elf \
|
||||
-device loader,file=<linux_build_directory>/arch/riscv/boot/Image,addr=0x80200000 \
|
||||
-bios build/platform/generic/firmware/fw_jump.bin \
|
||||
-kernel <linux_build_directory>/arch/riscv/boot/Image \
|
||||
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
|
||||
-device virtio-blk-device,drive=hd0 \
|
||||
-append "root=/dev/vda rw console=ttyS0"
|
||||
```
|
||||
|
||||
|
||||
Execution on QEMU RISC-V 32bit
|
||||
------------------------------
|
||||
Execution on QEMU RISC-V 32-bit
|
||||
-------------------------------
|
||||
|
||||
**No Payload Case**
|
||||
|
||||
Build:
|
||||
```
|
||||
make PLATFORM=qemu/virt
|
||||
make PLATFORM=generic PLATFORM_RISCV_XLEN=32
|
||||
```
|
||||
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv32 -M virt -m 256M -nographic \
|
||||
-kernel build/platform/qemu/virt/firmware/fw_payload.elf
|
||||
-kernel build/platform/generic/firmware/fw_payload.bin
|
||||
```
|
||||
|
||||
**U-Boot Payload**
|
||||
@@ -105,37 +105,35 @@ the `qemu-riscv32_smode_defconfig` configuration.
|
||||
|
||||
Build:
|
||||
```
|
||||
make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
|
||||
make PLATFORM=generic PLATFORM_RISCV_XLEN=32 FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
|
||||
```
|
||||
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv32 -M virt -m 256M -nographic \
|
||||
-kernel build/platform/qemu/virt/firmware/fw_payload.elf
|
||||
-kernel build/platform/generic/firmware/fw_payload.elf
|
||||
```
|
||||
or
|
||||
```
|
||||
qemu-system-riscv32 -M virt -m 256M -nographic \
|
||||
-kernel build/platform/qemu/virt/firmware/fw_jump.elf \
|
||||
-device loader,file=<uboot_build_directory>/u-boot.bin,addr=0x80400000
|
||||
-bios build/platform/generic/firmware/fw_jump.bin \
|
||||
-kernel <uboot_build_directory>/u-boot.bin
|
||||
```
|
||||
|
||||
**Linux Kernel Payload**
|
||||
|
||||
Note: We assume that the Linux kernel is compiled using
|
||||
*arch/riscv/configs/rv32_defconfig* (kernel 5.1 and newer)
|
||||
respectively using *arch/riscv/configs/defconfig* plus setting
|
||||
CONFIG_ARCH_RV32I=y (kernel 5.0 and older).
|
||||
*arch/riscv/configs/rv32_defconfig*.
|
||||
|
||||
Build:
|
||||
```
|
||||
make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
||||
make PLATFORM=generic PLATFORM_RISCV_XLEN=32 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
||||
```
|
||||
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv32 -M virt -m 256M -nographic \
|
||||
-kernel build/platform/qemu/virt/firmware/fw_payload.elf \
|
||||
-kernel build/platform/generic/firmware/fw_payload.elf \
|
||||
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
|
||||
-device virtio-blk-device,drive=hd0 \
|
||||
-append "root=/dev/vda rw console=ttyS0"
|
||||
@@ -143,10 +141,9 @@ qemu-system-riscv32 -M virt -m 256M -nographic \
|
||||
or
|
||||
```
|
||||
qemu-system-riscv32 -M virt -m 256M -nographic \
|
||||
-kernel build/platform/qemu/virt/firmware/fw_jump.elf \
|
||||
-device loader,file=<linux_build_directory>/arch/riscv/boot/Image,addr=0x80400000 \
|
||||
-bios build/platform/generic/firmware/fw_jump.bin \
|
||||
-kernel <linux_build_directory>/arch/riscv/boot/Image \
|
||||
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
|
||||
-device virtio-blk-device,drive=hd0 \
|
||||
-append "root=/dev/vda rw console=ttyS0"
|
||||
```
|
||||
|
||||
|
33
docs/platform/shakti_cclass.md
Normal file
33
docs/platform/shakti_cclass.md
Normal file
@@ -0,0 +1,33 @@
|
||||
Shakti C-class SoC Platform
|
||||
===========================
|
||||
C-Class is a member of the SHAKTI family of processors from
|
||||
Indian Institute of Technology - Madras (IIT-M).
|
||||
|
||||
It is an extremely configurable and commercial-grade 5-stage
|
||||
in-order core supporting the standard RV64GCSUN ISA extensions.
|
||||
|
||||
For more details, refer:
|
||||
* https://gitlab.com/shaktiproject/cores/c-class/blob/master/README.md
|
||||
* https://c-class.readthedocs.io/en/latest
|
||||
* https://shakti.org.in
|
||||
|
||||
Platform Options
|
||||
----------------
|
||||
|
||||
The *Shakti C-class SoC* platform does not have any platform-specific
|
||||
options.
|
||||
|
||||
Building Shakti C-class Platform
|
||||
--------------------------------
|
||||
|
||||
**Linux Kernel Payload**
|
||||
|
||||
```
|
||||
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_PAYLOAD_FDT_PATH=<shakti.dtb path>
|
||||
```
|
||||
|
||||
**Test Payload**
|
||||
|
||||
```
|
||||
make PLATFORM=generic FW_PAYLOAD_FDT_PATH=<shakti.dtb path>
|
||||
```
|
@@ -1,31 +1,26 @@
|
||||
SiFive FU540 SoC Platform
|
||||
==========================
|
||||
=========================
|
||||
The FU540-C000 is the world’s first 4+1 64-bit RISC-V SoC from SiFive.
|
||||
The HiFive Unleashed development platform is based on FU540-C000 and capable
|
||||
of running Linux.
|
||||
|
||||
With QEMU v4.2 or above release, the 'sifive_u' machine can be used to test
|
||||
OpenSBI image built for the real hardware as well.
|
||||
|
||||
To build platform specific library and firmwares, provide the
|
||||
*PLATFORM=sifive/fu540* parameter to the top level `make` command.
|
||||
|
||||
Platform Options
|
||||
----------------
|
||||
|
||||
As hart0 in the FU540 doesn't have an MMU, only harts 1-4 boot by default.
|
||||
A hart mask i.e. *FU540_ENABLED_HART_MASK* compile time option is provided
|
||||
to select any other hart for booting. Please keep in mind that this is not
|
||||
a generic option and it can only be specified for FU540 platform in the
|
||||
following way:
|
||||
|
||||
```
|
||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=Image FU540_ENABLED_HART_MASK=0x02
|
||||
```
|
||||
This will let the board boot only hart1 instead of default 1-4.
|
||||
The *SiFive FU540 SoC* platform does not have any platform-specific
|
||||
options.
|
||||
|
||||
Building SiFive Fu540 Platform
|
||||
-----------------------------
|
||||
------------------------------
|
||||
|
||||
In order to boot SMP Linux in U-Boot, Linux v5.1 (or higher) and latest
|
||||
U-Boot v2019.04 (or higher) should be used.
|
||||
U-Boot v2020.01 (or higher) should be used.
|
||||
|
||||
**Linux Kernel Payload**
|
||||
|
||||
@@ -46,63 +41,19 @@ make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/bo
|
||||
**U-Boot Payload**
|
||||
|
||||
The command-line example here assumes that U-Boot was compiled using the
|
||||
sifive_fu540_defconfig configuration and with U-Boot v2019.04 (or higher)
|
||||
having SMP support.
|
||||
sifive_fu540_defconfig configuration and with U-Boot v2020.01 (or higher).
|
||||
|
||||
To use U-Boot which follows Linux v5.2 (or higher) DT bindings, we will
|
||||
need custom U-Boot with required driver changes which can be found in
|
||||
riscv_unleashed_mmc_spi_v2 branch of https://github.com/avpatel/u-boot.git
|
||||
The detailed U-Boot booting guide is avaialble at [U-Boot].
|
||||
|
||||
```
|
||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin
|
||||
or
|
||||
(For U-Boot which follows Linux v5.2 (or higher) DT bindings)
|
||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin FW_PAYLOAD_FDT_PATH=<hifive-unleashed-a00.dtb path from Linux kernel>
|
||||
```
|
||||
|
||||
Generate the uImage from Linux Image.
|
||||
```
|
||||
mkimage -A riscv -O linux -T kernel -C none -a 0x80200000 -e 0x80200000 -n Linux -d \
|
||||
<linux_build_directory>/arch/riscv/boot/Image \
|
||||
<linux_build_directory>/arch/riscv/boot/uImage
|
||||
```
|
||||
|
||||
**U-Boot & Linux Kernel as a single payload**
|
||||
|
||||
A single monolithic image containing both U-Boot & Linux can also be used if
|
||||
network boot setup is not available.
|
||||
|
||||
1. Generate the uImage from Linux Image.
|
||||
```
|
||||
mkimage -A riscv -O linux -T kernel -C none -a 0x80200000 -e 0x80200000 -n Linux -d \
|
||||
<linux_build_directory>/arch/riscv/boot/Image \
|
||||
<linux_build_directory>/arch/riscv/boot/uImage
|
||||
```
|
||||
|
||||
2. Create a temporary image with u-boot.bin as the first payload. The
|
||||
command-line example here assumes that U-Boot was compiled using
|
||||
sifive_fu540_defconfig configuration.
|
||||
```
|
||||
dd if=~/workspace/u-boot-riscv/u-boot.bin of=/tmp/temp.bin bs=1M
|
||||
```
|
||||
3. Append the Linux Kernel image generated in step 1.
|
||||
```
|
||||
dd if=<linux_build_directory>/arch/riscv/boot/uImage of=/tmp/temp.bin bs=1M seek=4
|
||||
```
|
||||
4. Compile OpenSBI with temp.bin (generated in step 3) as payload.
|
||||
```
|
||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=/tmp/temp.bin
|
||||
or
|
||||
(For U-Boot which follows Linux v5.2 (or higher) DT bindings)
|
||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=/tmp/temp.bin FW_PAYLOAD_FDT_PATH=<hifive-unleashed-a00.dtb path from Linux kernel>
|
||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot-dtb.bin
|
||||
```
|
||||
|
||||
Flashing the OpenSBI firmware binary to storage media:
|
||||
-----------------------------------------------------
|
||||
The first stage boot loader([FSBL](https://github.com/sifive/freedom-u540-c000-bootloader))
|
||||
expects the storage media to have a GPT partition table. It tries to look for
|
||||
a partition with following GUID to load the next stage boot loader (OpenSBI
|
||||
in this case).
|
||||
------------------------------------------------------
|
||||
The first stage boot loader ([FSBL]) expects the storage media to have a GPT
|
||||
partition table. It tries to look for a partition with following GUID to load
|
||||
the next stage boot loader (OpenSBI in this case).
|
||||
|
||||
```
|
||||
2E54B353-1271-4842-806F-E436D6AF6985
|
||||
@@ -142,39 +93,32 @@ As U-Boot image is used as payload, HiFive Unleashed will boot into a U-Boot
|
||||
prompt. U-Boot tftp boot method can be used to load kernel image in U-Boot
|
||||
prompt. Here are the steps do a tftpboot.
|
||||
|
||||
1. Set the mac address of the board.
|
||||
```
|
||||
setenv ethaddr <mac address of the board>
|
||||
```
|
||||
(Note: This step is optional)
|
||||
|
||||
2. Set the ip address of the board.
|
||||
1. Set the ip address of the board.
|
||||
```
|
||||
setenv ipaddr <ipaddr of the board>
|
||||
```
|
||||
|
||||
3. Set the tftpboot server IP.
|
||||
2. Set the tftpboot server IP.
|
||||
```
|
||||
setenv serverip <ipaddr of the tftp server>
|
||||
```
|
||||
|
||||
4. Set the network gateway address.
|
||||
3. Set the network gateway address.
|
||||
```
|
||||
setenv gatewayip <ipaddress of the network gateway>
|
||||
```
|
||||
|
||||
5. Load the Linux kernel image from the tftp server.
|
||||
4. Load the Linux kernel image from the tftp server.
|
||||
```
|
||||
tftpboot ${kernel_addr_r} <uImage path in tftpboot directory>
|
||||
tftpboot ${kernel_addr_r} <Image path in tftpboot directory>
|
||||
```
|
||||
|
||||
6. Load the ramdisk image from the tftp server. This is only required if
|
||||
5. Load the ramdisk image from the tftp server. This is only required if
|
||||
ramdisk is loaded from tftp server. This step is optional, if rootfs is
|
||||
already part of the kernel or loaded from an external storage by kernel.
|
||||
```
|
||||
tftpboot ${ramdisk_addr_r} <ramdisk path in tftpboot directory>
|
||||
```
|
||||
|
||||
6. Load the pre-compiled device tree via tftpboot.
|
||||
```
|
||||
tftpboot ${fdt_addr_r} <hifive-unleashed-a00.dtb path in tftpboot directory>
|
||||
```
|
||||
7. Set the boot command-line arguments.
|
||||
```
|
||||
setenv bootargs "root=<root partition> rw console=ttySIF0 earlycon=sbi"
|
||||
@@ -183,13 +127,12 @@ setenv bootargs "root=<root partition> rw console=ttySIF0 earlycon=sbi"
|
||||
** /dev/ram ** - If a ramdisk is used
|
||||
** root=/dev/mmcblk0pX ** - If a rootfs is already on some other partition
|
||||
of sdcard)
|
||||
|
||||
8. Now boot into Linux.
|
||||
```
|
||||
bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdtcontroladdr}
|
||||
booti ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}
|
||||
or
|
||||
(If ramdisk is not loaded from network)
|
||||
bootm ${kernel_addr_r} - ${fdtcontroladdr}
|
||||
booti ${kernel_addr_r} - ${fdt_addr_r}
|
||||
```
|
||||
|
||||
**U-Boot & Linux Kernel as a single payload**
|
||||
@@ -197,5 +140,31 @@ bootm ${kernel_addr_r} - ${fdtcontroladdr}
|
||||
At U-Boot prompt execute the following boot command to boot Linux.
|
||||
|
||||
```
|
||||
bootm ${kernel_addr_r} - ${fdtcontroladdr}
|
||||
booti ${kernel_addr_r} - ${fdt_addr_r}
|
||||
```
|
||||
|
||||
QEMU Specific Instructions
|
||||
--------------------------
|
||||
If you want to test OpenSBI with QEMU 'sifive_u' machine, please follow the
|
||||
same instructions above, with the exception of not passing FW_PAYLOAD_FDT_PATH.
|
||||
|
||||
This is because QEMU generates a device tree blob on the fly based on the
|
||||
command line parameters and it's compatible with the one used in the upstream
|
||||
Linux kernel.
|
||||
|
||||
When U-Boot v2020.01 (or higher) is used as the payload, as the SiFive FU540
|
||||
DTB for the real hardware is embedded in U-Boot binary itself, due to the same
|
||||
reason above, we need to switch the U-Boot sifive_fu540_defconfig configuration
|
||||
from CONFIG_OF_SEPARATE to CONFIG_OF_PRIOR_STAGE so that U-Boot uses the DTB
|
||||
generated by QEMU, and u-boot.bin should be used as the payload image, like:
|
||||
|
||||
```
|
||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin
|
||||
```
|
||||
|
||||
While the real hardware operates at the 64-bit mode, it's possible for QEMU to
|
||||
test the 32-bit OpenSBI firmware. This can be helpful for testing 32-bit SiFive
|
||||
specific drivers.
|
||||
|
||||
[U-Boot]: https://gitlab.denx.de/u-boot/u-boot/blob/master/doc/board/sifive/fu540.rst
|
||||
[FSBL]: https://github.com/sifive/freedom-u540-c000-bootloader
|
||||
|
89
docs/platform/spike.md
Normal file
89
docs/platform/spike.md
Normal file
@@ -0,0 +1,89 @@
|
||||
Spike Simulator Platform
|
||||
========================
|
||||
|
||||
The **Spike** is a RISC-V ISA simulator which implements a functional model
|
||||
of one or more RISC-V harts. The **Spike** compatible virtual platform is
|
||||
also available on QEMU. In fact, we can use same OpenSBI firmware binaries
|
||||
on **Spike** simulator and QEMU Spike machine.
|
||||
|
||||
For more details, refer [Spike on GitHub](https://github.com/riscv/riscv-isa-sim)
|
||||
|
||||
To build the platform-specific library and firmware images, provide the
|
||||
*PLATFORM=generic* parameter to the top level `make` command.
|
||||
|
||||
Platform Options
|
||||
----------------
|
||||
|
||||
The *Spike* platform does not have any platform-specific options.
|
||||
|
||||
Execution on Spike Simulator
|
||||
----------------------------
|
||||
|
||||
**No Payload Case**
|
||||
|
||||
Build:
|
||||
```
|
||||
make PLATFORM=generic
|
||||
```
|
||||
|
||||
Run:
|
||||
```
|
||||
spike build/platform/generic/firmware/fw_payload.elf
|
||||
```
|
||||
|
||||
**Linux Kernel Payload**
|
||||
|
||||
Note: We assume that the Linux kernel is compiled using
|
||||
*arch/riscv/configs/defconfig*.
|
||||
|
||||
Build:
|
||||
```
|
||||
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
||||
```
|
||||
|
||||
Run:
|
||||
```
|
||||
spike --initrd <path_to_cpio_ramdisk> build/platform/generic/firmware/fw_payload.elf
|
||||
```
|
||||
|
||||
Execution on QEMU RISC-V 64-bit
|
||||
-------------------------------
|
||||
|
||||
**No Payload Case**
|
||||
|
||||
Build:
|
||||
```
|
||||
make PLATFORM=generic
|
||||
```
|
||||
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv64 -M spike -m 256M -nographic \
|
||||
-kernel build/platform/generic/firmware/fw_payload.elf
|
||||
```
|
||||
|
||||
**Linux Kernel Payload**
|
||||
|
||||
Note: We assume that the Linux kernel is compiled using
|
||||
*arch/riscv/configs/defconfig*.
|
||||
|
||||
Build:
|
||||
```
|
||||
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
||||
```
|
||||
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv64 -M spike -m 256M -nographic \
|
||||
-kernel build/platform/generic/firmware/fw_payload.elf \
|
||||
-initrd <path_to_cpio_ramdisk> \
|
||||
-append "root=/dev/ram rw console=hvc0 earlycon=sbi"
|
||||
```
|
||||
or
|
||||
```
|
||||
qemu-system-riscv64 -M spike -m 256M -nographic \
|
||||
-bios build/platform/generic/firmware/fw_jump.elf \
|
||||
-kernel <linux_build_directory>/arch/riscv/boot/Image \
|
||||
-initrd <path_to_cpio_ramdisk> \
|
||||
-append "root=/dev/ram rw console=hvc0 earlycon=sbi"
|
||||
```
|
34
docs/platform/thead-c910.md
Normal file
34
docs/platform/thead-c910.md
Normal file
@@ -0,0 +1,34 @@
|
||||
T-HEAD C910 Processor
|
||||
=====================
|
||||
C910 is a 12-stage, 3 issues, 8 executions, out-of-order 64-bit RISC-V CPU which
|
||||
supports 16 cores, runs with 2.5GHz, and is capable of running Linux.
|
||||
|
||||
To build platform specific library and firmwares, provide the
|
||||
*PLATFORM=thead/c910* parameter to the top level make command.
|
||||
|
||||
Platform Options
|
||||
----------------
|
||||
|
||||
The *T-HEAD C910* platform does not have any platform-specific options.
|
||||
|
||||
Building T-HEAD C910 Platform
|
||||
-----------------------------
|
||||
|
||||
```
|
||||
make PLATFORM=thead/c910
|
||||
```
|
||||
|
||||
Booting T-HEAD C910 Platform
|
||||
----------------------------
|
||||
|
||||
**No Payload**
|
||||
|
||||
As there's no payload, you may download vmlinux or u-boot to FW_JUMP_ADDR which
|
||||
specified in config.mk or compile commands with GDB. And the execution flow will
|
||||
turn to vmlinux or u-boot when opensbi ends.
|
||||
|
||||
**Linux Kernel Payload**
|
||||
|
||||
You can also choose to use Linux kernel as payload by enabling FW_PAYLOAD=y
|
||||
along with specifying FW_PAYLOAD_OFFSET. The kernel image will be embedded in
|
||||
the OPENSBI firmware binary, T-head will directly boot into Linux after OpenSBI.
|
44
docs/platform_requirements.md
Normal file
44
docs/platform_requirements.md
Normal file
@@ -0,0 +1,44 @@
|
||||
OpenSBI Platform Requirements
|
||||
=============================
|
||||
|
||||
The RISC-V platform requirements for OpenSBI can change over time
|
||||
with advances in RISC-V specifications and ecosystem.
|
||||
|
||||
To handle this, we have two types of RISC-V platform requirements:
|
||||
|
||||
1. **Base platform requirements** which apply to all OpenSBI releases
|
||||
2. **Release specific platform requirements** which apply to a OpenSBI
|
||||
release and later releases
|
||||
|
||||
Currently, we don't have any **Release specific platform requirements**
|
||||
but such platform requirements will be added in future.
|
||||
|
||||
Base Platform Requirements
|
||||
--------------------------
|
||||
|
||||
The base RISC-V platform requirements for OpenSBI are as follows:
|
||||
|
||||
1. At least rv32ima or rv64ima required on all HARTs
|
||||
2. At least one HART should have S-mode support because:
|
||||
|
||||
* SBI calls are meant for RISC-V S-mode (Supervisor mode)
|
||||
* OpenSBI implements SBI calls for S-mode software
|
||||
|
||||
3. The MTVEC CSR on all HARTs must support direct mode
|
||||
4. The PMP CSRs are optional. If PMP CSRs are not implemented then
|
||||
OpenSBI cannot protect M-mode firmware and secured memory regions
|
||||
5. The TIME CSR is optional. If TIME CSR is not implemented in
|
||||
hardware then a 64-bit MMIO counter is required to track time
|
||||
and emulate TIME CSR
|
||||
6. Hardware support for injecting M-mode software interrupts on
|
||||
a multi-HART platform
|
||||
|
||||
The RISC-V extensions not covered by rv32ima or rv64ima are optional
|
||||
for OpenSBI. Although, OpenSBI will detect and handle some of these
|
||||
optional RISC-V extensions at runtime.
|
||||
|
||||
The optional RISC-V extensions handled by OpenSBI at runtime are:
|
||||
|
||||
* D-extension: Double precision floating point
|
||||
* F-extension: Single precision floating point
|
||||
* H-extension: Hypervisor
|
@@ -13,6 +13,9 @@
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
|
||||
#define BOOT_STATUS_RELOCATE_DONE 1
|
||||
#define BOOT_STATUS_BOOT_HART_DONE 2
|
||||
|
||||
.macro MOV_3R __d0, __s0, __d1, __s1, __d2, __s2
|
||||
add \__d0, \__s0, zero
|
||||
add \__d1, \__s1, zero
|
||||
@@ -38,17 +41,26 @@
|
||||
999:
|
||||
.endm
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _start
|
||||
.globl _start_warm
|
||||
_start:
|
||||
/*
|
||||
* Jump to warm-boot if this is not the first core booting,
|
||||
* that is, for mhartid != 0
|
||||
*/
|
||||
csrr a6, CSR_MHARTID
|
||||
blt zero, a6, _wait_relocate_copy_done
|
||||
/* Find preferred boot HART id */
|
||||
MOV_3R s0, a0, s1, a1, s2, a2
|
||||
call fw_boot_hart
|
||||
add a6, a0, zero
|
||||
MOV_3R a0, s0, a1, s1, a2, s2
|
||||
li a7, -1
|
||||
beq a6, a7, _try_lottery
|
||||
/* Jump to relocation wait loop if we are not boot hart */
|
||||
bne a0, a6, _wait_relocate_copy_done
|
||||
_try_lottery:
|
||||
/* Jump to relocation wait loop if we don't get relocation lottery */
|
||||
la a6, _relocate_lottery
|
||||
li a7, 1
|
||||
amoadd.w a6, a7, (a6)
|
||||
bnez a6, _wait_relocate_copy_done
|
||||
|
||||
/* Save load address */
|
||||
la t0, _load_start
|
||||
@@ -72,6 +84,8 @@ _relocate:
|
||||
blt t2, t0, _relocate_copy_to_upper
|
||||
_relocate_copy_to_lower:
|
||||
ble t1, t2, _relocate_copy_to_lower_loop
|
||||
la t3, _relocate_lottery
|
||||
BRANGE t2, t1, t3, _start_hang
|
||||
la t3, _boot_status
|
||||
BRANGE t2, t1, t3, _start_hang
|
||||
la t3, _relocate
|
||||
@@ -88,6 +102,8 @@ _relocate_copy_to_lower_loop:
|
||||
jr t4
|
||||
_relocate_copy_to_upper:
|
||||
ble t3, t0, _relocate_copy_to_upper_loop
|
||||
la t2, _relocate_lottery
|
||||
BRANGE t0, t3, t2, _start_hang
|
||||
la t2, _boot_status
|
||||
BRANGE t0, t3, t2, _start_hang
|
||||
la t2, _relocate
|
||||
@@ -108,26 +124,33 @@ _wait_relocate_copy_done:
|
||||
REG_L t1, 0(t1)
|
||||
beq t0, t1, _wait_for_boot_hart
|
||||
la t2, _boot_status
|
||||
sub t2, t2, t0
|
||||
add t2, t2, t1
|
||||
la t3, _wait_for_boot_hart
|
||||
sub t3, t3, t0
|
||||
add t3, t3, t1
|
||||
1:
|
||||
/* waitting for relocate copy done (_boot_status == 1) */
|
||||
li t4, 1
|
||||
li t4, BOOT_STATUS_RELOCATE_DONE
|
||||
REG_L t5, 0(t2)
|
||||
/* Reduce the bus traffic so that boot hart may proceed faster */
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
bne t4, t5, 1b
|
||||
bgt t4, t5, 1b
|
||||
jr t3
|
||||
_relocate_done:
|
||||
|
||||
/* mark relocate copy done */
|
||||
/*
|
||||
* Mark relocate copy done
|
||||
* Use _boot_status copy relative to the load address
|
||||
*/
|
||||
la t0, _boot_status
|
||||
li t1, 1
|
||||
la t1, _link_start
|
||||
REG_L t1, 0(t1)
|
||||
la t2, _load_start
|
||||
REG_L t2, 0(t2)
|
||||
sub t0, t0, t1
|
||||
add t0, t0, t2
|
||||
li t1, BOOT_STATUS_RELOCATE_DONE
|
||||
REG_S t1, 0(t0)
|
||||
fence rw, rw
|
||||
|
||||
@@ -137,11 +160,48 @@ _relocate_done:
|
||||
li ra, 0
|
||||
call _reset_regs
|
||||
|
||||
/* Zero-out BSS */
|
||||
la s4, _bss_start
|
||||
la s5, _bss_end
|
||||
_bss_zero:
|
||||
REG_S zero, (s4)
|
||||
add s4, s4, __SIZEOF_POINTER__
|
||||
blt s4, s5, _bss_zero
|
||||
|
||||
/* Setup temporary trap handler */
|
||||
la s4, _start_hang
|
||||
csrw CSR_MTVEC, s4
|
||||
|
||||
/* Setup temporary stack */
|
||||
la s4, _fw_end
|
||||
li s5, (SBI_SCRATCH_SIZE * 2)
|
||||
add sp, s4, s5
|
||||
|
||||
/* Allow main firmware to save info */
|
||||
MOV_5R s0, a0, s1, a1, s2, a2, s3, a3, s4, a4
|
||||
call fw_save_info
|
||||
MOV_5R a0, s0, a1, s1, a2, s2, a3, s3, a4, s4
|
||||
|
||||
/* Override previous arg1 */
|
||||
MOV_3R s0, a0, s1, a1, s2, a2
|
||||
call fw_prev_arg1
|
||||
add t1, a0, zero
|
||||
MOV_3R a0, s0, a1, s1, a2, s2
|
||||
beqz t1, _prev_arg1_override_done
|
||||
add a1, t1, zero
|
||||
_prev_arg1_override_done:
|
||||
|
||||
/*
|
||||
* Initialize platform
|
||||
* Note: The a0 to a4 registers passed to the
|
||||
* firmware are parameters to this function.
|
||||
*/
|
||||
MOV_5R s0, a0, s1, a1, s2, a2, s3, a3, s4, a4
|
||||
call fw_platform_init
|
||||
add t0, a0, zero
|
||||
MOV_5R a0, s0, a1, s1, a2, s2, a3, s3, a4, s4
|
||||
add a1, t0, zero
|
||||
|
||||
/* Preload HART details
|
||||
* s7 -> HART Count
|
||||
* s8 -> HART Stack Size
|
||||
@@ -210,35 +270,16 @@ _scratch_init:
|
||||
/* Store firmware options in scratch space */
|
||||
MOV_3R s0, a0, s1, a1, s2, a2
|
||||
#ifdef FW_OPTIONS
|
||||
li a4, FW_OPTIONS
|
||||
li a0, FW_OPTIONS
|
||||
#else
|
||||
add a4, zero, zero
|
||||
#endif
|
||||
call fw_options
|
||||
or a4, a4, a0
|
||||
REG_S a4, SBI_SCRATCH_OPTIONS_OFFSET(tp)
|
||||
#endif
|
||||
REG_S a0, SBI_SCRATCH_OPTIONS_OFFSET(tp)
|
||||
MOV_3R a0, s0, a1, s1, a2, s2
|
||||
/* Move to next scratch space */
|
||||
add t1, t1, t2
|
||||
blt t1, s7, _scratch_init
|
||||
|
||||
/* Zero-out BSS */
|
||||
la a4, _bss_start
|
||||
la a5, _bss_end
|
||||
_bss_zero:
|
||||
REG_S zero, (a4)
|
||||
add a4, a4, __SIZEOF_POINTER__
|
||||
blt a4, a5, _bss_zero
|
||||
|
||||
/* Override pervious arg1 */
|
||||
MOV_3R s0, a0, s1, a1, s2, a2
|
||||
call fw_prev_arg1
|
||||
add t1, a0, zero
|
||||
MOV_3R a0, s0, a1, s1, a2, s2
|
||||
beqz t1, _prev_arg1_override_done
|
||||
add a1, t1, zero
|
||||
_prev_arg1_override_done:
|
||||
|
||||
/*
|
||||
* Relocate Flatened Device Tree (FDT)
|
||||
* source FDT address = previous arg1
|
||||
@@ -302,15 +343,15 @@ _fdt_reloc_again:
|
||||
_fdt_reloc_done:
|
||||
|
||||
/* mark boot hart done */
|
||||
li t0, 2
|
||||
li t0, BOOT_STATUS_BOOT_HART_DONE
|
||||
la t1, _boot_status
|
||||
REG_S t0, 0(t1)
|
||||
fence rw, rw
|
||||
j _start_warm
|
||||
|
||||
/* waitting for boot hart done (_boot_status == 2) */
|
||||
/* waiting for boot hart to be done (_boot_status == 2) */
|
||||
_wait_for_boot_hart:
|
||||
li t0, 2
|
||||
li t0, BOOT_STATUS_BOOT_HART_DONE
|
||||
la t1, _boot_status
|
||||
REG_L t1, 0(t1)
|
||||
/* Reduce the bus traffic so that boot hart may proceed faster */
|
||||
@@ -328,6 +369,7 @@ _start_warm:
|
||||
csrw CSR_MIE, zero
|
||||
csrw CSR_MIP, zero
|
||||
|
||||
/* Find HART count and HART stack size */
|
||||
la a4, platform
|
||||
#if __riscv_xlen == 64
|
||||
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
|
||||
@@ -336,12 +378,29 @@ _start_warm:
|
||||
lw s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
|
||||
lw s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
|
||||
#endif
|
||||
REG_L s9, SBI_PLATFORM_HART_INDEX2ID_OFFSET(a4)
|
||||
|
||||
/* HART ID should be within expected limit */
|
||||
/* Find HART id */
|
||||
csrr s6, CSR_MHARTID
|
||||
bge s6, s7, _start_hang
|
||||
|
||||
/* find the scratch space for this hart */
|
||||
/* Find HART index */
|
||||
beqz s9, 3f
|
||||
li a4, 0
|
||||
1:
|
||||
#if __riscv_xlen == 64
|
||||
lwu a5, (s9)
|
||||
#else
|
||||
lw a5, (s9)
|
||||
#endif
|
||||
beq a5, s6, 2f
|
||||
add s9, s9, 4
|
||||
add a4, a4, 1
|
||||
blt a4, s7, 1b
|
||||
li a4, -1
|
||||
2: add s6, a4, zero
|
||||
3: bge s6, s7, _start_hang
|
||||
|
||||
/* Find the scratch space based on HART index */
|
||||
la tp, _fw_end
|
||||
mul a5, s7, s8
|
||||
add tp, tp, a5
|
||||
@@ -359,9 +418,6 @@ _start_warm:
|
||||
/* Setup trap handler */
|
||||
la a4, _trap_handler
|
||||
csrw CSR_MTVEC, a4
|
||||
/* Make sure that mtvec is updated */
|
||||
1: csrr a5, CSR_MTVEC
|
||||
bne a4, a5, 1b
|
||||
|
||||
/* Initialize SBI runtime */
|
||||
csrr a0, CSR_MSCRATCH
|
||||
@@ -371,6 +427,8 @@ _start_warm:
|
||||
j _start_hang
|
||||
|
||||
.align 3
|
||||
_relocate_lottery:
|
||||
RISCV_PTR 0
|
||||
_boot_status:
|
||||
RISCV_PTR 0
|
||||
_load_start:
|
||||
@@ -380,50 +438,50 @@ _link_start:
|
||||
_link_end:
|
||||
RISCV_PTR _fw_reloc_end
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _hartid_to_scratch
|
||||
_hartid_to_scratch:
|
||||
add sp, sp, -(3 * __SIZEOF_POINTER__)
|
||||
REG_S s0, (sp)
|
||||
REG_S s1, (__SIZEOF_POINTER__)(sp)
|
||||
REG_S s2, (__SIZEOF_POINTER__ * 2)(sp)
|
||||
/*
|
||||
* a0 -> HART ID (passed by caller)
|
||||
* s0 -> HART Stack Size
|
||||
* s1 -> HART Stack End
|
||||
* s2 -> Temporary
|
||||
* a1 -> HART Index (passed by caller)
|
||||
* t0 -> HART Stack Size
|
||||
* t1 -> HART Stack End
|
||||
* t2 -> Temporary
|
||||
*/
|
||||
la s2, platform
|
||||
la t2, platform
|
||||
#if __riscv_xlen == 64
|
||||
lwu s0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(s2)
|
||||
lwu s2, SBI_PLATFORM_HART_COUNT_OFFSET(s2)
|
||||
lwu t0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(t2)
|
||||
lwu t2, SBI_PLATFORM_HART_COUNT_OFFSET(t2)
|
||||
#else
|
||||
lw s0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(s2)
|
||||
lw s2, SBI_PLATFORM_HART_COUNT_OFFSET(s2)
|
||||
lw t0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(t2)
|
||||
lw t2, SBI_PLATFORM_HART_COUNT_OFFSET(t2)
|
||||
#endif
|
||||
mul s2, s2, s0
|
||||
la s1, _fw_end
|
||||
add s1, s1, s2
|
||||
mul s2, s0, a0
|
||||
sub s1, s1, s2
|
||||
li s2, SBI_SCRATCH_SIZE
|
||||
sub a0, s1, s2
|
||||
REG_L s0, (sp)
|
||||
REG_L s1, (__SIZEOF_POINTER__)(sp)
|
||||
REG_L s2, (__SIZEOF_POINTER__ * 2)(sp)
|
||||
add sp, sp, (3 * __SIZEOF_POINTER__)
|
||||
sub t2, t2, a1
|
||||
mul t2, t2, t0
|
||||
la t1, _fw_end
|
||||
add t1, t1, t2
|
||||
li t2, SBI_SCRATCH_SIZE
|
||||
sub a0, t1, t2
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _start_hang
|
||||
_start_hang:
|
||||
wfi
|
||||
j _start_hang
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl fw_platform_init
|
||||
.weak fw_platform_init
|
||||
fw_platform_init:
|
||||
add a0, a1, zero
|
||||
ret
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _trap_handler
|
||||
_trap_handler:
|
||||
/* Swap TP and MSCRATCH */
|
||||
@@ -476,6 +534,16 @@ _trap_handler_all_mode:
|
||||
REG_S t0, SBI_TRAP_REGS_OFFSET(mepc)(sp)
|
||||
csrr t0, CSR_MSTATUS
|
||||
REG_S t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
|
||||
REG_S zero, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
|
||||
#if __riscv_xlen == 32
|
||||
csrr t0, CSR_MISA
|
||||
srli t0, t0, ('H' - 'A')
|
||||
andi t0, t0, 0x1
|
||||
beq t0, zero, _skip_mstatush_save
|
||||
csrr t0, CSR_MSTATUSH
|
||||
REG_S t0, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
|
||||
_skip_mstatush_save:
|
||||
#endif
|
||||
|
||||
/* Save all general regisers except SP and T0 */
|
||||
REG_S zero, SBI_TRAP_REGS_OFFSET(zero)(sp)
|
||||
@@ -511,7 +579,6 @@ _trap_handler_all_mode:
|
||||
|
||||
/* Call C routine */
|
||||
add a0, sp, zero
|
||||
csrr a1, CSR_MSCRATCH
|
||||
call sbi_trap_handler
|
||||
|
||||
/* Restore all general regisers except SP and T0 */
|
||||
@@ -550,6 +617,15 @@ _trap_handler_all_mode:
|
||||
csrw CSR_MEPC, t0
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
|
||||
csrw CSR_MSTATUS, t0
|
||||
#if __riscv_xlen == 32
|
||||
csrr t0, CSR_MISA
|
||||
srli t0, t0, ('H' - 'A')
|
||||
andi t0, t0, 0x1
|
||||
beq t0, zero, _skip_mstatush_restore
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
|
||||
csrw CSR_MSTATUSH, t0
|
||||
_skip_mstatush_restore:
|
||||
#endif
|
||||
|
||||
/* Restore T0 */
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(t0)(sp)
|
||||
@@ -559,8 +635,8 @@ _trap_handler_all_mode:
|
||||
|
||||
mret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _reset_regs
|
||||
_reset_regs:
|
||||
|
||||
|
@@ -11,14 +11,40 @@
|
||||
|
||||
#include "fw_base.S"
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
_bad_dynamic_info:
|
||||
wfi
|
||||
j _bad_dynamic_info
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_boot_hart
|
||||
/*
|
||||
* This function is called very early even before
|
||||
* fw_save_info() is called.
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
* The boot HART id should be returned in 'a0'.
|
||||
*/
|
||||
fw_boot_hart:
|
||||
/* Sanity checks */
|
||||
li a1, FW_DYNAMIC_INFO_MAGIC_VALUE
|
||||
REG_L a0, FW_DYNAMIC_INFO_MAGIC_OFFSET(a2)
|
||||
bne a0, a1, _bad_dynamic_info
|
||||
li a1, FW_DYNAMIC_INFO_VERSION_MAX
|
||||
REG_L a0, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
|
||||
bgt a0, a1, _bad_dynamic_info
|
||||
|
||||
/* Read boot HART id */
|
||||
li a1, 0x2
|
||||
blt a0, a1, 2f
|
||||
REG_L a0, FW_DYNAMIC_INFO_BOOT_HART_OFFSET(a2)
|
||||
ret
|
||||
2: li a0, -1
|
||||
ret
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_save_info
|
||||
/*
|
||||
* We can only use a0, a1, a2, a3, and a4 registers here.
|
||||
@@ -27,14 +53,19 @@ _bad_dynamic_info:
|
||||
* Nothing to be returned here.
|
||||
*/
|
||||
fw_save_info:
|
||||
/* Save next arg1 in 'a1' */
|
||||
la a4, _dynamic_next_arg1
|
||||
REG_S a1, (a4)
|
||||
|
||||
/* Sanity checks */
|
||||
li a4, FW_DYNAMIC_INFO_MAGIC_VALUE
|
||||
REG_L a3, FW_DYNAMIC_INFO_MAGIC_OFFSET(a2)
|
||||
bne a3, a4, _bad_dynamic_info
|
||||
li a4, FW_DYNAMIC_INFO_VERSION_MAX
|
||||
REG_L a3, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
|
||||
bgt a3, a4, _bad_dynamic_info
|
||||
|
||||
/* Save version == 0x1 fields */
|
||||
la a4, _dynamic_next_addr
|
||||
REG_L a3, FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET(a2)
|
||||
REG_S a3, (a4)
|
||||
@@ -44,24 +75,37 @@ fw_save_info:
|
||||
la a4, _dynamic_options
|
||||
REG_L a3, FW_DYNAMIC_INFO_OPTIONS_OFFSET(a2)
|
||||
REG_S a3, (a4)
|
||||
|
||||
/* Save version == 0x2 fields */
|
||||
li a4, 0x2
|
||||
REG_L a3, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
|
||||
blt a3, a4, 2f
|
||||
la a4, _dynamic_boot_hart
|
||||
REG_L a3, FW_DYNAMIC_INFO_BOOT_HART_OFFSET(a2)
|
||||
REG_S a3, (a4)
|
||||
2:
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_prev_arg1
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
* The a0, a1, and a2 registers will be same as passed by
|
||||
* previous booting stage.
|
||||
* The previous arg1 should be returned in 'a0'.
|
||||
*/
|
||||
fw_prev_arg1:
|
||||
add a0, zero, zero
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_arg1
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
* The a0, a1, and a2 registers will be same as passed by
|
||||
* previous booting stage.
|
||||
* The next arg1 should be returned in 'a0'.
|
||||
*/
|
||||
fw_next_arg1:
|
||||
@@ -69,8 +113,8 @@ fw_next_arg1:
|
||||
REG_L a0, (a0)
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_addr
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
@@ -81,8 +125,8 @@ fw_next_addr:
|
||||
REG_L a0, (a0)
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_mode
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
@@ -93,8 +137,8 @@ fw_next_mode:
|
||||
REG_L a0, (a0)
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_options
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
@@ -106,8 +150,8 @@ fw_options:
|
||||
REG_L a0, (a0)
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
_dynamic_next_arg1:
|
||||
RISCV_PTR 0x0
|
||||
_dynamic_next_addr:
|
||||
@@ -116,3 +160,5 @@ _dynamic_next_mode:
|
||||
RISCV_PTR PRV_S
|
||||
_dynamic_options:
|
||||
RISCV_PTR 0x0
|
||||
_dynamic_boot_hart:
|
||||
RISCV_PTR -1
|
||||
|
@@ -9,8 +9,21 @@
|
||||
|
||||
#include "fw_base.S"
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_boot_hart
|
||||
/*
|
||||
* This function is called very early even before
|
||||
* fw_save_info() is called.
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
* The boot HART id should be returned in 'a0'.
|
||||
*/
|
||||
fw_boot_hart:
|
||||
li a0, -1
|
||||
ret
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_save_info
|
||||
/*
|
||||
* We can only use a0, a1, a2, a3, and a4 registers here.
|
||||
@@ -21,34 +34,38 @@
|
||||
fw_save_info:
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_prev_arg1
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
* The a0, a1, and a2 registers will be same as passed by
|
||||
* previous booting stage.
|
||||
* The previous arg1 should be returned in 'a0'.
|
||||
*/
|
||||
fw_prev_arg1:
|
||||
add a0, zero, zero
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_arg1
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
* The a0, a1, and a2 registers will be same as passed by
|
||||
* previous booting stage.
|
||||
* The next arg1 should be returned in 'a0'.
|
||||
*/
|
||||
fw_next_arg1:
|
||||
#ifdef FW_JUMP_FDT_ADDR
|
||||
li a0, FW_JUMP_FDT_ADDR
|
||||
#else
|
||||
add a0, zero, zero
|
||||
add a0, a1, zero
|
||||
#endif
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_addr
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
@@ -59,8 +76,8 @@ fw_next_addr:
|
||||
REG_L a0, (a0)
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_mode
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
@@ -70,8 +87,8 @@ fw_next_mode:
|
||||
li a0, PRV_S
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_options
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
@@ -86,7 +103,7 @@ fw_options:
|
||||
#error "Must define FW_JUMP_ADDR"
|
||||
#endif
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
_jump_addr:
|
||||
RISCV_PTR FW_JUMP_ADDR
|
||||
|
@@ -9,8 +9,21 @@
|
||||
|
||||
#include "fw_base.S"
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_boot_hart
|
||||
/*
|
||||
* This function is called very early even before
|
||||
* fw_save_info() is called.
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
* The boot HART id should be returned in 'a0'.
|
||||
*/
|
||||
fw_boot_hart:
|
||||
li a0, -1
|
||||
ret
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_save_info
|
||||
/*
|
||||
* We can only use a0, a1, a2, a3, and a4 registers here.
|
||||
@@ -21,11 +34,13 @@
|
||||
fw_save_info:
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_prev_arg1
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
* The a0, a1, and a2 registers will be same as passed by
|
||||
* previous booting stage.
|
||||
* The previous arg1 should be returned in 'a0'.
|
||||
*/
|
||||
fw_prev_arg1:
|
||||
@@ -36,23 +51,25 @@ fw_prev_arg1:
|
||||
#endif
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_arg1
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
* The a0, a1, and a2 registers will be same as passed by
|
||||
* previous booting stage.
|
||||
* The next arg1 should be returned in 'a0'.
|
||||
*/
|
||||
fw_next_arg1:
|
||||
#ifdef FW_PAYLOAD_FDT_ADDR
|
||||
li a0, FW_PAYLOAD_FDT_ADDR
|
||||
#else
|
||||
add a0, zero, zero
|
||||
add a0, a1, zero
|
||||
#endif
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_addr
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
@@ -62,8 +79,8 @@ fw_next_addr:
|
||||
la a0, payload_bin
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_mode
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
@@ -73,8 +90,8 @@ fw_next_mode:
|
||||
li a0, PRV_S
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_options
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
@@ -86,15 +103,15 @@ fw_options:
|
||||
ret
|
||||
|
||||
#ifdef FW_PAYLOAD_FDT_PATH
|
||||
.align 4
|
||||
.section .text, "ax", %progbits
|
||||
.align 4
|
||||
.globl fdt_bin
|
||||
fdt_bin:
|
||||
.incbin FW_PAYLOAD_FDT_PATH
|
||||
#endif
|
||||
|
||||
.align 4
|
||||
.section .payload, "ax", %progbits
|
||||
.align 4
|
||||
.globl payload_bin
|
||||
payload_bin:
|
||||
#ifndef FW_PAYLOAD_PATH
|
||||
|
@@ -41,11 +41,6 @@ ifdef FW_PAYLOAD_ALIGN
|
||||
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_ALIGN=$(FW_PAYLOAD_ALIGN)
|
||||
endif
|
||||
|
||||
ifndef FW_PAYLOAD_FDT_PATH
|
||||
ifdef FW_PAYLOAD_FDT
|
||||
FW_PAYLOAD_FDT_PATH=$(platform_build_dir)/$(FW_PAYLOAD_FDT)
|
||||
endif
|
||||
endif
|
||||
ifdef FW_PAYLOAD_FDT_PATH
|
||||
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_FDT_PATH=\"$(FW_PAYLOAD_FDT_PATH)\"
|
||||
endif
|
||||
|
@@ -23,8 +23,8 @@
|
||||
#define REG_L __REG_SEL(ld, lw)
|
||||
#define REG_S __REG_SEL(sd, sw)
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _start
|
||||
_start:
|
||||
/* Pick one hart to run the main boot sequence */
|
||||
@@ -71,15 +71,15 @@ _start_warm:
|
||||
/* We don't expect to reach here hence just hang */
|
||||
j _start_hang
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _start_hang
|
||||
_start_hang:
|
||||
wfi
|
||||
j _start_hang
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
_hart_lottery:
|
||||
RISCV_PTR 0
|
||||
_boot_a0:
|
||||
|
@@ -9,6 +9,31 @@
|
||||
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
|
||||
#define SBI_ECALL(__num, __a0, __a1, __a2) \
|
||||
({ \
|
||||
register unsigned long a0 asm("a0") = (unsigned long)(__a0); \
|
||||
register unsigned long a1 asm("a1") = (unsigned long)(__a1); \
|
||||
register unsigned long a2 asm("a2") = (unsigned long)(__a2); \
|
||||
register unsigned long a7 asm("a7") = (unsigned long)(__num); \
|
||||
asm volatile("ecall" \
|
||||
: "+r"(a0) \
|
||||
: "r"(a1), "r"(a2), "r"(a7) \
|
||||
: "memory"); \
|
||||
a0; \
|
||||
})
|
||||
|
||||
#define SBI_ECALL_0(__num) SBI_ECALL(__num, 0, 0, 0)
|
||||
#define SBI_ECALL_1(__num, __a0) SBI_ECALL(__num, __a0, 0, 0)
|
||||
#define SBI_ECALL_2(__num, __a0, __a1) SBI_ECALL(__num, __a0, __a1, 0)
|
||||
|
||||
#define sbi_ecall_console_putc(c) SBI_ECALL_1(SBI_EXT_0_1_CONSOLE_PUTCHAR, (c))
|
||||
|
||||
static inline void sbi_ecall_console_puts(const char *str)
|
||||
{
|
||||
while (str && *str)
|
||||
sbi_ecall_console_putc(*str++);
|
||||
}
|
||||
|
||||
#define wfi() \
|
||||
do { \
|
||||
__asm__ __volatile__("wfi" ::: "memory"); \
|
||||
|
@@ -18,18 +18,20 @@
|
||||
#define FW_DYNAMIC_INFO_MAGIC_OFFSET (0 * __SIZEOF_POINTER__)
|
||||
/** Offset of version member in fw_dynamic_info */
|
||||
#define FW_DYNAMIC_INFO_VERSION_OFFSET (1 * __SIZEOF_POINTER__)
|
||||
/** Offset of next_addr member in fw_dynamic_info */
|
||||
/** Offset of next_addr member in fw_dynamic_info (version >= 1) */
|
||||
#define FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET (2 * __SIZEOF_POINTER__)
|
||||
/** Offset of next_mode member in fw_dynamic_info */
|
||||
/** Offset of next_mode member in fw_dynamic_info (version >= 1) */
|
||||
#define FW_DYNAMIC_INFO_NEXT_MODE_OFFSET (3 * __SIZEOF_POINTER__)
|
||||
/** Offset of options member in fw_dynamic_info */
|
||||
/** Offset of options member in fw_dynamic_info (version >= 1) */
|
||||
#define FW_DYNAMIC_INFO_OPTIONS_OFFSET (4 * __SIZEOF_POINTER__)
|
||||
/** Offset of boot_hart member in fw_dynamic_info (version >= 2) */
|
||||
#define FW_DYNAMIC_INFO_BOOT_HART_OFFSET (5 * __SIZEOF_POINTER__)
|
||||
|
||||
/** Expected value of info magic ('OSBI' ascii string in hex) */
|
||||
#define FW_DYNAMIC_INFO_MAGIC_VALUE 0x4942534f
|
||||
|
||||
/** Maximum supported info version */
|
||||
#define FW_DYNAMIC_INFO_VERSION_MAX 0x1
|
||||
#define FW_DYNAMIC_INFO_VERSION_MAX 0x2
|
||||
|
||||
/** Possible next mode values */
|
||||
#define FW_DYNAMIC_INFO_NEXT_MODE_U 0x0
|
||||
@@ -54,6 +56,22 @@ struct fw_dynamic_info {
|
||||
unsigned long next_mode;
|
||||
/** Options for OpenSBI library */
|
||||
unsigned long options;
|
||||
/**
|
||||
* Preferred boot HART id
|
||||
*
|
||||
* It is possible that the previous booting stage uses same link
|
||||
* address as the FW_DYNAMIC firmware. In this case, the relocation
|
||||
* lottery mechanism can potentially overwrite the previous booting
|
||||
* stage while other HARTs are still running in the previous booting
|
||||
* stage leading to boot-time crash. To avoid this boot-time crash,
|
||||
* the previous booting stage can specify last HART that will jump
|
||||
* to the FW_DYNAMIC firmware as the preferred boot HART.
|
||||
*
|
||||
* To avoid specifying a preferred boot HART, the previous booting
|
||||
* stage can set it to -1UL which will force the FW_DYNAMIC firmware
|
||||
* to use the relocation lottery mechanism.
|
||||
*/
|
||||
unsigned long boot_hart;
|
||||
} __packed;
|
||||
|
||||
#endif
|
||||
|
@@ -28,9 +28,9 @@
|
||||
#error "Unexpected __riscv_xlen"
|
||||
#endif
|
||||
|
||||
#define PAGE_SHIFT (12)
|
||||
#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
|
||||
#define PAGE_MASK (~(PAGE_SIZE - 1))
|
||||
#define PAGE_SHIFT (12)
|
||||
#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
|
||||
#define PAGE_MASK (~(PAGE_SIZE - 1))
|
||||
|
||||
#define REG_L __REG_SEL(ld, lw)
|
||||
#define REG_S __REG_SEL(sd, sw)
|
||||
@@ -38,7 +38,6 @@
|
||||
#define LGREG __REG_SEL(3, 2)
|
||||
|
||||
#if __SIZEOF_POINTER__ == 8
|
||||
#define BITS_PER_LONG 64
|
||||
#ifdef __ASSEMBLY__
|
||||
#define RISCV_PTR .dword
|
||||
#define RISCV_SZPTR 8
|
||||
@@ -49,7 +48,6 @@
|
||||
#define RISCV_LGPTR "3"
|
||||
#endif
|
||||
#elif __SIZEOF_POINTER__ == 4
|
||||
#define BITS_PER_LONG 32
|
||||
#ifdef __ASSEMBLY__
|
||||
#define RISCV_PTR .word
|
||||
#define RISCV_SZPTR 4
|
||||
@@ -159,35 +157,30 @@ void csr_write_num(int csr_num, unsigned long val);
|
||||
__asm__ __volatile__("wfi" ::: "memory"); \
|
||||
} while (0)
|
||||
|
||||
static inline int misa_extension(char ext)
|
||||
{
|
||||
return csr_read(CSR_MISA) & (1 << (ext - 'A'));
|
||||
}
|
||||
/* Get current HART id */
|
||||
#define current_hartid() ((unsigned int)csr_read(CSR_MHARTID))
|
||||
|
||||
static inline int misa_xlen(void)
|
||||
{
|
||||
return ((long)csr_read(CSR_MISA) < 0) ? 64 : 32;
|
||||
}
|
||||
/* determine CPU extension, return non-zero support */
|
||||
int misa_extension_imp(char ext);
|
||||
|
||||
static inline void misa_string(char *out, unsigned int out_sz)
|
||||
{
|
||||
unsigned long i, val = csr_read(CSR_MISA);
|
||||
#define misa_extension(c)\
|
||||
({\
|
||||
_Static_assert(((c >= 'A') && (c <= 'Z')),\
|
||||
"The parameter of misa_extension must be [A-Z]");\
|
||||
misa_extension_imp(c);\
|
||||
})
|
||||
|
||||
for (i = 0; i < 26; i++) {
|
||||
if (val & (1 << i)) {
|
||||
*out = 'A' + i;
|
||||
out++;
|
||||
}
|
||||
}
|
||||
*out = '\0';
|
||||
out++;
|
||||
}
|
||||
/* Get MXL field of misa, return -1 on error */
|
||||
int misa_xlen(void);
|
||||
|
||||
/* Get RISC-V ISA string representation */
|
||||
void misa_string(int xlen, char *out, unsigned int out_sz);
|
||||
|
||||
int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
|
||||
unsigned long log2len);
|
||||
|
||||
int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
|
||||
unsigned long *log2len_out);
|
||||
unsigned long *size);
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
|
@@ -29,12 +29,15 @@ long atomic_add_return(atomic_t *atom, long value);
|
||||
|
||||
long atomic_sub_return(atomic_t *atom, long value);
|
||||
|
||||
long arch_atomic_cmpxchg(atomic_t *atom, long oldval, long newval);
|
||||
long atomic_cmpxchg(atomic_t *atom, long oldval, long newval);
|
||||
|
||||
long arch_atomic_xchg(atomic_t *atom, long newval);
|
||||
long atomic_xchg(atomic_t *atom, long newval);
|
||||
|
||||
unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
|
||||
unsigned int newval);
|
||||
|
||||
unsigned long atomic_raw_xchg_ulong(volatile unsigned long *ptr,
|
||||
unsigned long newval);
|
||||
/**
|
||||
* Set a bit in an atomic variable and return the new value.
|
||||
* @nr : Bit to set.
|
||||
|
@@ -12,189 +12,159 @@
|
||||
|
||||
#include <sbi/sbi_const.h>
|
||||
|
||||
/* TODO: Make constants usable in assembly with _AC() macro */
|
||||
|
||||
/* clang-format off */
|
||||
#define MSTATUS_UIE 0x00000001
|
||||
#define MSTATUS_SIE 0x00000002
|
||||
#define MSTATUS_HIE 0x00000004
|
||||
#define MSTATUS_MIE 0x00000008
|
||||
#define MSTATUS_UPIE 0x00000010
|
||||
#define MSTATUS_SIE _UL(0x00000002)
|
||||
#define MSTATUS_MIE _UL(0x00000008)
|
||||
#define MSTATUS_SPIE_SHIFT 5
|
||||
#define MSTATUS_SPIE (1UL << MSTATUS_SPIE_SHIFT)
|
||||
#define MSTATUS_HPIE 0x00000040
|
||||
#define MSTATUS_MPIE 0x00000080
|
||||
#define MSTATUS_SPIE (_UL(1) << MSTATUS_SPIE_SHIFT)
|
||||
#define MSTATUS_UBE _UL(0x00000040)
|
||||
#define MSTATUS_MPIE _UL(0x00000080)
|
||||
#define MSTATUS_SPP_SHIFT 8
|
||||
#define MSTATUS_SPP (1UL << MSTATUS_SPP_SHIFT)
|
||||
#define MSTATUS_HPP 0x00000600
|
||||
#define MSTATUS_SPP (_UL(1) << MSTATUS_SPP_SHIFT)
|
||||
#define MSTATUS_MPP_SHIFT 11
|
||||
#define MSTATUS_MPP (3UL << MSTATUS_MPP_SHIFT)
|
||||
#define MSTATUS_FS 0x00006000
|
||||
#define MSTATUS_XS 0x00018000
|
||||
#define MSTATUS_MPRV 0x00020000
|
||||
#define MSTATUS_SUM 0x00040000
|
||||
#define MSTATUS_MXR 0x00080000
|
||||
#define MSTATUS_TVM 0x00100000
|
||||
#define MSTATUS_TW 0x00200000
|
||||
#define MSTATUS_TSR 0x00400000
|
||||
#define MSTATUS32_SD 0x80000000
|
||||
#define MSTATUS_UXL 0x0000000300000000
|
||||
#define MSTATUS_SXL 0x0000000C00000000
|
||||
#define MSTATUS64_SD 0x8000000000000000
|
||||
#define MSTATUS_MPP (_UL(3) << MSTATUS_MPP_SHIFT)
|
||||
#define MSTATUS_FS _UL(0x00006000)
|
||||
#define MSTATUS_XS _UL(0x00018000)
|
||||
#define MSTATUS_VS _UL(0x01800000)
|
||||
#define MSTATUS_MPRV _UL(0x00020000)
|
||||
#define MSTATUS_SUM _UL(0x00040000)
|
||||
#define MSTATUS_MXR _UL(0x00080000)
|
||||
#define MSTATUS_TVM _UL(0x00100000)
|
||||
#define MSTATUS_TW _UL(0x00200000)
|
||||
#define MSTATUS_TSR _UL(0x00400000)
|
||||
#define MSTATUS32_SD _UL(0x80000000)
|
||||
#if __riscv_xlen == 64
|
||||
#define MSTATUS_UXL _ULL(0x0000000300000000)
|
||||
#define MSTATUS_SXL _ULL(0x0000000C00000000)
|
||||
#define MSTATUS_SBE _ULL(0x0000001000000000)
|
||||
#define MSTATUS_MBE _ULL(0x0000002000000000)
|
||||
#define MSTATUS_MPV _ULL(0x0000008000000000)
|
||||
#else
|
||||
#define MSTATUSH_SBE _UL(0x00000010)
|
||||
#define MSTATUSH_MBE _UL(0x00000020)
|
||||
#define MSTATUSH_MPV _UL(0x00000080)
|
||||
#endif
|
||||
#define MSTATUS32_SD _UL(0x80000000)
|
||||
#define MSTATUS64_SD _ULL(0x8000000000000000)
|
||||
|
||||
#define SSTATUS_UIE 0x00000001
|
||||
#define SSTATUS_SIE 0x00000002
|
||||
#define SSTATUS_UPIE 0x00000010
|
||||
#define SSTATUS_SPIE 0x00000020
|
||||
#define SSTATUS_SPP 0x00000100
|
||||
#define SSTATUS_FS 0x00006000
|
||||
#define SSTATUS_XS 0x00018000
|
||||
#define SSTATUS_SUM 0x00040000
|
||||
#define SSTATUS_MXR 0x00080000
|
||||
#define SSTATUS32_SD 0x80000000
|
||||
#define SSTATUS_UXL 0x0000000300000000
|
||||
#define SSTATUS64_SD 0x8000000000000000
|
||||
#define SSTATUS_SIE MSTATUS_SIE
|
||||
#define SSTATUS_SPIE_SHIFT MSTATUS_SPIE_SHIFT
|
||||
#define SSTATUS_SPIE MSTATUS_SPIE
|
||||
#define SSTATUS_SPP_SHIFT MSTATUS_SPP_SHIFT
|
||||
#define SSTATUS_SPP MSTATUS_SPP
|
||||
#define SSTATUS_FS MSTATUS_FS
|
||||
#define SSTATUS_XS MSTATUS_XS
|
||||
#define SSTATUS_VS MSTATUS_VS
|
||||
#define SSTATUS_SUM MSTATUS_SUM
|
||||
#define SSTATUS_MXR MSTATUS_MXR
|
||||
#define SSTATUS32_SD MSTATUS32_SD
|
||||
#define SSTATUS64_UXL MSTATUS_UXL
|
||||
#define SSTATUS64_SD MSTATUS64_SD
|
||||
|
||||
#define DCSR_XDEBUGVER (3U<<30)
|
||||
#define DCSR_NDRESET (1<<29)
|
||||
#define DCSR_FULLRESET (1<<28)
|
||||
#define DCSR_EBREAKM (1<<15)
|
||||
#define DCSR_EBREAKH (1<<14)
|
||||
#define DCSR_EBREAKS (1<<13)
|
||||
#define DCSR_EBREAKU (1<<12)
|
||||
#define DCSR_STOPCYCLE (1<<10)
|
||||
#define DCSR_STOPTIME (1<<9)
|
||||
#define DCSR_CAUSE (7<<6)
|
||||
#define DCSR_DEBUGINT (1<<5)
|
||||
#define DCSR_HALT (1<<3)
|
||||
#define DCSR_STEP (1<<2)
|
||||
#define DCSR_PRV (3<<0)
|
||||
|
||||
#define DCSR_CAUSE_NONE 0
|
||||
#define DCSR_CAUSE_SWBP 1
|
||||
#define DCSR_CAUSE_HWBP 2
|
||||
#define DCSR_CAUSE_DEBUGINT 3
|
||||
#define DCSR_CAUSE_STEP 4
|
||||
#define DCSR_CAUSE_HALT 5
|
||||
|
||||
#define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4))
|
||||
#define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5))
|
||||
#define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11))
|
||||
|
||||
#define MCONTROL_SELECT (1<<19)
|
||||
#define MCONTROL_TIMING (1<<18)
|
||||
#define MCONTROL_ACTION (0x3f<<12)
|
||||
#define MCONTROL_CHAIN (1<<11)
|
||||
#define MCONTROL_MATCH (0xf<<7)
|
||||
#define MCONTROL_M (1<<6)
|
||||
#define MCONTROL_H (1<<5)
|
||||
#define MCONTROL_S (1<<4)
|
||||
#define MCONTROL_U (1<<3)
|
||||
#define MCONTROL_EXECUTE (1<<2)
|
||||
#define MCONTROL_STORE (1<<1)
|
||||
#define MCONTROL_LOAD (1<<0)
|
||||
|
||||
#define MCONTROL_TYPE_NONE 0
|
||||
#define MCONTROL_TYPE_MATCH 2
|
||||
|
||||
#define MCONTROL_ACTION_DEBUG_EXCEPTION 0
|
||||
#define MCONTROL_ACTION_DEBUG_MODE 1
|
||||
#define MCONTROL_ACTION_TRACE_START 2
|
||||
#define MCONTROL_ACTION_TRACE_STOP 3
|
||||
#define MCONTROL_ACTION_TRACE_EMIT 4
|
||||
|
||||
#define MCONTROL_MATCH_EQUAL 0
|
||||
#define MCONTROL_MATCH_NAPOT 1
|
||||
#define MCONTROL_MATCH_GE 2
|
||||
#define MCONTROL_MATCH_LT 3
|
||||
#define MCONTROL_MATCH_MASK_LOW 4
|
||||
#define MCONTROL_MATCH_MASK_HIGH 5
|
||||
#if __riscv_xlen == 64
|
||||
#define HSTATUS_VSXL _UL(0x300000000)
|
||||
#define HSTATUS_VSXL_SHIFT 32
|
||||
#endif
|
||||
#define HSTATUS_VTSR _UL(0x00400000)
|
||||
#define HSTATUS_VTW _UL(0x00200000)
|
||||
#define HSTATUS_VTVM _UL(0x00100000)
|
||||
#define HSTATUS_VGEIN _UL(0x0003f000)
|
||||
#define HSTATUS_VGEIN_SHIFT 12
|
||||
#define HSTATUS_HU _UL(0x00000200)
|
||||
#define HSTATUS_SPVP _UL(0x00000100)
|
||||
#define HSTATUS_SPV _UL(0x00000080)
|
||||
#define HSTATUS_GVA _UL(0x00000040)
|
||||
#define HSTATUS_VSBE _UL(0x00000020)
|
||||
|
||||
#define IRQ_S_SOFT 1
|
||||
#define IRQ_H_SOFT 2
|
||||
#define IRQ_VS_SOFT 2
|
||||
#define IRQ_M_SOFT 3
|
||||
#define IRQ_S_TIMER 5
|
||||
#define IRQ_H_TIMER 6
|
||||
#define IRQ_VS_TIMER 6
|
||||
#define IRQ_M_TIMER 7
|
||||
#define IRQ_S_EXT 9
|
||||
#define IRQ_H_EXT 10
|
||||
#define IRQ_VS_EXT 10
|
||||
#define IRQ_M_EXT 11
|
||||
#define IRQ_COP 12
|
||||
#define IRQ_HOST 13
|
||||
#define IRQ_S_GEXT 12
|
||||
|
||||
#define MIP_SSIP (1 << IRQ_S_SOFT)
|
||||
#define MIP_HSIP (1 << IRQ_H_SOFT)
|
||||
#define MIP_MSIP (1 << IRQ_M_SOFT)
|
||||
#define MIP_STIP (1 << IRQ_S_TIMER)
|
||||
#define MIP_HTIP (1 << IRQ_H_TIMER)
|
||||
#define MIP_MTIP (1 << IRQ_M_TIMER)
|
||||
#define MIP_SEIP (1 << IRQ_S_EXT)
|
||||
#define MIP_HEIP (1 << IRQ_H_EXT)
|
||||
#define MIP_MEIP (1 << IRQ_M_EXT)
|
||||
#define MIP_SSIP (_UL(1) << IRQ_S_SOFT)
|
||||
#define MIP_VSSIP (_UL(1) << IRQ_VS_SOFT)
|
||||
#define MIP_MSIP (_UL(1) << IRQ_M_SOFT)
|
||||
#define MIP_STIP (_UL(1) << IRQ_S_TIMER)
|
||||
#define MIP_VSTIP (_UL(1) << IRQ_VS_TIMER)
|
||||
#define MIP_MTIP (_UL(1) << IRQ_M_TIMER)
|
||||
#define MIP_SEIP (_UL(1) << IRQ_S_EXT)
|
||||
#define MIP_VSEIP (_UL(1) << IRQ_VS_EXT)
|
||||
#define MIP_MEIP (_UL(1) << IRQ_M_EXT)
|
||||
#define MIP_SGEIP (_UL(1) << IRQ_S_GEXT)
|
||||
|
||||
#define SIP_SSIP MIP_SSIP
|
||||
#define SIP_STIP MIP_STIP
|
||||
|
||||
#define PRV_U 0
|
||||
#define PRV_S 1
|
||||
#define PRV_H 2
|
||||
#define PRV_M 3
|
||||
#define PRV_U _UL(0)
|
||||
#define PRV_S _UL(1)
|
||||
#define PRV_M _UL(3)
|
||||
|
||||
#define SATP32_MODE 0x80000000
|
||||
#define SATP32_ASID 0x7FC00000
|
||||
#define SATP32_PPN 0x003FFFFF
|
||||
#define SATP64_MODE 0xF000000000000000
|
||||
#define SATP64_ASID 0x0FFFF00000000000
|
||||
#define SATP64_PPN 0x00000FFFFFFFFFFF
|
||||
#define SATP32_MODE _UL(0x80000000)
|
||||
#define SATP32_ASID _UL(0x7FC00000)
|
||||
#define SATP32_PPN _UL(0x003FFFFF)
|
||||
#define SATP64_MODE _ULL(0xF000000000000000)
|
||||
#define SATP64_ASID _ULL(0x0FFFF00000000000)
|
||||
#define SATP64_PPN _ULL(0x00000FFFFFFFFFFF)
|
||||
|
||||
#define SATP_MODE_OFF 0
|
||||
#define SATP_MODE_SV32 1
|
||||
#define SATP_MODE_SV39 8
|
||||
#define SATP_MODE_SV48 9
|
||||
#define SATP_MODE_SV57 10
|
||||
#define SATP_MODE_SV64 11
|
||||
#define SATP_MODE_OFF _UL(0)
|
||||
#define SATP_MODE_SV32 _UL(1)
|
||||
#define SATP_MODE_SV39 _UL(8)
|
||||
#define SATP_MODE_SV48 _UL(9)
|
||||
#define SATP_MODE_SV57 _UL(10)
|
||||
#define SATP_MODE_SV64 _UL(11)
|
||||
|
||||
#define PMP_R 0x01
|
||||
#define PMP_W 0x02
|
||||
#define PMP_X 0x04
|
||||
#define PMP_A 0x18
|
||||
#define PMP_A_TOR 0x08
|
||||
#define PMP_A_NA4 0x10
|
||||
#define PMP_A_NAPOT 0x18
|
||||
#define PMP_L 0x80
|
||||
#define HGATP_MODE_OFF _UL(0)
|
||||
#define HGATP_MODE_SV32X4 _UL(1)
|
||||
#define HGATP_MODE_SV39X4 _UL(8)
|
||||
#define HGATP_MODE_SV48X4 _UL(9)
|
||||
|
||||
#define HGATP32_MODE_SHIFT 31
|
||||
#define HGATP32_VMID_SHIFT 22
|
||||
#define HGATP32_VMID_MASK _UL(0x1FC00000)
|
||||
#define HGATP32_PPN _UL(0x003FFFFF)
|
||||
|
||||
#define HGATP64_MODE_SHIFT 60
|
||||
#define HGATP64_VMID_SHIFT 44
|
||||
#define HGATP64_VMID_MASK _ULL(0x03FFF00000000000)
|
||||
#define HGATP64_PPN _ULL(0x00000FFFFFFFFFFF)
|
||||
|
||||
#define PMP_R _UL(0x01)
|
||||
#define PMP_W _UL(0x02)
|
||||
#define PMP_X _UL(0x04)
|
||||
#define PMP_A _UL(0x18)
|
||||
#define PMP_A_TOR _UL(0x08)
|
||||
#define PMP_A_NA4 _UL(0x10)
|
||||
#define PMP_A_NAPOT _UL(0x18)
|
||||
#define PMP_L _UL(0x80)
|
||||
|
||||
#define PMP_SHIFT 2
|
||||
#define PMP_COUNT 16
|
||||
|
||||
/* page table entry (PTE) fields */
|
||||
#define PTE_V 0x001 /* Valid */
|
||||
#define PTE_R 0x002 /* Read */
|
||||
#define PTE_W 0x004 /* Write */
|
||||
#define PTE_X 0x008 /* Execute */
|
||||
#define PTE_U 0x010 /* User */
|
||||
#define PTE_G 0x020 /* Global */
|
||||
#define PTE_A 0x040 /* Accessed */
|
||||
#define PTE_D 0x080 /* Dirty */
|
||||
#define PTE_SOFT 0x300 /* Reserved for Software */
|
||||
|
||||
#define PTE_PPN_SHIFT 10
|
||||
|
||||
#define PTE_TABLE(PTE) \
|
||||
(((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V)
|
||||
|
||||
#if __riscv_xlen == 64
|
||||
#define MSTATUS_SD MSTATUS64_SD
|
||||
#define SSTATUS_SD SSTATUS64_SD
|
||||
#define RISCV_PGLEVEL_BITS 9
|
||||
#define SATP_MODE SATP64_MODE
|
||||
|
||||
#define HGATP_PPN HGATP64_PPN
|
||||
#define HGATP_VMID_SHIFT HGATP64_VMID_SHIFT
|
||||
#define HGATP_VMID_MASK HGATP64_VMID_MASK
|
||||
#define HGATP_MODE_SHIFT HGATP64_MODE_SHIFT
|
||||
#else
|
||||
#define MSTATUS_SD MSTATUS32_SD
|
||||
#define SSTATUS_SD SSTATUS32_SD
|
||||
#define RISCV_PGLEVEL_BITS 10
|
||||
#define SATP_MODE SATP32_MODE
|
||||
|
||||
#define HGATP_PPN HGATP32_PPN
|
||||
#define HGATP_VMID_SHIFT HGATP32_VMID_SHIFT
|
||||
#define HGATP_VMID_MASK HGATP32_VMID_MASK
|
||||
#define HGATP_MODE_SHIFT HGATP32_MODE_SHIFT
|
||||
#endif
|
||||
#define RISCV_PGSHIFT 12
|
||||
#define RISCV_PGSIZE (1 << RISCV_PGSHIFT)
|
||||
|
||||
#define CSR_USTATUS 0x0
|
||||
#define CSR_FFLAGS 0x1
|
||||
@@ -249,6 +219,31 @@
|
||||
#define CSR_STVAL 0x143
|
||||
#define CSR_SIP 0x144
|
||||
#define CSR_SATP 0x180
|
||||
|
||||
#define CSR_HSTATUS 0x600
|
||||
#define CSR_HEDELEG 0x602
|
||||
#define CSR_HIDELEG 0x603
|
||||
#define CSR_HIE 0x604
|
||||
#define CSR_HTIMEDELTA 0x605
|
||||
#define CSR_HTIMEDELTAH 0x615
|
||||
#define CSR_HCOUNTERNEN 0x606
|
||||
#define CSR_HGEIE 0x607
|
||||
#define CSR_HTVAL 0x643
|
||||
#define CSR_HIP 0x644
|
||||
#define CSR_HTINST 0x64a
|
||||
#define CSR_HGATP 0x680
|
||||
#define CSR_HGEIP 0xe07
|
||||
|
||||
#define CSR_VSSTATUS 0x200
|
||||
#define CSR_VSIE 0x204
|
||||
#define CSR_VSTVEC 0x205
|
||||
#define CSR_VSSCRATCH 0x240
|
||||
#define CSR_VSEPC 0x241
|
||||
#define CSR_VSCAUSE 0x242
|
||||
#define CSR_VSTVAL 0x243
|
||||
#define CSR_VSIP 0x244
|
||||
#define CSR_VSATP 0x280
|
||||
|
||||
#define CSR_MSTATUS 0x300
|
||||
#define CSR_MISA 0x301
|
||||
#define CSR_MEDELEG 0x302
|
||||
@@ -256,11 +251,14 @@
|
||||
#define CSR_MIE 0x304
|
||||
#define CSR_MTVEC 0x305
|
||||
#define CSR_MCOUNTEREN 0x306
|
||||
#define CSR_MSTATUSH 0x310
|
||||
#define CSR_MSCRATCH 0x340
|
||||
#define CSR_MEPC 0x341
|
||||
#define CSR_MCAUSE 0x342
|
||||
#define CSR_MTVAL 0x343
|
||||
#define CSR_MIP 0x344
|
||||
#define CSR_MTINST 0x34a
|
||||
#define CSR_MTVAL2 0x34b
|
||||
#define CSR_PMPCFG0 0x3a0
|
||||
#define CSR_PMPCFG1 0x3a1
|
||||
#define CSR_PMPCFG2 0x3a2
|
||||
@@ -288,6 +286,7 @@
|
||||
#define CSR_DCSR 0x7b0
|
||||
#define CSR_DPC 0x7b1
|
||||
#define CSR_DSCRATCH 0x7b2
|
||||
|
||||
#define CSR_MCYCLE 0xb00
|
||||
#define CSR_MINSTRET 0xb02
|
||||
#define CSR_MHPMCOUNTER3 0xb03
|
||||
@@ -431,6 +430,10 @@
|
||||
#define CAUSE_FETCH_PAGE_FAULT 0xc
|
||||
#define CAUSE_LOAD_PAGE_FAULT 0xd
|
||||
#define CAUSE_STORE_PAGE_FAULT 0xf
|
||||
#define CAUSE_FETCH_GUEST_PAGE_FAULT 0x14
|
||||
#define CAUSE_LOAD_GUEST_PAGE_FAULT 0x15
|
||||
#define CAUSE_VIRTUAL_INST_FAULT 0x16
|
||||
#define CAUSE_STORE_GUEST_PAGE_FAULT 0x17
|
||||
|
||||
#define INSN_MATCH_LB 0x3
|
||||
#define INSN_MASK_LB 0x707f
|
||||
@@ -502,7 +505,19 @@
|
||||
#define INSN_MATCH_C_FSWSP 0xe002
|
||||
#define INSN_MASK_C_FSWSP 0xe003
|
||||
|
||||
#define INSN_LEN(insn) ((((insn) & 0x3) < 0x3) ? 2 : 4)
|
||||
#define INSN_MASK_WFI 0xffffff00
|
||||
#define INSN_MATCH_WFI 0x10500000
|
||||
|
||||
#define INSN_16BIT_MASK 0x3
|
||||
#define INSN_32BIT_MASK 0x1c
|
||||
|
||||
#define INSN_IS_16BIT(insn) \
|
||||
(((insn) & INSN_16BIT_MASK) != INSN_16BIT_MASK)
|
||||
#define INSN_IS_32BIT(insn) \
|
||||
(((insn) & INSN_16BIT_MASK) == INSN_16BIT_MASK && \
|
||||
((insn) & INSN_32BIT_MASK) != INSN_32BIT_MASK)
|
||||
|
||||
#define INSN_LEN(insn) (INSN_IS_16BIT(insn) ? 2 : 4)
|
||||
|
||||
#if __riscv_xlen == 64
|
||||
#define LOG_REGBYTES 3
|
||||
|
@@ -73,10 +73,6 @@
|
||||
|
||||
#define SET_FS_DIRTY() ((void)0)
|
||||
|
||||
#else
|
||||
#error "Floating point emulation not supported.\n"
|
||||
#endif
|
||||
|
||||
#define GET_F32_RS1(insn, regs) (GET_F32_REG(insn, 15, regs))
|
||||
#define GET_F32_RS2(insn, regs) (GET_F32_REG(insn, 20, regs))
|
||||
#define GET_F32_RS3(insn, regs) (GET_F32_REG(insn, 27, regs))
|
||||
@@ -94,3 +90,5 @@
|
||||
#define GET_F64_RS2S(insn, regs) (GET_F64_REG(RVC_RS2S(insn), 0, regs))
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
128
include/sbi/sbi_bitmap.h
Normal file
128
include/sbi/sbi_bitmap.h
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __SBI_BITMAP_H__
|
||||
#define __SBI_BITMAP_H__
|
||||
|
||||
#include <sbi/sbi_bitops.h>
|
||||
|
||||
#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) % BITS_PER_LONG))
|
||||
#define BITMAP_LAST_WORD_MASK(nbits) \
|
||||
( \
|
||||
((nbits) % BITS_PER_LONG) ? \
|
||||
((1UL << ((nbits) % BITS_PER_LONG)) - 1) : ~0UL \
|
||||
)
|
||||
|
||||
#define small_const_nbits(nbits) \
|
||||
(__builtin_constant_p(nbits) && (nbits) <= BITS_PER_LONG)
|
||||
|
||||
#define DECLARE_BITMAP(name, nbits) unsigned long name[BITS_TO_LONGS(nbits)]
|
||||
#define DEFINE_BITMAP(name) extern unsigned long name[]
|
||||
|
||||
static inline unsigned long bitmap_estimate_size(int nbits)
|
||||
{
|
||||
return (BITS_TO_LONGS(nbits) * sizeof(unsigned long));
|
||||
}
|
||||
|
||||
void __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, int bits);
|
||||
void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, int bits);
|
||||
void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, int bits);
|
||||
|
||||
static inline void bitmap_set(unsigned long *bmap, int start, int len)
|
||||
{
|
||||
int bit;
|
||||
for (bit = start; bit < (start + len); bit++)
|
||||
bmap[BIT_WORD(bit)] |= (0x1UL << BIT_WORD_OFFSET(bit));
|
||||
}
|
||||
|
||||
static inline void bitmap_clear(unsigned long *bmap, int start, int len)
|
||||
{
|
||||
int bit;
|
||||
for (bit = start; bit < (start + len); bit++)
|
||||
bmap[BIT_WORD(bit)] &= ~(0x1UL << BIT_WORD_OFFSET(bit));
|
||||
}
|
||||
|
||||
static inline void bitmap_zero(unsigned long *dst, int nbits)
|
||||
{
|
||||
if (small_const_nbits(nbits))
|
||||
*dst = 0UL;
|
||||
else {
|
||||
size_t i, len = BITS_TO_LONGS(nbits);
|
||||
for (i = 0; i < len; i++)
|
||||
dst[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void bitmap_zero_except(unsigned long *dst,
|
||||
int exception, int nbits)
|
||||
{
|
||||
if (small_const_nbits(nbits))
|
||||
*dst = 0UL;
|
||||
else {
|
||||
size_t i, len = BITS_TO_LONGS(nbits);
|
||||
for (i = 0; i < len; i++)
|
||||
dst[i] = 0;
|
||||
}
|
||||
if (exception < nbits)
|
||||
__set_bit(exception, dst);
|
||||
}
|
||||
|
||||
static inline void bitmap_fill(unsigned long *dst, int nbits)
|
||||
{
|
||||
size_t i, nlongs = BITS_TO_LONGS(nbits);
|
||||
if (!small_const_nbits(nbits)) {
|
||||
for (i = 0; i < (nlongs - 1); i++)
|
||||
dst[i] = -1UL;
|
||||
}
|
||||
dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits);
|
||||
}
|
||||
|
||||
static inline void bitmap_copy(unsigned long *dst,
|
||||
const unsigned long *src, int nbits)
|
||||
{
|
||||
if (small_const_nbits(nbits))
|
||||
*dst = *src;
|
||||
else {
|
||||
size_t i, len = BITS_TO_LONGS(nbits);
|
||||
for (i = 0; i < len; i++)
|
||||
dst[i] = src[i];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void bitmap_and(unsigned long *dst, const unsigned long *src1,
|
||||
const unsigned long *src2, int nbits)
|
||||
{
|
||||
if (small_const_nbits(nbits))
|
||||
*dst = *src1 & *src2;
|
||||
else
|
||||
__bitmap_and(dst, src1, src2, nbits);
|
||||
}
|
||||
|
||||
static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
|
||||
const unsigned long *src2, int nbits)
|
||||
{
|
||||
if (small_const_nbits(nbits))
|
||||
*dst = *src1 | *src2;
|
||||
else
|
||||
__bitmap_or(dst, src1, src2, nbits);
|
||||
}
|
||||
|
||||
static inline void bitmap_xor(unsigned long *dst, const unsigned long *src1,
|
||||
const unsigned long *src2, int nbits)
|
||||
{
|
||||
if (small_const_nbits(nbits))
|
||||
*dst = *src1 ^ *src2;
|
||||
else
|
||||
__bitmap_xor(dst, src1, src2, nbits);
|
||||
}
|
||||
|
||||
#endif
|
@@ -4,14 +4,37 @@
|
||||
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Atish Patra<atish.patra@wdc.com>
|
||||
* Atish Patra <atish.patra@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __SBI_BITOPS_H__
|
||||
#define __SBI_BITOPS_H__
|
||||
|
||||
#include <sbi/sbi_bits.h>
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
#if __SIZEOF_POINTER__ == 8
|
||||
#define BITS_PER_LONG 64
|
||||
#elif __SIZEOF_POINTER__ == 4
|
||||
#define BITS_PER_LONG 32
|
||||
#else
|
||||
#error "Unexpected __SIZEOF_POINTER__"
|
||||
#endif
|
||||
|
||||
#define EXTRACT_FIELD(val, which) \
|
||||
(((val) & (which)) / ((which) & ~((which)-1)))
|
||||
#define INSERT_FIELD(val, which, fieldval) \
|
||||
(((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1))))
|
||||
|
||||
#define BITS_TO_LONGS(nbits) (((nbits) + BITS_PER_LONG - 1) / \
|
||||
BITS_PER_LONG)
|
||||
|
||||
#define BIT(nr) (1UL << (nr))
|
||||
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
|
||||
#define BIT_WORD(bit) ((bit) / BITS_PER_LONG)
|
||||
#define BIT_WORD_OFFSET(bit) ((bit) & (BITS_PER_LONG - 1))
|
||||
|
||||
#define GENMASK(h, l) \
|
||||
(((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
|
||||
|
||||
/**
|
||||
* ffs - Find first bit set
|
||||
@@ -95,4 +118,207 @@ static inline int __ffs(unsigned long word)
|
||||
*/
|
||||
#define ffz(x) __ffs(~(x))
|
||||
|
||||
/**
|
||||
* fls - find last (most-significant) bit set
|
||||
* @x: the word to search
|
||||
*
|
||||
* This is defined the same way as ffs.
|
||||
* Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
|
||||
*/
|
||||
|
||||
static inline int fls(int x)
|
||||
{
|
||||
int r = 32;
|
||||
|
||||
if (!x)
|
||||
return 0;
|
||||
if (!(x & 0xffff0000u)) {
|
||||
x <<= 16;
|
||||
r -= 16;
|
||||
}
|
||||
if (!(x & 0xff000000u)) {
|
||||
x <<= 8;
|
||||
r -= 8;
|
||||
}
|
||||
if (!(x & 0xf0000000u)) {
|
||||
x <<= 4;
|
||||
r -= 4;
|
||||
}
|
||||
if (!(x & 0xc0000000u)) {
|
||||
x <<= 2;
|
||||
r -= 2;
|
||||
}
|
||||
if (!(x & 0x80000000u)) {
|
||||
x <<= 1;
|
||||
r -= 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* __fls - find last (most-significant) set bit in a long word
|
||||
* @word: the word to search
|
||||
*
|
||||
* Undefined if no set bit exists, so code should check against 0 first.
|
||||
*/
|
||||
static inline unsigned long __fls(unsigned long word)
|
||||
{
|
||||
int num = BITS_PER_LONG - 1;
|
||||
|
||||
#if BITS_PER_LONG == 64
|
||||
if (!(word & (~0ul << 32))) {
|
||||
num -= 32;
|
||||
word <<= 32;
|
||||
}
|
||||
#endif
|
||||
if (!(word & (~0ul << (BITS_PER_LONG-16)))) {
|
||||
num -= 16;
|
||||
word <<= 16;
|
||||
}
|
||||
if (!(word & (~0ul << (BITS_PER_LONG-8)))) {
|
||||
num -= 8;
|
||||
word <<= 8;
|
||||
}
|
||||
if (!(word & (~0ul << (BITS_PER_LONG-4)))) {
|
||||
num -= 4;
|
||||
word <<= 4;
|
||||
}
|
||||
if (!(word & (~0ul << (BITS_PER_LONG-2)))) {
|
||||
num -= 2;
|
||||
word <<= 2;
|
||||
}
|
||||
if (!(word & (~0ul << (BITS_PER_LONG-1))))
|
||||
num -= 1;
|
||||
return num;
|
||||
}
|
||||
|
||||
#define for_each_set_bit(bit, addr, size) \
|
||||
for ((bit) = find_first_bit((addr), (size)); \
|
||||
(bit) < (size); \
|
||||
(bit) = find_next_bit((addr), (size), (bit) + 1))
|
||||
|
||||
/* same as for_each_set_bit() but use bit as value to start with */
|
||||
#define for_each_set_bit_from(bit, addr, size) \
|
||||
for ((bit) = find_next_bit((addr), (size), (bit)); \
|
||||
(bit) < (size); \
|
||||
(bit) = find_next_bit((addr), (size), (bit) + 1))
|
||||
|
||||
#define for_each_clear_bit(bit, addr, size) \
|
||||
for ((bit) = find_first_zero_bit((addr), (size)); \
|
||||
(bit) < (size); \
|
||||
(bit) = find_next_zero_bit((addr), (size), (bit) + 1))
|
||||
|
||||
/* same as for_each_clear_bit() but use bit as value to start with */
|
||||
#define for_each_clear_bit_from(bit, addr, size) \
|
||||
for ((bit) = find_next_zero_bit((addr), (size), (bit)); \
|
||||
(bit) < (size); \
|
||||
(bit) = find_next_zero_bit((addr), (size), (bit) + 1))
|
||||
|
||||
unsigned long find_first_bit(const unsigned long *addr,
|
||||
unsigned long size);
|
||||
|
||||
unsigned long find_first_zero_bit(const unsigned long *addr,
|
||||
unsigned long size);
|
||||
|
||||
unsigned long find_last_bit(const unsigned long *addr,
|
||||
unsigned long size);
|
||||
|
||||
unsigned long find_next_bit(const unsigned long *addr,
|
||||
unsigned long size, unsigned long offset);
|
||||
|
||||
unsigned long find_next_zero_bit(const unsigned long *addr,
|
||||
unsigned long size,
|
||||
unsigned long offset);
|
||||
|
||||
/**
|
||||
* __set_bit - Set a bit in memory
|
||||
* @nr: the bit to set
|
||||
* @addr: the address to start counting from
|
||||
*
|
||||
* This function is non-atomic and may be reordered.
|
||||
*/
|
||||
static inline void __set_bit(int nr, volatile unsigned long *addr)
|
||||
{
|
||||
unsigned long mask = BIT_MASK(nr);
|
||||
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
|
||||
|
||||
*p |= mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* __clear_bit - Clear a bit in memory
|
||||
* @nr: the bit to clear
|
||||
* @addr: the address to start counting from
|
||||
*
|
||||
* This function is non-atomic and may be reordered.
|
||||
*/
|
||||
static inline void __clear_bit(int nr, volatile unsigned long *addr)
|
||||
{
|
||||
unsigned long mask = BIT_MASK(nr);
|
||||
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
|
||||
|
||||
*p &= ~mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* __change_bit - Toggle a bit in memory
|
||||
* @nr: the bit to change
|
||||
* @addr: the address to start counting from
|
||||
*
|
||||
* This function is non-atomic and may be reordered.
|
||||
*/
|
||||
static inline void __change_bit(int nr, volatile unsigned long *addr)
|
||||
{
|
||||
unsigned long mask = BIT_MASK(nr);
|
||||
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
|
||||
|
||||
*p ^= mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* __test_and_set_bit - Set a bit and return its old value
|
||||
* @nr: Bit to set
|
||||
* @addr: Address to count from
|
||||
*
|
||||
* This operation is non-atomic and can be reordered.
|
||||
*/
|
||||
static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
|
||||
{
|
||||
unsigned long mask = BIT_MASK(nr);
|
||||
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
|
||||
unsigned long old = *p;
|
||||
|
||||
*p = old | mask;
|
||||
return (old & mask) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* __test_and_clear_bit - Clear a bit and return its old value
|
||||
* @nr: Bit to clear
|
||||
* @addr: Address to count from
|
||||
*
|
||||
* This operation is non-atomic and can be reordered.
|
||||
*/
|
||||
static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
|
||||
{
|
||||
unsigned long mask = BIT_MASK(nr);
|
||||
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
|
||||
unsigned long old = *p;
|
||||
|
||||
*p = old & ~mask;
|
||||
return (old & mask) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* __test_bit - Determine whether a bit is set
|
||||
* @nr: bit number to test
|
||||
* @addr: Address to start counting from
|
||||
*
|
||||
* This operation is non-atomic and can be reordered.
|
||||
*/
|
||||
static inline int __test_bit(int nr, const volatile unsigned long *addr)
|
||||
{
|
||||
return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __SBI_BITS_H__
|
||||
#define __SBI_BITS_H__
|
||||
|
||||
#define likely(x) __builtin_expect((x), 1)
|
||||
#define unlikely(x) __builtin_expect((x), 0)
|
||||
|
||||
#define ROUNDUP(a, b) ((((a)-1) / (b) + 1) * (b))
|
||||
#define ROUNDDOWN(a, b) ((a) / (b) * (b))
|
||||
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define CLAMP(a, lo, hi) MIN(MAX(a, lo), hi)
|
||||
|
||||
#define EXTRACT_FIELD(val, which) (((val) & (which)) / ((which) & ~((which)-1)))
|
||||
#define INSERT_FIELD(val, which, fieldval) \
|
||||
(((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1))))
|
||||
|
||||
#define STR(x) XSTR(x)
|
||||
#define XSTR(x) #x
|
||||
|
||||
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
|
||||
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
|
||||
#endif
|
@@ -30,7 +30,10 @@ int __printf(3, 4) sbi_snprintf(char *out, u32 out_sz, const char *format, ...);
|
||||
|
||||
int __printf(1, 2) sbi_printf(const char *format, ...);
|
||||
|
||||
int __printf(1, 2) sbi_dprintf(const char *format, ...);
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
int sbi_console_init(struct sbi_scratch *scratch);
|
||||
|
||||
#endif
|
||||
|
@@ -10,7 +10,8 @@
|
||||
#ifndef __SBI_CONST_H__
|
||||
#define __SBI_CONST_H__
|
||||
|
||||
/* Some constant macros are used in both assembler and
|
||||
/*
|
||||
* Some constant macros are used in both assembler and
|
||||
* C code. Therefore we cannot annotate them always with
|
||||
* 'UL' and other type specifiers unilaterally. We
|
||||
* use the following macros to deal with this.
|
||||
@@ -39,8 +40,8 @@
|
||||
#define UL(x) (_UL(x))
|
||||
#define ULL(x) (_ULL(x))
|
||||
|
||||
#define __STR(s) #s
|
||||
#define STRINGIFY(s) __STR(s)
|
||||
#define __STR(s) #s
|
||||
#define STRINGIFY(s) __STR(s)
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
|
50
include/sbi/sbi_csr_detect.h
Normal file
50
include/sbi/sbi_csr_detect.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Atish Patra <atish.patra@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __SBI_CSR_DETECT__H
|
||||
#define __SBI_CSR_DETECT__H
|
||||
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
|
||||
#define csr_read_allowed(csr_num, trap) \
|
||||
({ \
|
||||
register ulong tinfo asm("a3") = (ulong)trap; \
|
||||
register ulong ttmp asm("a4"); \
|
||||
register ulong mtvec = sbi_hart_expected_trap_addr(); \
|
||||
register ulong ret = 0; \
|
||||
asm volatile( \
|
||||
"add %[ttmp], %[tinfo], zero\n" \
|
||||
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
|
||||
"csrr %[ret], %[csr]\n" \
|
||||
"csrw " STR(CSR_MTVEC) ", %[mtvec]" \
|
||||
: [mtvec] "+&r"(mtvec), [tinfo] "+&r"(tinfo), \
|
||||
[ttmp] "+&r"(ttmp), [ret] "=&r" (ret) \
|
||||
: [csr] "i" (csr_num) \
|
||||
: "memory"); \
|
||||
ret; \
|
||||
}) \
|
||||
|
||||
#define csr_write_allowed(csr_num, trap, value) \
|
||||
({ \
|
||||
register ulong tinfo asm("a3") = (ulong)trap; \
|
||||
register ulong ttmp asm("a4"); \
|
||||
register ulong mtvec = sbi_hart_expected_trap_addr(); \
|
||||
asm volatile( \
|
||||
"add %[ttmp], %[tinfo], zero\n" \
|
||||
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
|
||||
"csrw %[csr], %[val]\n" \
|
||||
"csrw " STR(CSR_MTVEC) ", %[mtvec]" \
|
||||
: [mtvec] "+&r"(mtvec), \
|
||||
[tinfo] "+&r"(tinfo), [ttmp] "+&r"(ttmp) \
|
||||
: [csr] "i" (csr_num), [val] "r" (value) \
|
||||
: "memory"); \
|
||||
}) \
|
||||
|
||||
#endif
|
@@ -11,15 +11,49 @@
|
||||
#define __SBI_ECALL_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
#include <sbi/sbi_list.h>
|
||||
|
||||
#define SBI_ECALL_VERSION_MAJOR 0
|
||||
#define SBI_ECALL_VERSION_MINOR 2
|
||||
#define SBI_OPENSBI_IMPID 1
|
||||
|
||||
struct sbi_trap_regs;
|
||||
struct sbi_scratch;
|
||||
struct sbi_trap_info;
|
||||
|
||||
struct sbi_ecall_extension {
|
||||
struct sbi_dlist head;
|
||||
unsigned long extid_start;
|
||||
unsigned long extid_end;
|
||||
int (* probe)(unsigned long extid, unsigned long *out_val);
|
||||
int (* handle)(unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap);
|
||||
};
|
||||
|
||||
extern struct sbi_ecall_extension ecall_base;
|
||||
extern struct sbi_ecall_extension ecall_legacy;
|
||||
extern struct sbi_ecall_extension ecall_time;
|
||||
extern struct sbi_ecall_extension ecall_rfence;
|
||||
extern struct sbi_ecall_extension ecall_ipi;
|
||||
extern struct sbi_ecall_extension ecall_vendor;
|
||||
extern struct sbi_ecall_extension ecall_hsm;
|
||||
|
||||
u16 sbi_ecall_version_major(void);
|
||||
|
||||
u16 sbi_ecall_version_minor(void);
|
||||
|
||||
int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch);
|
||||
unsigned long sbi_ecall_get_impid(void);
|
||||
|
||||
void sbi_ecall_set_impid(unsigned long impid);
|
||||
|
||||
struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid);
|
||||
|
||||
int sbi_ecall_register_extension(struct sbi_ecall_extension *ext);
|
||||
|
||||
void sbi_ecall_unregister_extension(struct sbi_ecall_extension *ext);
|
||||
|
||||
int sbi_ecall_handler(struct sbi_trap_regs *regs);
|
||||
|
||||
int sbi_ecall_init(void);
|
||||
|
||||
#endif
|
||||
|
@@ -12,41 +12,75 @@
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#define SBI_ECALL_SET_TIMER 0
|
||||
#define SBI_ECALL_CONSOLE_PUTCHAR 1
|
||||
#define SBI_ECALL_CONSOLE_GETCHAR 2
|
||||
#define SBI_ECALL_CLEAR_IPI 3
|
||||
#define SBI_ECALL_SEND_IPI 4
|
||||
#define SBI_ECALL_REMOTE_FENCE_I 5
|
||||
#define SBI_ECALL_REMOTE_SFENCE_VMA 6
|
||||
#define SBI_ECALL_REMOTE_SFENCE_VMA_ASID 7
|
||||
#define SBI_ECALL_SHUTDOWN 8
|
||||
/* SBI Extension IDs */
|
||||
#define SBI_EXT_0_1_SET_TIMER 0x0
|
||||
#define SBI_EXT_0_1_CONSOLE_PUTCHAR 0x1
|
||||
#define SBI_EXT_0_1_CONSOLE_GETCHAR 0x2
|
||||
#define SBI_EXT_0_1_CLEAR_IPI 0x3
|
||||
#define SBI_EXT_0_1_SEND_IPI 0x4
|
||||
#define SBI_EXT_0_1_REMOTE_FENCE_I 0x5
|
||||
#define SBI_EXT_0_1_REMOTE_SFENCE_VMA 0x6
|
||||
#define SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID 0x7
|
||||
#define SBI_EXT_0_1_SHUTDOWN 0x8
|
||||
#define SBI_EXT_BASE 0x10
|
||||
#define SBI_EXT_TIME 0x54494D45
|
||||
#define SBI_EXT_IPI 0x735049
|
||||
#define SBI_EXT_RFENCE 0x52464E43
|
||||
#define SBI_EXT_HSM 0x48534D
|
||||
|
||||
/* SBI function IDs for BASE extension*/
|
||||
#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
|
||||
#define SBI_EXT_BASE_GET_IMP_ID 0x1
|
||||
#define SBI_EXT_BASE_GET_IMP_VERSION 0x2
|
||||
#define SBI_EXT_BASE_PROBE_EXT 0x3
|
||||
#define SBI_EXT_BASE_GET_MVENDORID 0x4
|
||||
#define SBI_EXT_BASE_GET_MARCHID 0x5
|
||||
#define SBI_EXT_BASE_GET_MIMPID 0x6
|
||||
|
||||
/* SBI function IDs for TIME extension*/
|
||||
#define SBI_EXT_TIME_SET_TIMER 0x0
|
||||
|
||||
/* SBI function IDs for IPI extension*/
|
||||
#define SBI_EXT_IPI_SEND_IPI 0x0
|
||||
|
||||
/* SBI function IDs for RFENCE extension*/
|
||||
#define SBI_EXT_RFENCE_REMOTE_FENCE_I 0x0
|
||||
#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA 0x1
|
||||
#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID 0x2
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA 0x3
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID 0x4
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA 0x5
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID 0x6
|
||||
|
||||
/* SBI function IDs for HSM extension */
|
||||
#define SBI_EXT_HSM_HART_START 0x0
|
||||
#define SBI_EXT_HSM_HART_STOP 0x1
|
||||
#define SBI_EXT_HSM_HART_GET_STATUS 0x2
|
||||
|
||||
#define SBI_HSM_HART_STATUS_STARTED 0x0
|
||||
#define SBI_HSM_HART_STATUS_STOPPED 0x1
|
||||
#define SBI_HSM_HART_STATUS_START_PENDING 0x2
|
||||
#define SBI_HSM_HART_STATUS_STOP_PENDING 0x3
|
||||
|
||||
#define SBI_SPEC_VERSION_MAJOR_OFFSET 24
|
||||
#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f
|
||||
#define SBI_SPEC_VERSION_MINOR_MASK 0xffffff
|
||||
#define SBI_EXT_VENDOR_START 0x09000000
|
||||
#define SBI_EXT_VENDOR_END 0x09FFFFFF
|
||||
#define SBI_EXT_FIRMWARE_START 0x0A000000
|
||||
#define SBI_EXT_FIRMWARE_END 0x0AFFFFFF
|
||||
|
||||
/* SBI return error codes */
|
||||
#define SBI_SUCCESS 0
|
||||
#define SBI_ERR_FAILED -1
|
||||
#define SBI_ERR_NOT_SUPPORTED -2
|
||||
#define SBI_ERR_INVALID_PARAM -3
|
||||
#define SBI_ERR_DENIED -4
|
||||
#define SBI_ERR_INVALID_ADDRESS -5
|
||||
#define SBI_ERR_ALREADY_AVAILABLE -6
|
||||
|
||||
#define SBI_LAST_ERR SBI_ERR_ALREADY_AVAILABLE
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
#define SBI_ECALL(__num, __a0, __a1, __a2) \
|
||||
({ \
|
||||
register unsigned long a0 asm("a0") = (unsigned long)(__a0); \
|
||||
register unsigned long a1 asm("a1") = (unsigned long)(__a1); \
|
||||
register unsigned long a2 asm("a2") = (unsigned long)(__a2); \
|
||||
register unsigned long a7 asm("a7") = (unsigned long)(__num); \
|
||||
asm volatile("ecall" \
|
||||
: "+r"(a0) \
|
||||
: "r"(a1), "r"(a2), "r"(a7) \
|
||||
: "memory"); \
|
||||
a0; \
|
||||
})
|
||||
|
||||
#define SBI_ECALL_0(__num) SBI_ECALL(__num, 0, 0, 0)
|
||||
#define SBI_ECALL_1(__num, __a0) SBI_ECALL(__num, __a0, 0, 0)
|
||||
#define SBI_ECALL_2(__num, __a0, __a1) SBI_ECALL(__num, __a0, __a1, 0)
|
||||
|
||||
#define sbi_ecall_console_putc(c) SBI_ECALL_1(SBI_ECALL_CONSOLE_PUTCHAR, (c));
|
||||
|
||||
static inline void sbi_ecall_console_puts(const char *str)
|
||||
{
|
||||
while (str && *str)
|
||||
sbi_ecall_console_putc(*str++);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -12,12 +12,12 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
struct sbi_scratch;
|
||||
struct sbi_trap_regs;
|
||||
|
||||
int sbi_emulate_csr_read(int csr_num, u32 hartid, ulong mstatus,
|
||||
struct sbi_scratch *scratch, ulong *csr_val);
|
||||
int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs,
|
||||
ulong *csr_val);
|
||||
|
||||
int sbi_emulate_csr_write(int csr_num, u32 hartid, ulong mstatus,
|
||||
struct sbi_scratch *scratch, ulong csr_val);
|
||||
int sbi_emulate_csr_write(int csr_num, struct sbi_trap_regs *regs,
|
||||
ulong csr_val);
|
||||
|
||||
#endif
|
||||
|
@@ -10,22 +10,28 @@
|
||||
#ifndef __SBI_ERROR_H__
|
||||
#define __SBI_ERROR_H__
|
||||
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#define SBI_OK 0
|
||||
#define SBI_EUNKNOWN -1
|
||||
#define SBI_EFAIL -2
|
||||
#define SBI_EINVAL -3
|
||||
#define SBI_ENOENT -4
|
||||
#define SBI_ENOTSUPP -5
|
||||
#define SBI_ENODEV -6
|
||||
#define SBI_ENOSYS -7
|
||||
#define SBI_ETIMEDOUT -8
|
||||
#define SBI_EIO -9
|
||||
#define SBI_EILL -10
|
||||
#define SBI_ENOSPC -11
|
||||
#define SBI_ENOMEM -12
|
||||
#define SBI_ETRAP -13
|
||||
#define SBI_OK 0
|
||||
#define SBI_EFAIL SBI_ERR_FAILED
|
||||
#define SBI_ENOTSUPP SBI_ERR_NOT_SUPPORTED
|
||||
#define SBI_EINVAL SBI_ERR_INVALID_PARAM
|
||||
#define SBI_EDENIED SBI_ERR_DENIED
|
||||
#define SBI_EINVALID_ADDR SBI_ERR_INVALID_ADDRESS
|
||||
#define SBI_EALREADY SBI_ERR_ALREADY_AVAILABLE
|
||||
|
||||
#define SBI_ENODEV -1000
|
||||
#define SBI_ENOSYS -1001
|
||||
#define SBI_ETIMEDOUT -1002
|
||||
#define SBI_EIO -1003
|
||||
#define SBI_EILL -1004
|
||||
#define SBI_ENOSPC -1005
|
||||
#define SBI_ENOMEM -1006
|
||||
#define SBI_ETRAP -1007
|
||||
#define SBI_EUNKNOWN -1008
|
||||
#define SBI_ENOENT -1009
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
|
@@ -26,7 +26,6 @@ struct sbi_fifo {
|
||||
enum sbi_fifo_inplace_update_types {
|
||||
SBI_FIFO_SKIP,
|
||||
SBI_FIFO_UPDATED,
|
||||
SBI_FIFO_RESET,
|
||||
SBI_FIFO_UNCHANGED,
|
||||
};
|
||||
|
||||
|
@@ -12,35 +12,48 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
/** Possible feature flags of a hart */
|
||||
enum sbi_hart_features {
|
||||
/** Hart has PMP support */
|
||||
SBI_HART_HAS_PMP = (1 << 0),
|
||||
/** Hart has S-mode counter enable */
|
||||
SBI_HART_HAS_SCOUNTEREN = (1 << 1),
|
||||
/** Hart has M-mode counter enable */
|
||||
SBI_HART_HAS_MCOUNTEREN = (1 << 2),
|
||||
/** HART has timer csr implementation in hardware */
|
||||
SBI_HART_HAS_TIME = (1 << 3),
|
||||
|
||||
/** Last index of Hart features*/
|
||||
SBI_HART_HAS_LAST_FEATURE = SBI_HART_HAS_TIME,
|
||||
};
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot);
|
||||
|
||||
void *sbi_hart_get_trap_info(struct sbi_scratch *scratch);
|
||||
|
||||
void sbi_hart_set_trap_info(struct sbi_scratch *scratch, void *data);
|
||||
extern void (*sbi_hart_expected_trap)(void);
|
||||
static inline ulong sbi_hart_expected_trap_addr(void)
|
||||
{
|
||||
return (ulong)sbi_hart_expected_trap;
|
||||
}
|
||||
|
||||
void sbi_hart_delegation_dump(struct sbi_scratch *scratch);
|
||||
unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch);
|
||||
int sbi_hart_pmp_get(struct sbi_scratch *scratch, unsigned int n,
|
||||
unsigned long *prot_out, unsigned long *addr_out,
|
||||
unsigned long *size);
|
||||
void sbi_hart_pmp_dump(struct sbi_scratch *scratch);
|
||||
int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long daddr,
|
||||
unsigned long attr);
|
||||
bool sbi_hart_has_feature(struct sbi_scratch *scratch, unsigned long feature);
|
||||
void sbi_hart_get_features_str(struct sbi_scratch *scratch,
|
||||
char *features_str, int nfstr);
|
||||
|
||||
void __attribute__((noreturn)) sbi_hart_hang(void);
|
||||
|
||||
void __attribute__((noreturn))
|
||||
sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
|
||||
unsigned long next_addr, unsigned long next_mode);
|
||||
|
||||
void sbi_hart_mark_available(u32 hartid);
|
||||
|
||||
ulong sbi_hart_available_mask(void);
|
||||
|
||||
void sbi_hart_unmark_available(u32 hartid);
|
||||
|
||||
struct sbi_scratch *sbi_hart_id_to_scratch(struct sbi_scratch *scratch,
|
||||
u32 hartid);
|
||||
|
||||
void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid);
|
||||
|
||||
void sbi_hart_wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid);
|
||||
|
||||
u32 sbi_current_hartid(void);
|
||||
unsigned long next_addr, unsigned long next_mode,
|
||||
bool next_virt);
|
||||
|
||||
#endif
|
||||
|
141
include/sbi/sbi_hartmask.h
Normal file
141
include/sbi/sbi_hartmask.h
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __SBI_HARTMASK_H__
|
||||
#define __SBI_HARTMASK_H__
|
||||
|
||||
#include <sbi/sbi_bitmap.h>
|
||||
|
||||
/**
|
||||
* Maximum number of bits in a hartmask
|
||||
*
|
||||
* The hartmask is indexed using physical HART id so this define
|
||||
* also represents the maximum number of HART ids generic OpenSBI
|
||||
* can handle.
|
||||
*/
|
||||
#define SBI_HARTMASK_MAX_BITS 128
|
||||
|
||||
/** Representation of hartmask */
|
||||
struct sbi_hartmask {
|
||||
DECLARE_BITMAP(bits, SBI_HARTMASK_MAX_BITS);
|
||||
};
|
||||
|
||||
/** Initialize hartmask to zero */
|
||||
#define SBI_HARTMASK_INIT(__m) \
|
||||
bitmap_zero(((__m)->bits), SBI_HARTMASK_MAX_BITS)
|
||||
|
||||
/** Initialize hartmask to zero except a particular HART id */
|
||||
#define SBI_HARTMASK_INIT_EXCEPT(__m, __h) \
|
||||
bitmap_zero_except(((__m)->bits), (__h), SBI_HARTMASK_MAX_BITS)
|
||||
|
||||
/**
|
||||
* Get underlying bitmap of hartmask
|
||||
* @param m the hartmask pointer
|
||||
*/
|
||||
#define sbi_hartmask_bits(__m) ((__m)->bits)
|
||||
|
||||
/**
|
||||
* Set a HART in hartmask
|
||||
* @param h HART id to set
|
||||
* @param m the hartmask pointer
|
||||
*/
|
||||
static inline void sbi_hartmask_set_hart(u32 h, struct sbi_hartmask *m)
|
||||
{
|
||||
if (h < SBI_HARTMASK_MAX_BITS)
|
||||
__set_bit(h, m->bits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear a HART in hartmask
|
||||
* @param h HART id to clear
|
||||
* @param m the hartmask pointer
|
||||
*/
|
||||
static inline void sbi_hartmask_clear_hart(u32 h, struct sbi_hartmask *m)
|
||||
{
|
||||
if (h < SBI_HARTMASK_MAX_BITS)
|
||||
__clear_bit(h, m->bits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a HART in hartmask
|
||||
* @param h HART id to test
|
||||
* @param m the hartmask pointer
|
||||
*/
|
||||
static inline int sbi_hartmask_test_hart(u32 h, struct sbi_hartmask *m)
|
||||
{
|
||||
if (h < SBI_HARTMASK_MAX_BITS)
|
||||
return __test_bit(h, m->bits);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all HARTs in a hartmask
|
||||
* @param dstp the hartmask pointer
|
||||
*/
|
||||
static inline void sbi_hartmask_set_all(struct sbi_hartmask *dstp)
|
||||
{
|
||||
bitmap_fill(sbi_hartmask_bits(dstp), SBI_HARTMASK_MAX_BITS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all HARTs in a hartmask
|
||||
* @param dstp the hartmask pointer
|
||||
*/
|
||||
static inline void sbi_hartmask_clear_all(struct sbi_hartmask *dstp)
|
||||
{
|
||||
bitmap_zero(sbi_hartmask_bits(dstp), SBI_HARTMASK_MAX_BITS);
|
||||
}
|
||||
|
||||
/**
|
||||
* *dstp = *src1p & *src2p
|
||||
* @param dstp the hartmask result
|
||||
* @param src1p the first input
|
||||
* @param src2p the second input
|
||||
*/
|
||||
static inline void sbi_hartmask_and(struct sbi_hartmask *dstp,
|
||||
const struct sbi_hartmask *src1p,
|
||||
const struct sbi_hartmask *src2p)
|
||||
{
|
||||
bitmap_and(sbi_hartmask_bits(dstp), sbi_hartmask_bits(src1p),
|
||||
sbi_hartmask_bits(src2p), SBI_HARTMASK_MAX_BITS);
|
||||
}
|
||||
|
||||
/**
|
||||
* *dstp = *src1p | *src2p
|
||||
* @param dstp the hartmask result
|
||||
* @param src1p the first input
|
||||
* @param src2p the second input
|
||||
*/
|
||||
static inline void sbi_hartmask_or(struct sbi_hartmask *dstp,
|
||||
const struct sbi_hartmask *src1p,
|
||||
const struct sbi_hartmask *src2p)
|
||||
{
|
||||
bitmap_or(sbi_hartmask_bits(dstp), sbi_hartmask_bits(src1p),
|
||||
sbi_hartmask_bits(src2p), SBI_HARTMASK_MAX_BITS);
|
||||
}
|
||||
|
||||
/**
|
||||
* *dstp = *src1p ^ *src2p
|
||||
* @param dstp the hartmask result
|
||||
* @param src1p the first input
|
||||
* @param src2p the second input
|
||||
*/
|
||||
static inline void sbi_hartmask_xor(struct sbi_hartmask *dstp,
|
||||
const struct sbi_hartmask *src1p,
|
||||
const struct sbi_hartmask *src2p)
|
||||
{
|
||||
bitmap_xor(sbi_hartmask_bits(dstp), sbi_hartmask_bits(src1p),
|
||||
sbi_hartmask_bits(src2p), SBI_HARTMASK_MAX_BITS);
|
||||
}
|
||||
|
||||
/** Iterate over each HART in hartmask */
|
||||
#define sbi_hartmask_for_each_hart(__h, __m) \
|
||||
for_each_set_bit(__h, (__m)->bits, SBI_HARTMASK_MAX_BITS)
|
||||
|
||||
#endif
|
38
include/sbi/sbi_hfence.h
Normal file
38
include/sbi/sbi_hfence.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Atish Patra <atish.patra@wdc.com>
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __SBI_FENCE_H__
|
||||
#define __SBI_FENCE_H__
|
||||
|
||||
/** Invalidate Stage2 TLBs for given VMID and guest physical address */
|
||||
void __sbi_hfence_gvma_vmid_gpa(unsigned long gpa, unsigned long vmid);
|
||||
|
||||
/** Invalidate Stage2 TLBs for given VMID */
|
||||
void __sbi_hfence_gvma_vmid(unsigned long vmid);
|
||||
|
||||
/** Invalidate Stage2 TLBs for given guest physical address */
|
||||
void __sbi_hfence_gvma_gpa(unsigned long gpa);
|
||||
|
||||
/** Invalidate all possible Stage2 TLBs */
|
||||
void __sbi_hfence_gvma_all(void);
|
||||
|
||||
/** Invalidate unified TLB entries for given asid and guest virtual address */
|
||||
void __sbi_hfence_vvma_asid_va(unsigned long va, unsigned long asid);
|
||||
|
||||
/** Invalidate unified TLB entries for given ASID for a guest*/
|
||||
void __sbi_hfence_vvma_asid(unsigned long asid);
|
||||
|
||||
/** Invalidate unified TLB entries for a given guest virtual address */
|
||||
void __sbi_hfence_vvma_va(unsigned long va);
|
||||
|
||||
/** Invalidate all possible Stage2 TLBs */
|
||||
void __sbi_hfence_vvma_all(void);
|
||||
|
||||
#endif
|
36
include/sbi/sbi_hsm.h
Normal file
36
include/sbi/sbi_hsm.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Atish Patra <atish.patra@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __SBI_HSM_H__
|
||||
#define __SBI_HSM_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
/** Hart state values **/
|
||||
#define SBI_HART_STOPPED 0
|
||||
#define SBI_HART_STOPPING 1
|
||||
#define SBI_HART_STARTING 2
|
||||
#define SBI_HART_STARTED 3
|
||||
#define SBI_HART_UNKNOWN 4
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot);
|
||||
void __noreturn sbi_hsm_exit(struct sbi_scratch *scratch);
|
||||
|
||||
int sbi_hsm_hart_start(struct sbi_scratch *scratch, u32 hartid,
|
||||
ulong saddr, ulong priv);
|
||||
int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow);
|
||||
int sbi_hsm_hart_get_state(u32 hartid);
|
||||
int sbi_hsm_hart_state_to_status(int state);
|
||||
bool sbi_hsm_hart_started(u32 hartid);
|
||||
int sbi_hsm_hart_started_mask(ulong hbase, ulong *out_hmask);
|
||||
void sbi_hsm_prepare_next_jump(struct sbi_scratch *scratch, u32 hartid);
|
||||
|
||||
#endif
|
@@ -13,10 +13,7 @@
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
struct sbi_trap_regs;
|
||||
struct sbi_scratch;
|
||||
|
||||
int sbi_illegal_insn_handler(u32 hartid, ulong mcause,
|
||||
struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch);
|
||||
int sbi_illegal_insn_handler(ulong insn, struct sbi_trap_regs *regs);
|
||||
|
||||
#endif
|
||||
|
@@ -16,4 +16,8 @@ struct sbi_scratch;
|
||||
|
||||
void __noreturn sbi_init(struct sbi_scratch *scratch);
|
||||
|
||||
unsigned long sbi_init_count(u32 hartid);
|
||||
|
||||
void __noreturn sbi_exit(struct sbi_scratch *scratch);
|
||||
|
||||
#endif
|
||||
|
@@ -10,32 +10,61 @@
|
||||
#ifndef __SBI_IPI_H__
|
||||
#define __SBI_IPI_H__
|
||||
|
||||
#include <sbi/riscv_unpriv.h>
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#define SBI_IPI_EVENT_SOFT 0x1
|
||||
#define SBI_IPI_EVENT_FENCE_I 0x2
|
||||
#define SBI_IPI_EVENT_SFENCE_VMA 0x4
|
||||
#define SBI_IPI_EVENT_SFENCE_VMA_ASID 0x8
|
||||
#define SBI_IPI_EVENT_HALT 0x10
|
||||
#define SBI_IPI_EVENT_MAX __riscv_xlen
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
struct sbi_ipi_data {
|
||||
unsigned long ipi_type;
|
||||
/** IPI event operations or callbacks */
|
||||
struct sbi_ipi_event_ops {
|
||||
/** Name of the IPI event operations */
|
||||
char name[32];
|
||||
|
||||
/**
|
||||
* Update callback to save/enqueue data for remote HART
|
||||
* Note: This is an optional callback and it is called just before
|
||||
* triggering IPI to remote HART.
|
||||
*/
|
||||
int (* update)(struct sbi_scratch *scratch,
|
||||
struct sbi_scratch *remote_scratch,
|
||||
u32 remote_hartid, void *data);
|
||||
|
||||
/**
|
||||
* Sync callback to wait for remote HART
|
||||
* Note: This is an optional callback and it is called just after
|
||||
* triggering IPI to remote HART.
|
||||
*/
|
||||
void (* sync)(struct sbi_scratch *scratch);
|
||||
|
||||
/**
|
||||
* Process callback to handle IPI event
|
||||
* Note: This is a mandatory callback and it is called on the
|
||||
* remote HART after IPI is triggered.
|
||||
*/
|
||||
void (* process)(struct sbi_scratch *scratch);
|
||||
};
|
||||
|
||||
int sbi_ipi_send_many(struct sbi_scratch *scratch, struct unpriv_trap *uptrap,
|
||||
ulong *pmask, u32 event, void *data);
|
||||
int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data);
|
||||
|
||||
void sbi_ipi_clear_smode(struct sbi_scratch *scratch);
|
||||
int sbi_ipi_event_create(const struct sbi_ipi_event_ops *ops);
|
||||
|
||||
void sbi_ipi_process(struct sbi_scratch *scratch);
|
||||
void sbi_ipi_event_destroy(u32 event);
|
||||
|
||||
int sbi_ipi_send_smode(ulong hmask, ulong hbase);
|
||||
|
||||
void sbi_ipi_clear_smode(void);
|
||||
|
||||
int sbi_ipi_send_halt(ulong hmask, ulong hbase);
|
||||
|
||||
void sbi_ipi_process(void);
|
||||
|
||||
int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||
|
||||
void sbi_ipi_exit(struct sbi_scratch *scratch);
|
||||
|
||||
#endif
|
||||
|
152
include/sbi/sbi_list.h
Normal file
152
include/sbi/sbi_list.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Simple doubly-linked list library.
|
||||
*
|
||||
* Adapted from Xvisor source file libs/include/libs/list.h
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __SBI_LIST_H__
|
||||
#define __SBI_LIST_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
#define SBI_LIST_POISON_PREV 0xDEADBEEF
|
||||
#define SBI_LIST_POISON_NEXT 0xFADEBABE
|
||||
|
||||
struct sbi_dlist {
|
||||
struct sbi_dlist *next, *prev;
|
||||
};
|
||||
|
||||
#define SBI_LIST_HEAD_INIT(__lname) { &(__lname), &(__lname) }
|
||||
|
||||
#define SBI_LIST_HEAD(_lname) \
|
||||
struct sbi_dlist _lname = SBI_LIST_HEAD_INIT(_lname)
|
||||
|
||||
#define SBI_INIT_LIST_HEAD(ptr) \
|
||||
do { \
|
||||
(ptr)->next = ptr; (ptr)->prev = ptr; \
|
||||
} while (0);
|
||||
|
||||
static inline void __sbi_list_add(struct sbi_dlist *new,
|
||||
struct sbi_dlist *prev,
|
||||
struct sbi_dlist *next)
|
||||
{
|
||||
new->prev = prev;
|
||||
new->next = next;
|
||||
prev->next = new;
|
||||
next->prev = new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the new node after the given head.
|
||||
* @param new New node that needs to be added to list.
|
||||
* @param head List head after which the "new" node should be added.
|
||||
* Note: the new node is added after the head.
|
||||
*/
|
||||
static inline void sbi_list_add(struct sbi_dlist *new, struct sbi_dlist *head)
|
||||
{
|
||||
__sbi_list_add(new, head, head->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a node at the tail where tnode points to tail node.
|
||||
* @param new The new node to be added before tail.
|
||||
* @param tnode The current tail node.
|
||||
* Note: the new node is added before tail node.
|
||||
*/
|
||||
static inline void sbi_list_add_tail(struct sbi_dlist *new,
|
||||
struct sbi_dlist *tnode)
|
||||
{
|
||||
__sbi_list_add(new, tnode->prev, tnode);
|
||||
}
|
||||
|
||||
static inline void __sbi_list_del(struct sbi_dlist *prev,
|
||||
struct sbi_dlist *next)
|
||||
{
|
||||
prev->next = next;
|
||||
next->prev = prev;
|
||||
}
|
||||
|
||||
static inline void __sbi_list_del_entry(struct sbi_dlist *entry)
|
||||
{
|
||||
__sbi_list_del(entry->prev, entry->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a given entry from list.
|
||||
* @param node Node to be deleted.
|
||||
*/
|
||||
static inline void sbi_list_del(struct sbi_dlist *entry)
|
||||
{
|
||||
__sbi_list_del(entry->prev, entry->next);
|
||||
entry->next = (void *)SBI_LIST_POISON_NEXT;
|
||||
entry->prev = (void *)SBI_LIST_POISON_PREV;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes entry from list and reinitialize it.
|
||||
* @param entry the element to delete from the list.
|
||||
*/
|
||||
static inline void sbi_list_del_init(struct sbi_dlist *entry)
|
||||
{
|
||||
__sbi_list_del_entry(entry);
|
||||
SBI_INIT_LIST_HEAD(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the struct for this entry
|
||||
* @param ptr the &struct list_head pointer.
|
||||
* @param type the type of the struct this is embedded in.
|
||||
* @param member the name of the list_struct within the struct.
|
||||
*/
|
||||
#define sbi_list_entry(ptr, type, member) \
|
||||
container_of(ptr, type, member)
|
||||
|
||||
/**
|
||||
* Get the first element from a list
|
||||
* @param ptr the list head to take the element from.
|
||||
* @param type the type of the struct this is embedded in.
|
||||
* @param member the name of the list_struct within the struct.
|
||||
*
|
||||
* Note: that list is expected to be not empty.
|
||||
*/
|
||||
#define sbi_list_first_entry(ptr, type, member) \
|
||||
sbi_list_entry((ptr)->next, type, member)
|
||||
|
||||
/**
|
||||
* Get the last element from a list
|
||||
* @param ptr the list head to take the element from.
|
||||
* @param type the type of the struct this is embedded in.
|
||||
* @param member the name of the list_head within the struct.
|
||||
*
|
||||
* Note: that list is expected to be not empty.
|
||||
*/
|
||||
#define sbi_list_last_entry(ptr, type, member) \
|
||||
sbi_list_entry((ptr)->prev, type, member)
|
||||
|
||||
/**
|
||||
* Iterate over a list
|
||||
* @param pos the &struct list_head to use as a loop cursor.
|
||||
* @param head the head for your list.
|
||||
*/
|
||||
#define sbi_list_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||
|
||||
/**
|
||||
* Iterate over list of given type
|
||||
* @param pos the type * to use as a loop cursor.
|
||||
* @param head the head for your list.
|
||||
* @param member the name of the list_struct within the struct.
|
||||
*/
|
||||
#define sbi_list_for_each_entry(pos, head, member) \
|
||||
for (pos = sbi_list_entry((head)->next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = sbi_list_entry(pos->member.next, typeof(*pos), member))
|
||||
|
||||
#endif
|
15
include/sbi/sbi_math.h
Normal file
15
include/sbi/sbi_math.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Atish Patra <atish.patra@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __SBI_MATH_H__
|
||||
#define __SBI_MATH_H__
|
||||
|
||||
unsigned long log2roundup(unsigned long x);
|
||||
|
||||
#endif
|
@@ -13,14 +13,11 @@
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
struct sbi_trap_regs;
|
||||
struct sbi_scratch;
|
||||
|
||||
int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
|
||||
struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch);
|
||||
int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
|
||||
struct sbi_trap_regs *regs);
|
||||
|
||||
int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
|
||||
struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch);
|
||||
int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
|
||||
struct sbi_trap_regs *regs);
|
||||
|
||||
#endif
|
||||
|
@@ -10,9 +10,10 @@
|
||||
#ifndef __SBI_PLATFORM_H__
|
||||
#define __SBI_PLATFORM_H__
|
||||
|
||||
/** OpenSBI 32-bit platform version with:
|
||||
* 1. upper 16-bits as major number
|
||||
* 2. lower 16-bits as minor number
|
||||
/**
|
||||
* OpenSBI 32-bit platform version with:
|
||||
* 1. upper 16-bits as major number
|
||||
* 2. lower 16-bits as minor number
|
||||
*/
|
||||
#define SBI_PLATFORM_VERSION(Major, Minor) ((Major << 16) | Minor)
|
||||
|
||||
@@ -28,17 +29,22 @@
|
||||
#define SBI_PLATFORM_HART_COUNT_OFFSET (0x50)
|
||||
/** Offset of hart_stack_size in struct sbi_platform */
|
||||
#define SBI_PLATFORM_HART_STACK_SIZE_OFFSET (0x54)
|
||||
/** Offset of disabled_hart_mask in struct sbi_platform */
|
||||
#define SBI_PLATFORM_DISABLED_HART_OFFSET (0x58)
|
||||
/** Offset of platform_ops_addr in struct sbi_platform */
|
||||
#define SBI_PLATFORM_OPS_OFFSET (0x60)
|
||||
#define SBI_PLATFORM_OPS_OFFSET (0x58)
|
||||
/** Offset of firmware_context in struct sbi_platform */
|
||||
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x60 + __SIZEOF_POINTER__)
|
||||
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x58 + __SIZEOF_POINTER__)
|
||||
/** Offset of hart_index2id in struct sbi_platform */
|
||||
#define SBI_PLATFORM_HART_INDEX2ID_OFFSET (0x58 + (__SIZEOF_POINTER__ * 2))
|
||||
|
||||
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT (1UL << 12)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <sbi/sbi_version.h>
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
#include <sbi/sbi_version.h>
|
||||
|
||||
/** Possible feature flags of a platform */
|
||||
enum sbi_platform_features {
|
||||
@@ -46,21 +52,18 @@ enum sbi_platform_features {
|
||||
SBI_PLATFORM_HAS_TIMER_VALUE = (1 << 0),
|
||||
/** Platform has HART hotplug support */
|
||||
SBI_PLATFORM_HAS_HART_HOTPLUG = (1 << 1),
|
||||
/** Platform has PMP support */
|
||||
SBI_PLATFORM_HAS_PMP = (1 << 2),
|
||||
/** Platform has S-mode counter enable */
|
||||
SBI_PLATFORM_HAS_SCOUNTEREN = (1 << 3),
|
||||
/** Platform has M-mode counter enable */
|
||||
SBI_PLATFORM_HAS_MCOUNTEREN = (1 << 4),
|
||||
/** Platform has fault delegation support */
|
||||
SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 5),
|
||||
SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 2),
|
||||
/** Platform has custom secondary hart booting support */
|
||||
SBI_PLATFORM_HAS_HART_SECONDARY_BOOT = (1 << 3),
|
||||
|
||||
/** Last index of Platform features*/
|
||||
SBI_PLATFORM_HAS_LAST_FEATURE = SBI_PLATFORM_HAS_HART_SECONDARY_BOOT,
|
||||
};
|
||||
|
||||
/** Default feature set for a platform */
|
||||
#define SBI_PLATFORM_DEFAULT_FEATURES \
|
||||
(SBI_PLATFORM_HAS_TIMER_VALUE | SBI_PLATFORM_HAS_PMP | \
|
||||
SBI_PLATFORM_HAS_SCOUNTEREN | SBI_PLATFORM_HAS_MCOUNTEREN | \
|
||||
SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
|
||||
(SBI_PLATFORM_HAS_TIMER_VALUE | SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
|
||||
|
||||
/** Platform functions */
|
||||
struct sbi_platform_operations {
|
||||
@@ -69,6 +72,23 @@ struct sbi_platform_operations {
|
||||
/** Platform final initialization */
|
||||
int (*final_init)(bool cold_boot);
|
||||
|
||||
/** Platform early exit */
|
||||
void (*early_exit)(void);
|
||||
/** Platform final exit */
|
||||
void (*final_exit)(void);
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
u32 (*pmp_region_count)(u32 hartid);
|
||||
/**
|
||||
@@ -87,15 +107,20 @@ struct sbi_platform_operations {
|
||||
|
||||
/** Initialize the platform interrupt controller for current HART */
|
||||
int (*irqchip_init)(bool cold_boot);
|
||||
/** Exit the platform interrupt controller for current HART */
|
||||
void (*irqchip_exit)(void);
|
||||
|
||||
/** Send IPI to a target HART */
|
||||
void (*ipi_send)(u32 target_hart);
|
||||
/** Wait for target HART to acknowledge IPI */
|
||||
void (*ipi_sync)(u32 target_hart);
|
||||
/** Clear IPI for a target HART */
|
||||
void (*ipi_clear)(u32 target_hart);
|
||||
/** Initialize IPI for current HART */
|
||||
int (*ipi_init)(bool cold_boot);
|
||||
/** Exit IPI for current HART */
|
||||
void (*ipi_exit)(void);
|
||||
|
||||
/** Get tlb flush limit value **/
|
||||
u64 (*get_tlbr_flush_limit)(void);
|
||||
|
||||
/** Get platform timer value */
|
||||
u64 (*timer_value)(void);
|
||||
@@ -105,13 +130,35 @@ struct sbi_platform_operations {
|
||||
void (*timer_event_stop)(void);
|
||||
/** Initialize platform timer for current HART */
|
||||
int (*timer_init)(bool cold_boot);
|
||||
/** Exit platform timer for current HART */
|
||||
void (*timer_exit)(void);
|
||||
|
||||
/** Reboot the platform */
|
||||
int (*system_reboot)(u32 type);
|
||||
/** Shutdown or poweroff the platform */
|
||||
int (*system_shutdown)(u32 type);
|
||||
/** Bringup the given hart */
|
||||
int (*hart_start)(u32 hartid, ulong saddr);
|
||||
/**
|
||||
* Stop the current hart from running. This call doesn't expect to
|
||||
* return if success.
|
||||
*/
|
||||
int (*hart_stop)(void);
|
||||
|
||||
/** Reset the platform */
|
||||
#define SBI_PLATFORM_RESET_SHUTDOWN 0
|
||||
#define SBI_PLATFORM_RESET_COLD 1
|
||||
#define SBI_PLATFORM_RESET_WARM 2
|
||||
int (*system_reset)(u32 reset_type);
|
||||
|
||||
/** platform specific SBI extension implementation probe function */
|
||||
int (*vendor_ext_check)(long extid);
|
||||
/** platform specific SBI extension implementation provider */
|
||||
int (*vendor_ext_provider)(long extid, long funcid,
|
||||
unsigned long *args,
|
||||
unsigned long *out_value,
|
||||
struct sbi_trap_info *out_trap);
|
||||
} __packed;
|
||||
|
||||
/** Platform default per-HART stack size for exception/interrupt handling */
|
||||
#define SBI_PLATFORM_DEFAULT_HART_STACK_SIZE 8192
|
||||
|
||||
/** Representation of a platform */
|
||||
struct sbi_platform {
|
||||
/**
|
||||
@@ -134,12 +181,26 @@ struct sbi_platform {
|
||||
u32 hart_count;
|
||||
/** Per-HART stack size for exception/interrupt handling */
|
||||
u32 hart_stack_size;
|
||||
/** Mask representing the set of disabled HARTs */
|
||||
u64 disabled_hart_mask;
|
||||
/** Pointer to sbi platform operations */
|
||||
unsigned long platform_ops_addr;
|
||||
/** Pointer to system firmware specific context */
|
||||
unsigned long firmware_context;
|
||||
/**
|
||||
* HART index to HART id table
|
||||
*
|
||||
* For used HART index <abc>:
|
||||
* hart_index2id[<abc>] = some HART id
|
||||
* For unused HART index <abc>:
|
||||
* hart_index2id[<abc>] = -1U
|
||||
*
|
||||
* If hart_index2id == NULL then we assume identity mapping
|
||||
* hart_index2id[<abc>] = <abc>
|
||||
*
|
||||
* We have only two restrictions:
|
||||
* 1. HART index < sbi_platform hart_count
|
||||
* 2. HART id < SBI_HARTMASK_MAX_BITS
|
||||
*/
|
||||
const u32 *hart_index2id;
|
||||
} __packed;
|
||||
|
||||
/** Get pointer to sbi_platform for sbi_scratch pointer */
|
||||
@@ -158,46 +219,78 @@ struct sbi_platform {
|
||||
/** Check whether the platform supports HART hotplug */
|
||||
#define sbi_platform_has_hart_hotplug(__p) \
|
||||
((__p)->features & SBI_PLATFORM_HAS_HART_HOTPLUG)
|
||||
/** Check whether the platform has PMP support */
|
||||
#define sbi_platform_has_pmp(__p) ((__p)->features & SBI_PLATFORM_HAS_PMP)
|
||||
/** Check whether the platform supports scounteren CSR */
|
||||
#define sbi_platform_has_scounteren(__p) \
|
||||
((__p)->features & SBI_PLATFORM_HAS_SCOUNTEREN)
|
||||
/** Check whether the platform supports mcounteren CSR */
|
||||
#define sbi_platform_has_mcounteren(__p) \
|
||||
((__p)->features & SBI_PLATFORM_HAS_MCOUNTEREN)
|
||||
/** Check whether the platform supports fault delegation */
|
||||
#define sbi_platform_has_mfaults_delegation(__p) \
|
||||
((__p)->features & SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
|
||||
/** Check whether the platform supports custom secondary hart booting support */
|
||||
#define sbi_platform_has_hart_secondary_boot(__p) \
|
||||
((__p)->features & SBI_PLATFORM_HAS_HART_SECONDARY_BOOT)
|
||||
|
||||
/**
|
||||
* Get HART index for the given HART
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param hartid HART ID
|
||||
*
|
||||
* @return 0 <= value < hart_count for valid HART otherwise -1U
|
||||
*/
|
||||
u32 sbi_platform_hart_index(const struct sbi_platform *plat, u32 hartid);
|
||||
|
||||
/**
|
||||
* Get the platform features in string format
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param features_str pointer to a char array where the features string will be
|
||||
* updated
|
||||
* @param nfstr length of the features_str. The feature string will be truncated
|
||||
* if nfstr is not long enough.
|
||||
*/
|
||||
void sbi_platform_get_features_str(const struct sbi_platform *plat,
|
||||
char *features_str, int nfstr);
|
||||
|
||||
/**
|
||||
* Get name of the platform
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*
|
||||
* @return pointer to platform name on success and NULL on failure
|
||||
* @return pointer to platform name on success and "Unknown" on failure
|
||||
*/
|
||||
static inline const char *sbi_platform_name(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat)
|
||||
return plat->name;
|
||||
return NULL;
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given HART is disabled
|
||||
* Get the platform features
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param hartid HART ID
|
||||
*
|
||||
* @return TRUE if HART is disabled and FALSE otherwise
|
||||
* @return the features value currently set for the given platform
|
||||
*/
|
||||
static inline bool sbi_platform_hart_disabled(const struct sbi_platform *plat,
|
||||
u32 hartid)
|
||||
static inline unsigned long sbi_platform_get_features(
|
||||
const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && (plat->disabled_hart_mask & (1 << hartid)))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
if (plat)
|
||||
return plat->features;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get platform specific tlb range flush maximum value. Any request with size
|
||||
* higher than this is upgraded to a full flush.
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*
|
||||
* @return tlb range flush limit value. Returns a default (page size) if not
|
||||
* defined by platform.
|
||||
*/
|
||||
static inline u64 sbi_platform_tlbr_flush_limit(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->get_tlbr_flush_limit)
|
||||
return sbi_platform_ops(plat)->get_tlbr_flush_limit();
|
||||
return SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,6 +321,57 @@ static inline u32 sbi_platform_hart_stack_size(const struct sbi_platform *plat)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether given HART is invalid
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param hartid HART ID
|
||||
*
|
||||
* @return TRUE if HART is invalid and FALSE otherwise
|
||||
*/
|
||||
static inline bool sbi_platform_hart_invalid(const struct sbi_platform *plat,
|
||||
u32 hartid)
|
||||
{
|
||||
if (!plat)
|
||||
return TRUE;
|
||||
if (plat->hart_count <= sbi_platform_hart_index(plat, hartid))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bringup a given hart from previous stage. Platform should implement this
|
||||
* operation if they support a custom mechanism to start a hart. Otherwise,
|
||||
* a generic WFI based approach will be used to start/stop a hart in OpenSBI.
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param hartid HART id
|
||||
* @param saddr M-mode start physical address for the HART
|
||||
*
|
||||
* @return 0 if sucessful and negative error code on failure
|
||||
*/
|
||||
static inline int sbi_platform_hart_start(const struct sbi_platform *plat,
|
||||
u32 hartid, ulong saddr)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->hart_start)
|
||||
return sbi_platform_ops(plat)->hart_start(hartid, saddr);
|
||||
return SBI_ENOTSUPP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the current hart in OpenSBI.
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*
|
||||
* @return Negative error code on failure. It doesn't return on success.
|
||||
*/
|
||||
static inline int sbi_platform_hart_stop(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->hart_stop)
|
||||
return sbi_platform_ops(plat)->hart_stop();
|
||||
return SBI_ENOTSUPP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Early initialization for current HART
|
||||
*
|
||||
@@ -260,6 +404,58 @@ static inline int sbi_platform_final_init(const struct sbi_platform *plat,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Early exit for current HART
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*/
|
||||
static inline void sbi_platform_early_exit(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->early_exit)
|
||||
sbi_platform_ops(plat)->early_exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Final exit for current HART
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*/
|
||||
static inline void sbi_platform_final_exit(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->final_exit)
|
||||
sbi_platform_ops(plat)->final_exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
@@ -295,8 +491,9 @@ static inline int sbi_platform_pmp_region_info(const struct sbi_platform *plat,
|
||||
ulong *log2size)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->pmp_region_info)
|
||||
return sbi_platform_ops(plat)->pmp_region_info(hartid, index, prot, addr,
|
||||
log2size);
|
||||
return sbi_platform_ops(plat)->pmp_region_info(hartid, index,
|
||||
prot, addr,
|
||||
log2size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -357,6 +554,17 @@ static inline int sbi_platform_irqchip_init(const struct sbi_platform *plat,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit the platform interrupt controller for current HART
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*/
|
||||
static inline void sbi_platform_irqchip_exit(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->irqchip_exit)
|
||||
sbi_platform_ops(plat)->irqchip_exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send IPI to a target HART
|
||||
*
|
||||
@@ -370,19 +578,6 @@ static inline void sbi_platform_ipi_send(const struct sbi_platform *plat,
|
||||
sbi_platform_ops(plat)->ipi_send(target_hart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for target HART to acknowledge IPI
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param target_hart HART ID of IPI target
|
||||
*/
|
||||
static inline void sbi_platform_ipi_sync(const struct sbi_platform *plat,
|
||||
u32 target_hart)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->ipi_sync)
|
||||
sbi_platform_ops(plat)->ipi_sync(target_hart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear IPI for a target HART
|
||||
*
|
||||
@@ -412,12 +607,23 @@ static inline int sbi_platform_ipi_init(const struct sbi_platform *plat,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit the platform IPI support for current HART
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*/
|
||||
static inline void sbi_platform_ipi_exit(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->ipi_exit)
|
||||
sbi_platform_ops(plat)->ipi_exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get platform timer value
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*
|
||||
* @return 64bit timer value
|
||||
* @return 64-bit timer value
|
||||
*/
|
||||
static inline u64 sbi_platform_timer_value(const struct sbi_platform *plat)
|
||||
{
|
||||
@@ -468,35 +674,76 @@ static inline int sbi_platform_timer_init(const struct sbi_platform *plat,
|
||||
}
|
||||
|
||||
/**
|
||||
* Reboot the platform
|
||||
* Exit the platform timer for current HART
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param type type of reboot
|
||||
*/
|
||||
static inline void sbi_platform_timer_exit(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->timer_exit)
|
||||
sbi_platform_ops(plat)->timer_exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the platform
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param reset_type type of reset
|
||||
*
|
||||
* @return 0 on success and negative error code on failure
|
||||
*/
|
||||
static inline int sbi_platform_system_reboot(const struct sbi_platform *plat,
|
||||
u32 type)
|
||||
static inline int sbi_platform_system_reset(const struct sbi_platform *plat,
|
||||
u32 reset_type)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->system_reboot)
|
||||
return sbi_platform_ops(plat)->system_reboot(type);
|
||||
if (plat && sbi_platform_ops(plat)->system_reset)
|
||||
return sbi_platform_ops(plat)->system_reset(reset_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown or poweroff the platform
|
||||
* Check if a vendor extension is implemented or not.
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param type type of shutdown or poweroff
|
||||
* @param extid vendor SBI extension id
|
||||
*
|
||||
* @return 0 if extid is not implemented and 1 if implemented
|
||||
*/
|
||||
static inline int sbi_platform_vendor_ext_check(const struct sbi_platform *plat,
|
||||
long extid)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->vendor_ext_check)
|
||||
return sbi_platform_ops(plat)->vendor_ext_check(extid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke platform specific vendor SBI extension implementation.
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param extid vendor SBI extension id
|
||||
* @param funcid SBI function id within the extension id
|
||||
* @param args pointer to arguments passed by the caller
|
||||
* @param out_value output value that can be filled by the callee
|
||||
* @param out_trap trap info that can be filled by the callee
|
||||
*
|
||||
* @return 0 on success and negative error code on failure
|
||||
*/
|
||||
static inline int sbi_platform_system_shutdown(const struct sbi_platform *plat,
|
||||
u32 type)
|
||||
static inline int sbi_platform_vendor_ext_provider(
|
||||
const struct sbi_platform *plat,
|
||||
long extid, long funcid,
|
||||
unsigned long *args,
|
||||
unsigned long *out_value,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->system_shutdown)
|
||||
return sbi_platform_ops(plat)->system_shutdown(type);
|
||||
return 0;
|
||||
if (plat && sbi_platform_ops(plat)->vendor_ext_provider) {
|
||||
return sbi_platform_ops(plat)->vendor_ext_provider(extid,
|
||||
funcid, args,
|
||||
out_value,
|
||||
out_trap);
|
||||
}
|
||||
|
||||
return SBI_ENOTSUPP;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -36,15 +36,14 @@
|
||||
#define SBI_SCRATCH_OPTIONS_OFFSET (9 * __SIZEOF_POINTER__)
|
||||
/** Offset of extra space in sbi_scratch */
|
||||
#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (10 * __SIZEOF_POINTER__)
|
||||
/** Maximum size of sbi_scratch and sbi_ipi_data */
|
||||
#define SBI_SCRATCH_SIZE (64 * __SIZEOF_POINTER__)
|
||||
/** Maximum size of sbi_scratch (4KB) */
|
||||
#define SBI_SCRATCH_SIZE (0x1000)
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
#include <sbi/sbi_ipi.h>
|
||||
|
||||
/** Representation of per-HART scratch space */
|
||||
struct sbi_scratch {
|
||||
@@ -74,6 +73,8 @@ struct sbi_scratch {
|
||||
enum sbi_scratch_options {
|
||||
/** Disable prints during boot */
|
||||
SBI_SCRATCH_NO_BOOT_PRINTS = (1 << 0),
|
||||
/** Enable runtime debug prints */
|
||||
SBI_SCRATCH_DEBUG_PRINTS = (1 << 1),
|
||||
};
|
||||
|
||||
/** Get pointer to sbi_scratch for current HART */
|
||||
@@ -84,7 +85,11 @@ enum sbi_scratch_options {
|
||||
#define sbi_scratch_thishart_arg1_ptr() \
|
||||
((void *)(sbi_scratch_thishart_ptr()->next_arg1))
|
||||
|
||||
/** Allocate from extra space in sbi_scratch
|
||||
/** Initialize scatch table and allocator */
|
||||
int sbi_scratch_init(struct sbi_scratch *scratch);
|
||||
|
||||
/**
|
||||
* Allocate from extra space in sbi_scratch
|
||||
*
|
||||
* @return zero on failure and non-zero (>= SBI_SCRATCH_EXTRA_SPACE_OFFSET)
|
||||
* on success
|
||||
@@ -101,6 +106,19 @@ void sbi_scratch_free_offset(unsigned long offset);
|
||||
#define sbi_scratch_thishart_offset_ptr(offset) \
|
||||
((void *)sbi_scratch_thishart_ptr() + (offset))
|
||||
|
||||
/** HART id to scratch table */
|
||||
extern struct sbi_scratch *hartid_to_scratch_table[];
|
||||
|
||||
/** Get sbi_scratch from HART id */
|
||||
#define sbi_hartid_to_scratch(__hartid) \
|
||||
hartid_to_scratch_table[__hartid]
|
||||
|
||||
/** Last HART id having a sbi_scratch pointer */
|
||||
extern u32 last_hartid_having_scratch;
|
||||
|
||||
/** Get last HART id having a sbi_scratch pointer */
|
||||
#define sbi_scratch_last_hartid() last_hartid_having_scratch
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@@ -12,16 +12,6 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
int sbi_system_early_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||
|
||||
int sbi_system_final_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||
|
||||
void __attribute__((noreturn))
|
||||
sbi_system_reboot(struct sbi_scratch *scratch, u32 type);
|
||||
|
||||
void __attribute__((noreturn))
|
||||
sbi_system_shutdown(struct sbi_scratch *scratch, u32 type);
|
||||
void __noreturn sbi_system_reset(u32 platform_reset_type);
|
||||
|
||||
#endif
|
||||
|
@@ -14,14 +14,31 @@
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
u64 sbi_timer_value(struct sbi_scratch *scratch);
|
||||
/** Get timer value for current HART */
|
||||
u64 sbi_timer_value(void);
|
||||
|
||||
void sbi_timer_event_stop(struct sbi_scratch *scratch);
|
||||
/** Get virtualized timer value for current HART */
|
||||
u64 sbi_timer_virt_value(void);
|
||||
|
||||
void sbi_timer_event_start(struct sbi_scratch *scratch, u64 next_event);
|
||||
/** Get timer delta value for current HART */
|
||||
u64 sbi_timer_get_delta(void);
|
||||
|
||||
void sbi_timer_process(struct sbi_scratch *scratch);
|
||||
/** Set timer delta value for current HART */
|
||||
void sbi_timer_set_delta(ulong delta);
|
||||
|
||||
/** Set upper 32-bits of timer delta value for current HART */
|
||||
void sbi_timer_set_delta_upper(ulong delta_upper);
|
||||
|
||||
/** Start timer event for current HART */
|
||||
void sbi_timer_event_start(u64 next_event);
|
||||
|
||||
/** Process timer event for current HART */
|
||||
void sbi_timer_process(void);
|
||||
|
||||
/* Initialize timer */
|
||||
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||
|
||||
/* Exit timer */
|
||||
void sbi_timer_exit(struct sbi_scratch *scratch);
|
||||
|
||||
#endif
|
||||
|
@@ -12,20 +12,24 @@
|
||||
#define __SBI_TLB_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
#include <sbi/sbi_hartmask.h>
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#define SBI_TLB_FLUSH_ALL ((unsigned long)-1)
|
||||
#define SBI_TLB_FLUSH_MAX_SIZE (1UL << 30)
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
#define SBI_TLB_FIFO_NUM_ENTRIES 4
|
||||
#define SBI_TLB_FIFO_NUM_ENTRIES 8
|
||||
|
||||
enum sbi_tlb_info_types {
|
||||
SBI_TLB_FLUSH_VMA,
|
||||
SBI_TLB_FLUSH_VMA_ASID,
|
||||
SBI_TLB_FLUSH_VMA_VMID
|
||||
SBI_TLB_FLUSH_GVMA,
|
||||
SBI_TLB_FLUSH_GVMA_VMID,
|
||||
SBI_TLB_FLUSH_VVMA,
|
||||
SBI_TLB_FLUSH_VVMA_ASID,
|
||||
SBI_ITLB_FLUSH
|
||||
};
|
||||
|
||||
struct sbi_scratch;
|
||||
@@ -34,15 +38,25 @@ struct sbi_tlb_info {
|
||||
unsigned long start;
|
||||
unsigned long size;
|
||||
unsigned long asid;
|
||||
unsigned long vmid;
|
||||
unsigned long type;
|
||||
struct sbi_hartmask smask;
|
||||
};
|
||||
|
||||
#define SBI_TLB_INFO_SIZE sizeof(struct sbi_tlb_info)
|
||||
#define SBI_TLB_INFO_INIT(__p, __start, __size, __asid, __vmid, __type, __src) \
|
||||
do { \
|
||||
(__p)->start = (__start); \
|
||||
(__p)->size = (__size); \
|
||||
(__p)->asid = (__asid); \
|
||||
(__p)->vmid = (__vmid); \
|
||||
(__p)->type = (__type); \
|
||||
SBI_HARTMASK_INIT_EXCEPT(&(__p)->smask, (__src)); \
|
||||
} while (0)
|
||||
|
||||
int sbi_tlb_fifo_update(struct sbi_scratch *scratch, u32 event, void *data);
|
||||
#define SBI_TLB_INFO_SIZE sizeof(struct sbi_tlb_info)
|
||||
|
||||
void sbi_tlb_fifo_process(struct sbi_scratch *scratch, u32 event);
|
||||
int sbi_tlb_request(ulong hmask, ulong hbase, struct sbi_tlb_info *tinfo);
|
||||
|
||||
int sbi_tlb_fifo_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||
int sbi_tlb_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||
|
||||
#endif
|
||||
|
@@ -80,8 +80,23 @@
|
||||
#define SBI_TRAP_REGS_mepc 32
|
||||
/** Index of mstatus member in sbi_trap_regs */
|
||||
#define SBI_TRAP_REGS_mstatus 33
|
||||
/** Index of mstatusH member in sbi_trap_regs */
|
||||
#define SBI_TRAP_REGS_mstatusH 34
|
||||
/** Last member index in sbi_trap_regs */
|
||||
#define SBI_TRAP_REGS_last 34
|
||||
#define SBI_TRAP_REGS_last 35
|
||||
|
||||
/** Index of epc member in sbi_trap_info */
|
||||
#define SBI_TRAP_INFO_epc 0
|
||||
/** Index of cause member in sbi_trap_info */
|
||||
#define SBI_TRAP_INFO_cause 1
|
||||
/** Index of tval member in sbi_trap_info */
|
||||
#define SBI_TRAP_INFO_tval 2
|
||||
/** Index of tval2 member in sbi_trap_info */
|
||||
#define SBI_TRAP_INFO_tval2 3
|
||||
/** Index of tinst member in sbi_trap_info */
|
||||
#define SBI_TRAP_INFO_tinst 4
|
||||
/** Last member index in sbi_trap_info */
|
||||
#define SBI_TRAP_INFO_last 5
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
@@ -90,6 +105,11 @@
|
||||
/** Size (in bytes) of sbi_trap_regs */
|
||||
#define SBI_TRAP_REGS_SIZE SBI_TRAP_REGS_OFFSET(last)
|
||||
|
||||
/** Get offset of member with name 'x' in sbi_trap_info */
|
||||
#define SBI_TRAP_INFO_OFFSET(x) ((SBI_TRAP_INFO_##x) * __SIZEOF_POINTER__)
|
||||
/** Size (in bytes) of sbi_trap_info */
|
||||
#define SBI_TRAP_INFO_SIZE SBI_TRAP_INFO_OFFSET(last)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
@@ -164,14 +184,28 @@ struct sbi_trap_regs {
|
||||
unsigned long mepc;
|
||||
/** mstatus register state */
|
||||
unsigned long mstatus;
|
||||
/** mstatusH register state (only for 32-bit) */
|
||||
unsigned long mstatusH;
|
||||
} __packed;
|
||||
|
||||
struct sbi_scratch;
|
||||
/** Representation of trap details */
|
||||
struct sbi_trap_info {
|
||||
/** epc Trap program counter */
|
||||
unsigned long epc;
|
||||
/** cause Trap exception cause */
|
||||
unsigned long cause;
|
||||
/** tval Trap value */
|
||||
unsigned long tval;
|
||||
/** tval2 Trap value 2 */
|
||||
unsigned long tval2;
|
||||
/** tinst Trap instruction */
|
||||
unsigned long tinst;
|
||||
};
|
||||
|
||||
int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch,
|
||||
ulong epc, ulong cause, ulong tval);
|
||||
int sbi_trap_redirect(struct sbi_trap_regs *regs,
|
||||
struct sbi_trap_info *trap);
|
||||
|
||||
void sbi_trap_handler(struct sbi_trap_regs *regs, struct sbi_scratch *scratch);
|
||||
void sbi_trap_handler(struct sbi_trap_regs *regs);
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -10,6 +10,8 @@
|
||||
#ifndef __SBI_TYPES_H__
|
||||
#define __SBI_TYPES_H__
|
||||
|
||||
#ifndef OPENSBI_EXTERNAL_SBI_TYPES
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
typedef char s8;
|
||||
@@ -54,12 +56,54 @@ typedef unsigned long physical_size_t;
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#define true TRUE
|
||||
#define false FALSE
|
||||
|
||||
#define NULL ((void *)0)
|
||||
|
||||
#define __packed __attribute__((packed))
|
||||
#define __noreturn __attribute__((noreturn))
|
||||
|
||||
#define likely(x) __builtin_expect((x), 1)
|
||||
#define unlikely(x) __builtin_expect((x), 0)
|
||||
|
||||
#undef offsetof
|
||||
#ifdef __compiler_offsetof
|
||||
#define offsetof(TYPE, MEMBER) __compiler_offsetof(TYPE,MEMBER)
|
||||
#else
|
||||
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||
#endif
|
||||
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
const typeof(((type *)0)->member) * __mptr = (ptr); \
|
||||
(type *)((char *)__mptr - offsetof(type, member)); })
|
||||
|
||||
#define array_size(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define CLAMP(a, lo, hi) MIN(MAX(a, lo), hi)
|
||||
|
||||
#define STR(x) XSTR(x)
|
||||
#define XSTR(x) #x
|
||||
|
||||
#define ROUNDUP(a, b) ((((a)-1) / (b) + 1) * (b))
|
||||
#define ROUNDDOWN(a, b) ((a) / (b) * (b))
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
#else
|
||||
/*
|
||||
* OPENSBI_EXTERNAL_SBI_TYPES could be defined in CFLAGS for using the
|
||||
* external definitions of data types and common macros.
|
||||
* OPENSBI_EXTERNAL_SBI_TYPES is the file name to external header file,
|
||||
* the external build system should address the additional include
|
||||
* directory ccordingly.
|
||||
*/
|
||||
|
||||
#define XSTR(x) #x
|
||||
#define STR(x) XSTR(x)
|
||||
#include STR(OPENSBI_EXTERNAL_SBI_TYPES)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@@ -7,28 +7,21 @@
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __RISCV_UNPRIV_H__
|
||||
#define __RISCV_UNPRIV_H__
|
||||
#ifndef __SBI_UNPRIV_H__
|
||||
#define __SBI_UNPRIV_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
struct sbi_scratch;
|
||||
struct sbi_trap_info;
|
||||
|
||||
struct unpriv_trap {
|
||||
unsigned long ilen;
|
||||
unsigned long cause;
|
||||
unsigned long tval;
|
||||
};
|
||||
#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type) \
|
||||
type sbi_load_##type(const type *addr, \
|
||||
struct sbi_trap_info *trap);
|
||||
|
||||
#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type) \
|
||||
type load_##type(const type *addr, \
|
||||
struct sbi_scratch *scratch, \
|
||||
struct unpriv_trap *trap);
|
||||
|
||||
#define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type) \
|
||||
void store_##type(type *addr, type val, \
|
||||
struct sbi_scratch *scratch, \
|
||||
struct unpriv_trap *trap);
|
||||
#define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type) \
|
||||
void sbi_store_##type(type *addr, type val, \
|
||||
struct sbi_trap_info *trap);
|
||||
|
||||
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u8)
|
||||
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u16)
|
||||
@@ -43,6 +36,6 @@ DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u64)
|
||||
DECLARE_UNPRIVILEGED_STORE_FUNCTION(u64)
|
||||
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong)
|
||||
|
||||
ulong get_insn(ulong mepc, ulong *mstatus);
|
||||
ulong sbi_get_insn(ulong mepc, struct sbi_trap_info *trap);
|
||||
|
||||
#endif
|
@@ -11,12 +11,12 @@
|
||||
#define __SBI_VERSION_H__
|
||||
|
||||
#define OPENSBI_VERSION_MAJOR 0
|
||||
#define OPENSBI_VERSION_MINOR 4
|
||||
#define OPENSBI_VERSION_MINOR 8
|
||||
|
||||
/**
|
||||
* OpenSBI 32-bit version with:
|
||||
* 1. upper 16-bits as major number
|
||||
* 2. lower 16-bits as minor number
|
||||
* OpenSBI 32-bit version with:
|
||||
* 1. upper 16-bits as major number
|
||||
* 2. lower 16-bits as minor number
|
||||
*/
|
||||
#define OPENSBI_VERSION ((OPENSBI_VERSION_MAJOR << 16) | \
|
||||
(OPENSBI_VERSION_MINOR))
|
||||
|
78
include/sbi_utils/fdt/fdt_fixup.h
Normal file
78
include/sbi_utils/fdt/fdt_fixup.h
Normal file
@@ -0,0 +1,78 @@
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
/*
|
||||
* fdt_fixup.h - Flat Device Tree manipulation helper routines
|
||||
* Implement platform specific DT fixups on top of libfdt.
|
||||
*
|
||||
* Copyright (C) 2020 Bin Meng <bmeng.cn@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __FDT_FIXUP_H__
|
||||
#define __FDT_FIXUP_H__
|
||||
|
||||
/**
|
||||
* Fix up the CPU node in the device tree
|
||||
*
|
||||
* This routine updates the "status" property of a CPU node in the device tree
|
||||
* to "disabled" if that hart is in disabled state in OpenSBI.
|
||||
*
|
||||
* It is recommended that platform codes call this helper in their final_init()
|
||||
*
|
||||
* @param fdt: device tree blob
|
||||
*/
|
||||
void fdt_cpu_fixup(void *fdt);
|
||||
|
||||
/**
|
||||
* Fix up the PLIC node in the device tree
|
||||
*
|
||||
* This routine updates the "interrupt-extended" property of the PLIC node in
|
||||
* the device tree to hide the M-mode external interrupt from CPUs.
|
||||
*
|
||||
* It is recommended that platform codes call this helper in their final_init()
|
||||
*
|
||||
* @param fdt: device tree blob
|
||||
* @param compat: PLIC node compatible string
|
||||
*/
|
||||
void fdt_plic_fixup(void *fdt, const char *compat);
|
||||
|
||||
/**
|
||||
* Fix up the reserved memory node in the device tree
|
||||
*
|
||||
* This routine inserts a child node of the reserved memory node in the device
|
||||
* tree that describes the protected memory region done by OpenSBI via PMP.
|
||||
*
|
||||
* It is recommended that platform codes call this helper in their final_init()
|
||||
*
|
||||
* @param fdt: device tree blob
|
||||
* @return zero on success and -ve on failure
|
||||
*/
|
||||
int fdt_reserved_memory_fixup(void *fdt);
|
||||
|
||||
/**
|
||||
* Fix up the reserved memory subnodes in the device tree
|
||||
*
|
||||
* This routine adds the no-map property to the reserved memory subnodes so
|
||||
* that the OS does not map those PMP protected memory regions.
|
||||
*
|
||||
* Platform codes must call this helper in their final_init() after fdt_fixups()
|
||||
* if the OS should not map the PMP protected reserved regions.
|
||||
*
|
||||
* @param fdt: device tree blob
|
||||
* @return zero on success and -ve on failure
|
||||
*/
|
||||
int fdt_reserved_memory_nomap_fixup(void *fdt);
|
||||
|
||||
/**
|
||||
* General device tree fix-up
|
||||
*
|
||||
* This routine do all required device tree fix-ups for a typical platform.
|
||||
* It fixes up the PLIC node and the reserved memory node in the device tree
|
||||
* by calling the corresponding helper routines to accomplish the task.
|
||||
*
|
||||
* It is recommended that platform codes call this helper in their final_init()
|
||||
*
|
||||
* @param fdt: device tree blob
|
||||
*/
|
||||
void fdt_fixups(void *fdt);
|
||||
|
||||
#endif /* __FDT_FIXUP_H__ */
|
||||
|
68
include/sbi_utils/fdt/fdt_helper.h
Normal file
68
include/sbi_utils/fdt/fdt_helper.h
Normal file
@@ -0,0 +1,68 @@
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
/*
|
||||
* fdt_helper.h - Flat Device Tree parsing helper routines
|
||||
* Implement helper routines to parse FDT nodes on top of
|
||||
* libfdt for OpenSBI usage
|
||||
*
|
||||
* Copyright (C) 2020 Bin Meng <bmeng.cn@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __FDT_HELPER_H__
|
||||
#define __FDT_HELPER_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
struct fdt_match {
|
||||
const char *compatible;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct platform_uart_data {
|
||||
unsigned long addr;
|
||||
unsigned long freq;
|
||||
unsigned long baud;
|
||||
unsigned long reg_shift;
|
||||
unsigned long reg_io_width;
|
||||
};
|
||||
|
||||
const struct fdt_match *fdt_match_node(void *fdt, int nodeoff,
|
||||
const struct fdt_match *match_table);
|
||||
|
||||
int fdt_find_match(void *fdt, int startoff,
|
||||
const struct fdt_match *match_table,
|
||||
const struct fdt_match **out_match);
|
||||
|
||||
int fdt_get_node_addr_size(void *fdt, int node, unsigned long *addr,
|
||||
unsigned long *size);
|
||||
|
||||
int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid);
|
||||
|
||||
int fdt_parse_max_hart_id(void *fdt, u32 *max_hartid);
|
||||
|
||||
int fdt_parse_shakti_uart_node(void *fdt, int nodeoffset,
|
||||
struct platform_uart_data *uart);
|
||||
|
||||
int fdt_parse_sifive_uart_node(void *fdt, int nodeoffset,
|
||||
struct platform_uart_data *uart);
|
||||
|
||||
int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
|
||||
struct platform_uart_data *uart);
|
||||
|
||||
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
|
||||
const char *compatible);
|
||||
|
||||
struct plic_data;
|
||||
|
||||
int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic);
|
||||
|
||||
int fdt_parse_plic(void *fdt, struct plic_data *plic, const char *compat);
|
||||
|
||||
struct clint_data;
|
||||
|
||||
int fdt_parse_clint_node(void *fdt, int nodeoffset, bool for_timer,
|
||||
struct clint_data *clint);
|
||||
|
||||
int fdt_parse_compat_addr(void *fdt, unsigned long *addr,
|
||||
const char *compatible);
|
||||
|
||||
#endif /* __FDT_HELPER_H__ */
|
32
include/sbi_utils/ipi/fdt_ipi.h
Normal file
32
include/sbi_utils/ipi/fdt_ipi.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __FDT_IPI_H__
|
||||
#define __FDT_IPI_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
struct fdt_ipi {
|
||||
const struct fdt_match *match_table;
|
||||
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||
int (*warm_init)(void);
|
||||
void (*exit)(void);
|
||||
void (*send)(u32 target_hart);
|
||||
void (*clear)(u32 target_hart);
|
||||
};
|
||||
|
||||
void fdt_ipi_send(u32 target_hart);
|
||||
|
||||
void fdt_ipi_clear(u32 target_hart);
|
||||
|
||||
void fdt_ipi_exit(void);
|
||||
|
||||
int fdt_ipi_init(bool cold_boot);
|
||||
|
||||
#endif
|
26
include/sbi_utils/irqchip/fdt_irqchip.h
Normal file
26
include/sbi_utils/irqchip/fdt_irqchip.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __FDT_IRQCHIP_H__
|
||||
#define __FDT_IRQCHIP_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
struct fdt_irqchip {
|
||||
const struct fdt_match *match_table;
|
||||
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||
int (*warm_init)(void);
|
||||
void (*exit)(void);
|
||||
};
|
||||
|
||||
void fdt_irqchip_exit(void);
|
||||
|
||||
int fdt_irqchip_init(bool cold_boot);
|
||||
|
||||
#endif
|
@@ -12,14 +12,18 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
void plic_fdt_fixup(void *fdt, const char *compat);
|
||||
struct plic_data {
|
||||
unsigned long addr;
|
||||
unsigned long num_src;
|
||||
};
|
||||
|
||||
int plic_warm_irqchip_init(u32 target_hart, int m_cntx_id, int s_cntx_id);
|
||||
int plic_warm_irqchip_init(struct plic_data *plic,
|
||||
int m_cntx_id, int s_cntx_id);
|
||||
|
||||
int plic_cold_irqchip_init(unsigned long base, u32 num_sources, u32 hart_count);
|
||||
int plic_cold_irqchip_init(struct plic_data *plic);
|
||||
|
||||
void plic_set_thresh(u32 cntxid, u32 val);
|
||||
void plic_set_thresh(struct plic_data *plic, u32 cntxid, u32 val);
|
||||
|
||||
void plic_set_ie(u32 cntxid, u32 word_index, u32 val);
|
||||
void plic_set_ie(struct plic_data *plic, u32 cntxid, u32 word_index, u32 val);
|
||||
|
||||
#endif
|
||||
|
25
include/sbi_utils/reset/fdt_reset.h
Normal file
25
include/sbi_utils/reset/fdt_reset.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __FDT_RESET_H__
|
||||
#define __FDT_RESET_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
struct fdt_reset {
|
||||
const struct fdt_match *match_table;
|
||||
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||
int (*system_reset)(u32 reset_type);
|
||||
};
|
||||
|
||||
int fdt_system_reset(u32 reset_type);
|
||||
|
||||
int fdt_reset_init(void);
|
||||
|
||||
#endif
|
28
include/sbi_utils/serial/fdt_serial.h
Normal file
28
include/sbi_utils/serial/fdt_serial.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __FDT_SERIAL_H__
|
||||
#define __FDT_SERIAL_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
struct fdt_serial {
|
||||
const struct fdt_match *match_table;
|
||||
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||
void (*putc)(char ch);
|
||||
int (*getc)(void);
|
||||
};
|
||||
|
||||
void fdt_serial_putc(char ch);
|
||||
|
||||
int fdt_serial_getc(void);
|
||||
|
||||
int fdt_serial_init(void);
|
||||
|
||||
#endif
|
18
include/sbi_utils/serial/shakti-uart.h
Normal file
18
include/sbi_utils/serial/shakti-uart.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Vijai Kumar K <vijai@behindbytes.com>
|
||||
*/
|
||||
|
||||
#ifndef __SERIAL_SHAKTI_UART_H__
|
||||
#define __SERIAL_SHAKTI_UART_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
void shakti_uart_putc(char ch);
|
||||
|
||||
int shakti_uart_getc(void);
|
||||
|
||||
int shakti_uart_init(unsigned long base, u32 in_freq, u32 baudrate);
|
||||
|
||||
#endif
|
@@ -12,15 +12,30 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
void clint_ipi_send(u32 target_hart);
|
||||
struct clint_data {
|
||||
/* Public details */
|
||||
unsigned long addr;
|
||||
u32 first_hartid;
|
||||
u32 hart_count;
|
||||
bool has_64bit_mmio;
|
||||
/* Private details (initialized and used by CLINT library)*/
|
||||
u32 *ipi;
|
||||
struct clint_data *time_delta_reference;
|
||||
unsigned long time_delta_computed;
|
||||
u64 time_delta;
|
||||
u64 *time_val;
|
||||
u64 *time_cmp;
|
||||
u64 (*time_rd)(volatile u64 *addr);
|
||||
void (*time_wr)(u64 value, volatile u64 *addr);
|
||||
};
|
||||
|
||||
void clint_ipi_sync(u32 target_hart);
|
||||
void clint_ipi_send(u32 target_hart);
|
||||
|
||||
void clint_ipi_clear(u32 target_hart);
|
||||
|
||||
int clint_warm_ipi_init(void);
|
||||
|
||||
int clint_cold_ipi_init(unsigned long base, u32 hart_count);
|
||||
int clint_cold_ipi_init(struct clint_data *clint);
|
||||
|
||||
u64 clint_timer_value(void);
|
||||
|
||||
@@ -30,6 +45,7 @@ void clint_timer_event_start(u64 next_event);
|
||||
|
||||
int clint_warm_timer_init(void);
|
||||
|
||||
int clint_cold_timer_init(unsigned long base, u32 hart_count);
|
||||
int clint_cold_timer_init(struct clint_data *clint,
|
||||
struct clint_data *reference);
|
||||
|
||||
#endif
|
||||
|
19
include/sbi_utils/sys/htif.h
Normal file
19
include/sbi_utils/sys/htif.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (c) 2010-2020, The Regents of the University of California
|
||||
* (Regents). All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef __SYS_HTIF_H__
|
||||
#define __SYS_HTIF_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
void htif_putc(char ch);
|
||||
|
||||
int htif_getc(void);
|
||||
|
||||
int htif_system_reset(u32 type);
|
||||
|
||||
#endif
|
19
include/sbi_utils/sys/sifive_test.h
Normal file
19
include/sbi_utils/sys/sifive_test.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __SYS_SIFIVE_TEST_H__
|
||||
#define __SYS_SIFIVE_TEST_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
int sifive_test_system_reset(u32 type);
|
||||
|
||||
int sifive_test_init(unsigned long base);
|
||||
|
||||
#endif
|
35
include/sbi_utils/timer/fdt_timer.h
Normal file
35
include/sbi_utils/timer/fdt_timer.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __FDT_TIMER_H__
|
||||
#define __FDT_TIMER_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
struct fdt_timer {
|
||||
const struct fdt_match *match_table;
|
||||
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||
int (*warm_init)(void);
|
||||
void (*exit)(void);
|
||||
u64 (*value)(void);
|
||||
void (*event_stop)(void);
|
||||
void (*event_start)(u64 next_event);
|
||||
};
|
||||
|
||||
u64 fdt_timer_value(void);
|
||||
|
||||
void fdt_timer_event_stop(void);
|
||||
|
||||
void fdt_timer_event_start(u64 next_event);
|
||||
|
||||
void fdt_timer_exit(void);
|
||||
|
||||
int fdt_timer_init(bool cold_boot);
|
||||
|
||||
#endif
|
@@ -11,20 +11,32 @@ libsbi-objs-y += riscv_asm.o
|
||||
libsbi-objs-y += riscv_atomic.o
|
||||
libsbi-objs-y += riscv_hardfp.o
|
||||
libsbi-objs-y += riscv_locks.o
|
||||
libsbi-objs-y += riscv_unpriv.o
|
||||
|
||||
libsbi-objs-y += sbi_bitmap.o
|
||||
libsbi-objs-y += sbi_bitops.o
|
||||
libsbi-objs-y += sbi_console.o
|
||||
libsbi-objs-y += sbi_ecall.o
|
||||
libsbi-objs-y += sbi_ecall_base.o
|
||||
libsbi-objs-y += sbi_ecall_hsm.o
|
||||
libsbi-objs-y += sbi_ecall_legacy.o
|
||||
libsbi-objs-y += sbi_ecall_replace.o
|
||||
libsbi-objs-y += sbi_ecall_vendor.o
|
||||
libsbi-objs-y += sbi_emulate_csr.o
|
||||
libsbi-objs-y += sbi_fifo.o
|
||||
libsbi-objs-y += sbi_hart.o
|
||||
libsbi-objs-y += sbi_math.o
|
||||
libsbi-objs-y += sbi_hfence.o
|
||||
libsbi-objs-y += sbi_hsm.o
|
||||
libsbi-objs-y += sbi_illegal_insn.o
|
||||
libsbi-objs-y += sbi_init.o
|
||||
libsbi-objs-y += sbi_ipi.o
|
||||
libsbi-objs-y += sbi_misaligned_ldst.o
|
||||
libsbi-objs-y += sbi_platform.o
|
||||
libsbi-objs-y += sbi_scratch.o
|
||||
libsbi-objs-y += sbi_string.o
|
||||
libsbi-objs-y += sbi_system.o
|
||||
libsbi-objs-y += sbi_timer.o
|
||||
libsbi-objs-y += sbi_tlb.o
|
||||
libsbi-objs-y += sbi_trap.o
|
||||
libsbi-objs-y += sbi_string.o
|
||||
libsbi-objs-y += sbi_unpriv.o
|
||||
libsbi-objs-y += sbi_expected_trap.o
|
||||
|
@@ -10,6 +10,83 @@
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
|
||||
/* determine CPU extension, return non-zero support */
|
||||
int misa_extension_imp(char ext)
|
||||
{
|
||||
unsigned long misa = csr_read(CSR_MISA);
|
||||
|
||||
if (misa) {
|
||||
if ('A' <= ext && ext <= 'Z')
|
||||
return misa & (1 << (ext - 'A'));
|
||||
if ('a' <= ext && ext <= 'z')
|
||||
return misa & (1 << (ext - 'a'));
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void misa_string(int xlen, char *out, unsigned int out_sz)
|
||||
{
|
||||
unsigned int i, pos = 0;
|
||||
const char valid_isa_order[] = "iemafdqclbjtpvnsuhkorwxyzg";
|
||||
|
||||
if (!out)
|
||||
return;
|
||||
|
||||
if (5 <= (out_sz - pos)) {
|
||||
out[pos++] = 'r';
|
||||
out[pos++] = 'v';
|
||||
switch (xlen) {
|
||||
case 1:
|
||||
out[pos++] = '3';
|
||||
out[pos++] = '2';
|
||||
break;
|
||||
case 2:
|
||||
out[pos++] = '6';
|
||||
out[pos++] = '4';
|
||||
break;
|
||||
case 3:
|
||||
out[pos++] = '1';
|
||||
out[pos++] = '2';
|
||||
out[pos++] = '8';
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < array_size(valid_isa_order) && (pos < out_sz); i++) {
|
||||
if (misa_extension_imp(valid_isa_order[i]))
|
||||
out[pos++] = valid_isa_order[i];
|
||||
}
|
||||
|
||||
if (pos < out_sz)
|
||||
out[pos++] = '\0';
|
||||
}
|
||||
|
||||
unsigned long csr_read_num(int csr_num)
|
||||
{
|
||||
@@ -174,7 +251,7 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
|
||||
if (n >= PMP_COUNT || log2len > __riscv_xlen || log2len < PMP_SHIFT)
|
||||
return SBI_EINVAL;
|
||||
|
||||
/* calculate PMP register and offset */
|
||||
/* calculate PMP register and offset */
|
||||
#if __riscv_xlen == 32
|
||||
pmpcfg_csr = CSR_PMPCFG0 + (n >> 2);
|
||||
pmpcfg_shift = (n & 3) << 3;
|
||||
@@ -191,7 +268,7 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
|
||||
|
||||
/* encode PMP config */
|
||||
prot |= (log2len == PMP_SHIFT) ? PMP_A_NA4 : PMP_A_NAPOT;
|
||||
cfgmask = ~(0xff << pmpcfg_shift);
|
||||
cfgmask = ~(0xffUL << pmpcfg_shift);
|
||||
pmpcfg = (csr_read_num(pmpcfg_csr) & cfgmask);
|
||||
pmpcfg |= ((prot << pmpcfg_shift) & ~cfgmask);
|
||||
|
||||
@@ -216,16 +293,16 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
|
||||
}
|
||||
|
||||
int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
|
||||
unsigned long *log2len_out)
|
||||
unsigned long *size)
|
||||
{
|
||||
int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr;
|
||||
unsigned long cfgmask, pmpcfg, prot;
|
||||
unsigned long t1, addr, log2len;
|
||||
|
||||
/* check parameters */
|
||||
if (n >= PMP_COUNT || !prot_out || !addr_out || !log2len_out)
|
||||
if (n >= PMP_COUNT || !prot_out || !addr_out || !size)
|
||||
return SBI_EINVAL;
|
||||
*prot_out = *addr_out = *log2len_out = 0;
|
||||
*prot_out = *addr_out = *size = 0;
|
||||
|
||||
/* calculate PMP register and offset */
|
||||
#if __riscv_xlen == 32
|
||||
@@ -243,7 +320,7 @@ int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
|
||||
return SBI_ENOTSUPP;
|
||||
|
||||
/* decode PMP config */
|
||||
cfgmask = (0xff << pmpcfg_shift);
|
||||
cfgmask = (0xffUL << pmpcfg_shift);
|
||||
pmpcfg = csr_read_num(pmpcfg_csr) & cfgmask;
|
||||
prot = pmpcfg >> pmpcfg_shift;
|
||||
|
||||
@@ -266,7 +343,9 @@ int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
|
||||
/* return details */
|
||||
*prot_out = prot;
|
||||
*addr_out = addr;
|
||||
*log2len_out = log2len;
|
||||
|
||||
if (log2len < __riscv_xlen)
|
||||
*size = (1UL << log2len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -7,11 +7,10 @@
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
#include <sbi/sbi_bitops.h>
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/riscv_atomic.h>
|
||||
#include <sbi/riscv_barrier.h>
|
||||
#include <sbi/sbi_bits.h>
|
||||
|
||||
long atomic_read(atomic_t *atom)
|
||||
{
|
||||
@@ -50,6 +49,39 @@ long atomic_sub_return(atomic_t *atom, long value)
|
||||
return ret - value;
|
||||
}
|
||||
|
||||
#define __axchg(ptr, new, size) \
|
||||
({ \
|
||||
__typeof__(ptr) __ptr = (ptr); \
|
||||
__typeof__(new) __new = (new); \
|
||||
__typeof__(*(ptr)) __ret; \
|
||||
switch (size) { \
|
||||
case 4: \
|
||||
__asm__ __volatile__ ( \
|
||||
" amoswap.w.aqrl %0, %2, %1\n" \
|
||||
: "=r" (__ret), "+A" (*__ptr) \
|
||||
: "r" (__new) \
|
||||
: "memory"); \
|
||||
break; \
|
||||
case 8: \
|
||||
__asm__ __volatile__ ( \
|
||||
" amoswap.d.aqrl %0, %2, %1\n" \
|
||||
: "=r" (__ret), "+A" (*__ptr) \
|
||||
: "r" (__new) \
|
||||
: "memory"); \
|
||||
break; \
|
||||
default: \
|
||||
break; \
|
||||
} \
|
||||
__ret; \
|
||||
})
|
||||
|
||||
#define axchg(ptr, x) \
|
||||
({ \
|
||||
__typeof__(*(ptr)) _x_ = (x); \
|
||||
(__typeof__(*(ptr))) __axchg((ptr), _x_, sizeof(*(ptr))); \
|
||||
})
|
||||
|
||||
|
||||
#define __xchg(ptr, new, size) \
|
||||
({ \
|
||||
__typeof__(ptr) __ptr = (ptr); \
|
||||
@@ -58,20 +90,20 @@ long atomic_sub_return(atomic_t *atom, long value)
|
||||
register unsigned int __rc; \
|
||||
switch (size) { \
|
||||
case 4: \
|
||||
__asm__ __volatile__("0: lr.w %0, %2\n" \
|
||||
" sc.w.rl %1, %z3, %2\n" \
|
||||
" bnez %1, 0b\n" \
|
||||
" fence rw, rw\n" \
|
||||
__asm__ __volatile__("0: lr.w %0, %2\n" \
|
||||
" sc.w.rl %1, %z3, %2\n" \
|
||||
" bnez %1, 0b\n" \
|
||||
" fence rw, rw\n" \
|
||||
: "=&r"(__ret), "=&r"(__rc), \
|
||||
"+A"(*__ptr) \
|
||||
: "rJ"(__new) \
|
||||
: "memory"); \
|
||||
break; \
|
||||
case 8: \
|
||||
__asm__ __volatile__("0: lr.d %0, %2\n" \
|
||||
" sc.d.rl %1, %z3, %2\n" \
|
||||
" bnez %1, 0b\n" \
|
||||
" fence rw, rw\n" \
|
||||
__asm__ __volatile__("0: lr.d %0, %2\n" \
|
||||
" sc.d.rl %1, %z3, %2\n" \
|
||||
" bnez %1, 0b\n" \
|
||||
" fence rw, rw\n" \
|
||||
: "=&r"(__ret), "=&r"(__rc), \
|
||||
"+A"(*__ptr) \
|
||||
: "rJ"(__new) \
|
||||
@@ -98,11 +130,11 @@ long atomic_sub_return(atomic_t *atom, long value)
|
||||
register unsigned int __rc; \
|
||||
switch (size) { \
|
||||
case 4: \
|
||||
__asm__ __volatile__("0: lr.w %0, %2\n" \
|
||||
" bne %0, %z3, 1f\n" \
|
||||
" sc.w.rl %1, %z4, %2\n" \
|
||||
" bnez %1, 0b\n" \
|
||||
" fence rw, rw\n" \
|
||||
__asm__ __volatile__("0: lr.w %0, %2\n" \
|
||||
" bne %0, %z3, 1f\n" \
|
||||
" sc.w.rl %1, %z4, %2\n" \
|
||||
" bnez %1, 0b\n" \
|
||||
" fence rw, rw\n" \
|
||||
"1:\n" \
|
||||
: "=&r"(__ret), "=&r"(__rc), \
|
||||
"+A"(*__ptr) \
|
||||
@@ -110,11 +142,11 @@ long atomic_sub_return(atomic_t *atom, long value)
|
||||
: "memory"); \
|
||||
break; \
|
||||
case 8: \
|
||||
__asm__ __volatile__("0: lr.d %0, %2\n" \
|
||||
" bne %0, %z3, 1f\n" \
|
||||
" sc.d.rl %1, %z4, %2\n" \
|
||||
" bnez %1, 0b\n" \
|
||||
" fence rw, rw\n" \
|
||||
__asm__ __volatile__("0: lr.d %0, %2\n" \
|
||||
" bne %0, %z3, 1f\n" \
|
||||
" sc.d.rl %1, %z4, %2\n" \
|
||||
" bnez %1, 0b\n" \
|
||||
" fence rw, rw\n" \
|
||||
"1:\n" \
|
||||
: "=&r"(__ret), "=&r"(__rc), \
|
||||
"+A"(*__ptr) \
|
||||
@@ -135,7 +167,7 @@ long atomic_sub_return(atomic_t *atom, long value)
|
||||
__cmpxchg((ptr), _o_, _n_, sizeof(*(ptr))); \
|
||||
})
|
||||
|
||||
long arch_atomic_cmpxchg(atomic_t *atom, long oldval, long newval)
|
||||
long atomic_cmpxchg(atomic_t *atom, long oldval, long newval)
|
||||
{
|
||||
#ifdef __riscv_atomic
|
||||
return __sync_val_compare_and_swap(&atom->counter, oldval, newval);
|
||||
@@ -144,16 +176,11 @@ long arch_atomic_cmpxchg(atomic_t *atom, long oldval, long newval)
|
||||
#endif
|
||||
}
|
||||
|
||||
long arch_atomic_xchg(atomic_t *atom, long newval)
|
||||
long atomic_xchg(atomic_t *atom, long newval)
|
||||
{
|
||||
/* Atomically set new value and return old value. */
|
||||
#ifdef __riscv_atomic
|
||||
/*
|
||||
* The name of GCC built-in macro __sync_lock_test_and_set()
|
||||
* is misleading. A more appropriate name for GCC built-in
|
||||
* macro would be __sync_val_exchange().
|
||||
*/
|
||||
return __sync_lock_test_and_set(&atom->counter, newval);
|
||||
return axchg(&atom->counter, newval);
|
||||
#else
|
||||
return xchg(&atom->counter, newval);
|
||||
#endif
|
||||
@@ -164,23 +191,29 @@ unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
|
||||
{
|
||||
/* Atomically set new value and return old value. */
|
||||
#ifdef __riscv_atomic
|
||||
/*
|
||||
* The name of GCC built-in macro __sync_lock_test_and_set()
|
||||
* is misleading. A more appropriate name for GCC built-in
|
||||
* macro would be __sync_val_exchange().
|
||||
*/
|
||||
return __sync_lock_test_and_set(ptr, newval);
|
||||
return axchg(ptr, newval);
|
||||
#else
|
||||
return xchg(ptr, newval);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if (BITS_PER_LONG == 64)
|
||||
unsigned long atomic_raw_xchg_ulong(volatile unsigned long *ptr,
|
||||
unsigned long newval)
|
||||
{
|
||||
/* Atomically set new value and return old value. */
|
||||
#ifdef __riscv_atomic
|
||||
return axchg(ptr, newval);
|
||||
#else
|
||||
return xchg(ptr, newval);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if (__SIZEOF_POINTER__ == 8)
|
||||
#define __AMO(op) "amo" #op ".d"
|
||||
#elif (BITS_PER_LONG == 32)
|
||||
#elif (__SIZEOF_POINTER__ == 4)
|
||||
#define __AMO(op) "amo" #op ".w"
|
||||
#else
|
||||
#error "Unexpected BITS_PER_LONG"
|
||||
#error "Unexpected __SIZEOF_POINTER__"
|
||||
#endif
|
||||
|
||||
#define __atomic_op_bit_ord(op, mod, nr, addr, ord) \
|
||||
|
@@ -1,145 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include <sbi/riscv_unpriv.h>
|
||||
#include <sbi/sbi_bits.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
|
||||
#define DEFINE_UNPRIVILEGED_LOAD_FUNCTION(type, insn, insnlen) \
|
||||
type load_##type(const type *addr, \
|
||||
struct sbi_scratch *scratch, \
|
||||
struct unpriv_trap *trap) \
|
||||
{ \
|
||||
register ulong __mstatus asm("a2"); \
|
||||
type val = 0; \
|
||||
trap->ilen = insnlen; \
|
||||
trap->cause = 0; \
|
||||
trap->tval = 0; \
|
||||
sbi_hart_set_trap_info(scratch, trap); \
|
||||
asm volatile( \
|
||||
"csrrs %0, " STR(CSR_MSTATUS) ", %3\n" \
|
||||
#insn " %1, %2\n" \
|
||||
"csrw " STR(CSR_MSTATUS) ", %0" \
|
||||
: "+&r"(__mstatus), "=&r"(val) \
|
||||
: "m"(*addr), "r"(MSTATUS_MPRV)); \
|
||||
sbi_hart_set_trap_info(scratch, NULL); \
|
||||
return val; \
|
||||
}
|
||||
|
||||
#define DEFINE_UNPRIVILEGED_STORE_FUNCTION(type, insn, insnlen) \
|
||||
void store_##type(type *addr, type val, \
|
||||
struct sbi_scratch *scratch, \
|
||||
struct unpriv_trap *trap) \
|
||||
{ \
|
||||
register ulong __mstatus asm("a3"); \
|
||||
trap->ilen = insnlen; \
|
||||
trap->cause = 0; \
|
||||
trap->tval = 0; \
|
||||
sbi_hart_set_trap_info(scratch, trap); \
|
||||
asm volatile( \
|
||||
"csrrs %0, " STR(CSR_MSTATUS) ", %3\n" \
|
||||
#insn " %1, %2\n" \
|
||||
"csrw " STR(CSR_MSTATUS) ", %0" \
|
||||
: "+&r"(__mstatus) \
|
||||
: "r"(val), "m"(*addr), "r"(MSTATUS_MPRV)); \
|
||||
sbi_hart_set_trap_info(scratch, NULL); \
|
||||
}
|
||||
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu, 4)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u16, lhu, 4)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s8, lb, 4)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s16, lh, 4)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s32, lw, 2)
|
||||
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u8, sb, 4)
|
||||
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u16, sh, 4)
|
||||
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u32, sw, 2)
|
||||
#if __riscv_xlen == 64
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu, 4)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld, 2)
|
||||
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u64, sd, 2)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld, 2)
|
||||
#else
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw, 2)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw, 2)
|
||||
|
||||
u64 load_u64(const u64 *addr,
|
||||
struct sbi_scratch *scratch, struct unpriv_trap *trap)
|
||||
{
|
||||
u64 ret = load_u32((u32 *)addr, scratch, trap);
|
||||
|
||||
if (trap->cause)
|
||||
return 0;
|
||||
ret |= ((u64)load_u32((u32 *)addr + 1, scratch, trap) << 32);
|
||||
if (trap->cause)
|
||||
return 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void store_u64(u64 *addr, u64 val,
|
||||
struct sbi_scratch *scratch, struct unpriv_trap *trap)
|
||||
{
|
||||
store_u32((u32 *)addr, val, scratch, trap);
|
||||
if (trap->cause)
|
||||
return;
|
||||
|
||||
store_u32((u32 *)addr + 1, val >> 32, scratch, trap);
|
||||
if (trap->cause)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
ulong get_insn(ulong mepc, ulong *mstatus)
|
||||
{
|
||||
register ulong __mepc asm("a2") = mepc;
|
||||
register ulong __mstatus asm("a3");
|
||||
ulong val;
|
||||
#ifndef __riscv_compressed
|
||||
asm("csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n"
|
||||
#if __riscv_xlen == 64
|
||||
STR(LWU) " %[insn], (%[addr])\n"
|
||||
#else
|
||||
STR(LW) " %[insn], (%[addr])\n"
|
||||
#endif
|
||||
"csrw " STR(CSR_MSTATUS) ", %[mstatus]"
|
||||
: [mstatus] "+&r"(__mstatus), [insn] "=&r"(val)
|
||||
: [mprv] "r"(MSTATUS_MPRV | MSTATUS_MXR), [addr] "r"(__mepc));
|
||||
#else
|
||||
ulong rvc_mask = 3, tmp;
|
||||
asm("csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n"
|
||||
"and %[tmp], %[addr], 2\n"
|
||||
"bnez %[tmp], 1f\n"
|
||||
#if __riscv_xlen == 64
|
||||
STR(LWU) " %[insn], (%[addr])\n"
|
||||
#else
|
||||
STR(LW) " %[insn], (%[addr])\n"
|
||||
#endif
|
||||
"and %[tmp], %[insn], %[rvc_mask]\n"
|
||||
"beq %[tmp], %[rvc_mask], 2f\n"
|
||||
"sll %[insn], %[insn], %[xlen_minus_16]\n"
|
||||
"srl %[insn], %[insn], %[xlen_minus_16]\n"
|
||||
"j 2f\n"
|
||||
"1:\n"
|
||||
"lhu %[insn], (%[addr])\n"
|
||||
"and %[tmp], %[insn], %[rvc_mask]\n"
|
||||
"bne %[tmp], %[rvc_mask], 2f\n"
|
||||
"lhu %[tmp], 2(%[addr])\n"
|
||||
"sll %[tmp], %[tmp], 16\n"
|
||||
"add %[insn], %[insn], %[tmp]\n"
|
||||
"2: csrw " STR(CSR_MSTATUS) ", %[mstatus]"
|
||||
: [mstatus] "+&r"(__mstatus), [insn] "=&r"(val), [tmp] "=&r"(tmp)
|
||||
: [mprv] "r"(MSTATUS_MPRV | MSTATUS_MXR), [addr] "r"(__mepc),
|
||||
[rvc_mask] "r"(rvc_mask), [xlen_minus_16] "i"(__riscv_xlen - 16));
|
||||
#endif
|
||||
if (mstatus)
|
||||
*mstatus = __mstatus;
|
||||
return val;
|
||||
}
|
40
lib/sbi/sbi_bitmap.c
Normal file
40
lib/sbi/sbi_bitmap.c
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/sbi_bitmap.h>
|
||||
|
||||
void __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, int bits)
|
||||
{
|
||||
int k;
|
||||
int nr = BITS_TO_LONGS(bits);
|
||||
|
||||
for (k = 0; k < nr; k++)
|
||||
dst[k] = bitmap1[k] & bitmap2[k];
|
||||
}
|
||||
|
||||
void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, int bits)
|
||||
{
|
||||
int k;
|
||||
int nr = BITS_TO_LONGS(bits);
|
||||
|
||||
for (k = 0; k < nr; k++)
|
||||
dst[k] = bitmap1[k] | bitmap2[k];
|
||||
}
|
||||
|
||||
void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, int bits)
|
||||
{
|
||||
int k;
|
||||
int nr = BITS_TO_LONGS(bits);
|
||||
|
||||
for (k = 0; k < nr; k++)
|
||||
dst[k] = bitmap1[k] ^ bitmap2[k];
|
||||
}
|
200
lib/sbi/sbi_bitops.c
Normal file
200
lib/sbi/sbi_bitops.c
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Atish Patra <atish.patra@wdc.com>
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/sbi_bitops.h>
|
||||
|
||||
#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG)
|
||||
|
||||
/**
|
||||
* find_first_bit - find the first set bit in a memory region
|
||||
* @addr: The address to start the search at
|
||||
* @size: The maximum size to search
|
||||
*
|
||||
* Returns the bit number of the first set bit.
|
||||
*/
|
||||
unsigned long find_first_bit(const unsigned long *addr,
|
||||
unsigned long size)
|
||||
{
|
||||
const unsigned long *p = addr;
|
||||
unsigned long result = 0;
|
||||
unsigned long tmp;
|
||||
|
||||
while (size & ~(BITS_PER_LONG-1)) {
|
||||
if ((tmp = *(p++)))
|
||||
goto found;
|
||||
result += BITS_PER_LONG;
|
||||
size -= BITS_PER_LONG;
|
||||
}
|
||||
if (!size)
|
||||
return result;
|
||||
|
||||
tmp = (*p) & (~0UL >> (BITS_PER_LONG - size));
|
||||
if (tmp == 0UL) /* Are any bits set? */
|
||||
return result + size; /* Nope. */
|
||||
found:
|
||||
return result + __ffs(tmp);
|
||||
}
|
||||
|
||||
/**
|
||||
* find_first_zero_bit - find the first cleared bit in a memory region
|
||||
* @addr: The address to start the search at
|
||||
* @size: The maximum size to search
|
||||
*
|
||||
* Returns the bit number of the first cleared bit.
|
||||
*/
|
||||
unsigned long find_first_zero_bit(const unsigned long *addr,
|
||||
unsigned long size)
|
||||
{
|
||||
const unsigned long *p = addr;
|
||||
unsigned long result = 0;
|
||||
unsigned long tmp;
|
||||
|
||||
while (size & ~(BITS_PER_LONG-1)) {
|
||||
if (~(tmp = *(p++)))
|
||||
goto found;
|
||||
result += BITS_PER_LONG;
|
||||
size -= BITS_PER_LONG;
|
||||
}
|
||||
if (!size)
|
||||
return result;
|
||||
|
||||
tmp = (*p) | (~0UL << size);
|
||||
if (tmp == ~0UL) /* Are any bits zero? */
|
||||
return result + size; /* Nope. */
|
||||
found:
|
||||
return result + ffz(tmp);
|
||||
}
|
||||
|
||||
/**
|
||||
* find_last_bit - find the last set bit in a memory region
|
||||
* @addr: The address to start the search at
|
||||
* @size: The maximum size to search
|
||||
*
|
||||
* Returns the bit number of the first set bit, or size.
|
||||
*/
|
||||
unsigned long find_last_bit(const unsigned long *addr,
|
||||
unsigned long size)
|
||||
{
|
||||
unsigned long words;
|
||||
unsigned long tmp;
|
||||
|
||||
/* Start at final word. */
|
||||
words = size / BITS_PER_LONG;
|
||||
|
||||
/* Partial final word? */
|
||||
if (size & (BITS_PER_LONG-1)) {
|
||||
tmp = (addr[words] & (~0UL >> (BITS_PER_LONG
|
||||
- (size & (BITS_PER_LONG-1)))));
|
||||
if (tmp)
|
||||
goto found;
|
||||
}
|
||||
|
||||
while (words) {
|
||||
tmp = addr[--words];
|
||||
if (tmp) {
|
||||
found:
|
||||
return words * BITS_PER_LONG + __fls(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* find_next_bit - find the next set bit in a memory region
|
||||
* @addr: The address to base the search on
|
||||
* @offset: The bitnumber to start searching at
|
||||
* @size: The bitmap size in bits
|
||||
*/
|
||||
unsigned long find_next_bit(const unsigned long *addr,
|
||||
unsigned long size, unsigned long offset)
|
||||
{
|
||||
const unsigned long *p = addr + BITOP_WORD(offset);
|
||||
unsigned long result = offset & ~(BITS_PER_LONG-1);
|
||||
unsigned long tmp;
|
||||
|
||||
if (offset >= size)
|
||||
return size;
|
||||
size -= result;
|
||||
offset %= BITS_PER_LONG;
|
||||
if (offset) {
|
||||
tmp = *(p++);
|
||||
tmp &= (~0UL << offset);
|
||||
if (size < BITS_PER_LONG)
|
||||
goto found_first;
|
||||
if (tmp)
|
||||
goto found_middle;
|
||||
size -= BITS_PER_LONG;
|
||||
result += BITS_PER_LONG;
|
||||
}
|
||||
while (size & ~(BITS_PER_LONG-1)) {
|
||||
if ((tmp = *(p++)))
|
||||
goto found_middle;
|
||||
result += BITS_PER_LONG;
|
||||
size -= BITS_PER_LONG;
|
||||
}
|
||||
if (!size)
|
||||
return result;
|
||||
tmp = *p;
|
||||
|
||||
found_first:
|
||||
tmp &= (~0UL >> (BITS_PER_LONG - size));
|
||||
if (tmp == 0UL) /* Are any bits set? */
|
||||
return result + size; /* Nope. */
|
||||
found_middle:
|
||||
return result + __ffs(tmp);
|
||||
}
|
||||
|
||||
/**
|
||||
* find_next_zero_bit - find the next cleared bit in a memory region
|
||||
* @addr: The address to base the search on
|
||||
* @offset: The bitnumber to start searching at
|
||||
* @size: The bitmap size in bits
|
||||
*/
|
||||
unsigned long find_next_zero_bit(const unsigned long *addr,
|
||||
unsigned long size,
|
||||
unsigned long offset)
|
||||
{
|
||||
const unsigned long *p = addr + BITOP_WORD(offset);
|
||||
unsigned long result = offset & ~(BITS_PER_LONG-1);
|
||||
unsigned long tmp;
|
||||
|
||||
if (offset >= size)
|
||||
return size;
|
||||
size -= result;
|
||||
offset %= BITS_PER_LONG;
|
||||
if (offset) {
|
||||
tmp = *(p++);
|
||||
tmp |= ~0UL >> (BITS_PER_LONG - offset);
|
||||
if (size < BITS_PER_LONG)
|
||||
goto found_first;
|
||||
if (~tmp)
|
||||
goto found_middle;
|
||||
size -= BITS_PER_LONG;
|
||||
result += BITS_PER_LONG;
|
||||
}
|
||||
while (size & ~(BITS_PER_LONG-1)) {
|
||||
if (~(tmp = *(p++)))
|
||||
goto found_middle;
|
||||
result += BITS_PER_LONG;
|
||||
size -= BITS_PER_LONG;
|
||||
}
|
||||
if (!size)
|
||||
return result;
|
||||
tmp = *p;
|
||||
|
||||
found_first:
|
||||
tmp |= ~0UL << size;
|
||||
if (tmp == ~0UL) /* Are any bits zero? */
|
||||
return result + size; /* Nope. */
|
||||
found_middle:
|
||||
return result + ffz(tmp);
|
||||
}
|
@@ -7,9 +7,10 @@
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/riscv_locks.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
|
||||
static const struct sbi_platform *console_plat = NULL;
|
||||
static spinlock_t console_out_lock = SPIN_LOCK_INITIALIZER;
|
||||
@@ -375,6 +376,20 @@ int sbi_printf(const char *format, ...)
|
||||
return retval;
|
||||
}
|
||||
|
||||
int sbi_dprintf(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int retval = 0;
|
||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||
|
||||
va_start(args, format);
|
||||
if (scratch->options & SBI_SCRATCH_DEBUG_PRINTS)
|
||||
retval = print(NULL, NULL, format, args);
|
||||
va_end(args);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int sbi_console_init(struct sbi_scratch *scratch)
|
||||
{
|
||||
console_plat = sbi_platform_ptr(scratch);
|
||||
|
@@ -11,15 +11,8 @@
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_ipi.h>
|
||||
#include <sbi/sbi_system.h>
|
||||
#include <sbi/sbi_timer.h>
|
||||
#include <sbi/sbi_tlb.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
|
||||
#define SBI_ECALL_VERSION_MAJOR 0
|
||||
#define SBI_ECALL_VERSION_MINOR 1
|
||||
|
||||
u16 sbi_ecall_version_major(void)
|
||||
{
|
||||
return SBI_ECALL_VERSION_MAJOR;
|
||||
@@ -30,78 +23,158 @@ u16 sbi_ecall_version_minor(void)
|
||||
return SBI_ECALL_VERSION_MINOR;
|
||||
}
|
||||
|
||||
int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch)
|
||||
static unsigned long ecall_impid = SBI_OPENSBI_IMPID;
|
||||
|
||||
unsigned long sbi_ecall_get_impid(void)
|
||||
{
|
||||
int ret = SBI_ENOTSUPP;
|
||||
struct unpriv_trap uptrap;
|
||||
struct sbi_tlb_info tlb_info;
|
||||
return ecall_impid;
|
||||
}
|
||||
|
||||
switch (regs->a7) {
|
||||
case SBI_ECALL_SET_TIMER:
|
||||
#if __riscv_xlen == 32
|
||||
sbi_timer_event_start(scratch,
|
||||
(((u64)regs->a1 << 32) | (u64)regs->a0));
|
||||
#else
|
||||
sbi_timer_event_start(scratch, (u64)regs->a0);
|
||||
#endif
|
||||
ret = 0;
|
||||
break;
|
||||
case SBI_ECALL_CONSOLE_PUTCHAR:
|
||||
sbi_putc(regs->a0);
|
||||
ret = 0;
|
||||
break;
|
||||
case SBI_ECALL_CONSOLE_GETCHAR:
|
||||
regs->a0 = sbi_getc();
|
||||
ret = 0;
|
||||
break;
|
||||
case SBI_ECALL_CLEAR_IPI:
|
||||
sbi_ipi_clear_smode(scratch);
|
||||
ret = 0;
|
||||
break;
|
||||
case SBI_ECALL_SEND_IPI:
|
||||
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)regs->a0,
|
||||
SBI_IPI_EVENT_SOFT, NULL);
|
||||
break;
|
||||
case SBI_ECALL_REMOTE_FENCE_I:
|
||||
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)regs->a0,
|
||||
SBI_IPI_EVENT_FENCE_I, NULL);
|
||||
break;
|
||||
case SBI_ECALL_REMOTE_SFENCE_VMA:
|
||||
tlb_info.start = (unsigned long)regs->a1;
|
||||
tlb_info.size = (unsigned long)regs->a2;
|
||||
tlb_info.type = SBI_TLB_FLUSH_VMA;
|
||||
void sbi_ecall_set_impid(unsigned long impid)
|
||||
{
|
||||
ecall_impid = impid;
|
||||
}
|
||||
|
||||
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)regs->a0,
|
||||
SBI_IPI_EVENT_SFENCE_VMA, &tlb_info);
|
||||
break;
|
||||
case SBI_ECALL_REMOTE_SFENCE_VMA_ASID:
|
||||
tlb_info.start = (unsigned long)regs->a1;
|
||||
tlb_info.size = (unsigned long)regs->a2;
|
||||
tlb_info.asid = (unsigned long)regs->a3;
|
||||
tlb_info.type = SBI_TLB_FLUSH_VMA_ASID;
|
||||
static SBI_LIST_HEAD(ecall_exts_list);
|
||||
|
||||
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)regs->a0,
|
||||
SBI_IPI_EVENT_SFENCE_VMA_ASID,
|
||||
&tlb_info);
|
||||
break;
|
||||
case SBI_ECALL_SHUTDOWN:
|
||||
sbi_system_shutdown(scratch, 0);
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
regs->a0 = SBI_ENOTSUPP;
|
||||
ret = 0;
|
||||
break;
|
||||
};
|
||||
struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
|
||||
{
|
||||
struct sbi_ecall_extension *t, *ret = NULL;
|
||||
|
||||
if (!ret) {
|
||||
regs->mepc += 4;
|
||||
} else if (ret == SBI_ETRAP) {
|
||||
ret = 0;
|
||||
sbi_trap_redirect(regs, scratch, regs->mepc,
|
||||
uptrap.cause, uptrap.tval);
|
||||
sbi_list_for_each_entry(t, &ecall_exts_list, head) {
|
||||
if (t->extid_start <= extid && extid <= t->extid_end) {
|
||||
ret = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)
|
||||
{
|
||||
struct sbi_ecall_extension *t;
|
||||
|
||||
if (!ext || (ext->extid_end < ext->extid_start) || !ext->handle)
|
||||
return SBI_EINVAL;
|
||||
|
||||
sbi_list_for_each_entry(t, &ecall_exts_list, head) {
|
||||
unsigned long start = t->extid_start;
|
||||
unsigned long end = t->extid_end;
|
||||
if (end < ext->extid_start || ext->extid_end < start)
|
||||
/* no overlap */;
|
||||
else
|
||||
return SBI_EINVAL;
|
||||
}
|
||||
|
||||
SBI_INIT_LIST_HEAD(&ext->head);
|
||||
sbi_list_add_tail(&ext->head, &ecall_exts_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sbi_ecall_unregister_extension(struct sbi_ecall_extension *ext)
|
||||
{
|
||||
bool found = FALSE;
|
||||
struct sbi_ecall_extension *t;
|
||||
|
||||
if (!ext)
|
||||
return;
|
||||
|
||||
sbi_list_for_each_entry(t, &ecall_exts_list, head) {
|
||||
if (t == ext) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
sbi_list_del_init(&ext->head);
|
||||
}
|
||||
|
||||
int sbi_ecall_handler(struct sbi_trap_regs *regs)
|
||||
{
|
||||
int ret = 0;
|
||||
struct sbi_ecall_extension *ext;
|
||||
unsigned long extension_id = regs->a7;
|
||||
unsigned long func_id = regs->a6;
|
||||
struct sbi_trap_info trap = {0};
|
||||
unsigned long out_val = 0;
|
||||
bool is_0_1_spec = 0;
|
||||
unsigned long args[6];
|
||||
|
||||
args[0] = regs->a0;
|
||||
args[1] = regs->a1;
|
||||
args[2] = regs->a2;
|
||||
args[3] = regs->a3;
|
||||
args[4] = regs->a4;
|
||||
args[5] = regs->a5;
|
||||
|
||||
ext = sbi_ecall_find_extension(extension_id);
|
||||
if (ext && ext->handle) {
|
||||
ret = ext->handle(extension_id, func_id,
|
||||
args, &out_val, &trap);
|
||||
if (extension_id >= SBI_EXT_0_1_SET_TIMER &&
|
||||
extension_id <= SBI_EXT_0_1_SHUTDOWN)
|
||||
is_0_1_spec = 1;
|
||||
} else {
|
||||
ret = SBI_ENOTSUPP;
|
||||
}
|
||||
|
||||
if (ret == SBI_ETRAP) {
|
||||
trap.epc = regs->mepc;
|
||||
sbi_trap_redirect(regs, &trap);
|
||||
} else {
|
||||
if (ret < SBI_LAST_ERR) {
|
||||
sbi_printf("%s: Invalid error %d for ext=0x%lx "
|
||||
"func=0x%lx\n", __func__, ret,
|
||||
extension_id, func_id);
|
||||
ret = SBI_ERR_FAILED;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function should return non-zero value only in case of
|
||||
* fatal error. However, there is no good way to distinguish
|
||||
* between a fatal and non-fatal errors yet. That's why we treat
|
||||
* every return value except ETRAP as non-fatal and just return
|
||||
* accordingly for now. Once fatal errors are defined, that
|
||||
* case should be handled differently.
|
||||
*/
|
||||
regs->mepc += 4;
|
||||
regs->a0 = ret;
|
||||
if (!is_0_1_spec)
|
||||
regs->a1 = out_val;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sbi_ecall_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* The order of below registrations is performance optimized */
|
||||
ret = sbi_ecall_register_extension(&ecall_time);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = sbi_ecall_register_extension(&ecall_rfence);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = sbi_ecall_register_extension(&ecall_ipi);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = sbi_ecall_register_extension(&ecall_base);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = sbi_ecall_register_extension(&ecall_hsm);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = sbi_ecall_register_extension(&ecall_legacy);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = sbi_ecall_register_extension(&ecall_vendor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
77
lib/sbi/sbi_ecall_base.c
Normal file
77
lib/sbi/sbi_ecall_base.c
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
* Atish Patra <atish.patra@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_version.h>
|
||||
#include <sbi/riscv_asm.h>
|
||||
|
||||
static int sbi_ecall_base_probe(unsigned long extid, unsigned long *out_val)
|
||||
{
|
||||
struct sbi_ecall_extension *ext;
|
||||
|
||||
ext = sbi_ecall_find_extension(extid);
|
||||
if (!ext) {
|
||||
*out_val = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ext->probe)
|
||||
return ext->probe(extid, out_val);
|
||||
|
||||
*out_val = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sbi_ecall_base_handler(unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (funcid) {
|
||||
case SBI_EXT_BASE_GET_SPEC_VERSION:
|
||||
*out_val = (SBI_ECALL_VERSION_MAJOR <<
|
||||
SBI_SPEC_VERSION_MAJOR_OFFSET) &
|
||||
(SBI_SPEC_VERSION_MAJOR_MASK <<
|
||||
SBI_SPEC_VERSION_MAJOR_OFFSET);
|
||||
*out_val = *out_val | SBI_ECALL_VERSION_MINOR;
|
||||
break;
|
||||
case SBI_EXT_BASE_GET_IMP_ID:
|
||||
*out_val = sbi_ecall_get_impid();
|
||||
break;
|
||||
case SBI_EXT_BASE_GET_IMP_VERSION:
|
||||
*out_val = OPENSBI_VERSION;
|
||||
break;
|
||||
case SBI_EXT_BASE_GET_MVENDORID:
|
||||
*out_val = csr_read(CSR_MVENDORID);
|
||||
break;
|
||||
case SBI_EXT_BASE_GET_MARCHID:
|
||||
*out_val = csr_read(CSR_MARCHID);
|
||||
break;
|
||||
case SBI_EXT_BASE_GET_MIMPID:
|
||||
*out_val = csr_read(CSR_MIMPID);
|
||||
break;
|
||||
case SBI_EXT_BASE_PROBE_EXT:
|
||||
ret = sbi_ecall_base_probe(args[0], out_val);
|
||||
break;
|
||||
default:
|
||||
ret = SBI_ENOTSUPP;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct sbi_ecall_extension ecall_base = {
|
||||
.extid_start = SBI_EXT_BASE,
|
||||
.extid_end = SBI_EXT_BASE,
|
||||
.handle = sbi_ecall_base_handler,
|
||||
};
|
51
lib/sbi/sbi_ecall_hsm.c
Normal file
51
lib/sbi/sbi_ecall_hsm.c
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Atish Patra <atish.patra@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_version.h>
|
||||
#include <sbi/sbi_hsm.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/riscv_asm.h>
|
||||
|
||||
static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
int ret = 0, hstate;
|
||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||
|
||||
switch (funcid) {
|
||||
case SBI_EXT_HSM_HART_START:
|
||||
ret = sbi_hsm_hart_start(scratch, args[0], args[1], args[2]);
|
||||
break;
|
||||
case SBI_EXT_HSM_HART_STOP:
|
||||
ret = sbi_hsm_hart_stop(scratch, TRUE);
|
||||
break;
|
||||
case SBI_EXT_HSM_HART_GET_STATUS:
|
||||
hstate = sbi_hsm_hart_get_state(args[0]);
|
||||
ret = sbi_hsm_hart_state_to_status(hstate);
|
||||
break;
|
||||
default:
|
||||
ret = SBI_ENOTSUPP;
|
||||
};
|
||||
if (ret >= 0) {
|
||||
*out_val = ret;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct sbi_ecall_extension ecall_hsm = {
|
||||
.extid_start = SBI_EXT_HSM,
|
||||
.extid_end = SBI_EXT_HSM,
|
||||
.handle = sbi_ecall_hsm_handler,
|
||||
};
|
117
lib/sbi/sbi_ecall_legacy.c
Normal file
117
lib/sbi/sbi_ecall_legacy.c
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
* Atish Patra <atish.patra@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_hsm.h>
|
||||
#include <sbi/sbi_ipi.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_system.h>
|
||||
#include <sbi/sbi_timer.h>
|
||||
#include <sbi/sbi_tlb.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
#include <sbi/sbi_unpriv.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
|
||||
static int sbi_load_hart_mask_unpriv(ulong *pmask, ulong *hmask,
|
||||
struct sbi_trap_info *uptrap)
|
||||
{
|
||||
ulong mask = 0;
|
||||
|
||||
if (pmask) {
|
||||
mask = sbi_load_ulong(pmask, uptrap);
|
||||
if (uptrap->cause)
|
||||
return SBI_ETRAP;
|
||||
} else {
|
||||
sbi_hsm_hart_started_mask(0, &mask);
|
||||
}
|
||||
*hmask = mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
int ret = 0;
|
||||
struct sbi_tlb_info tlb_info;
|
||||
u32 source_hart = current_hartid();
|
||||
ulong hmask = 0;
|
||||
|
||||
switch (extid) {
|
||||
case SBI_EXT_0_1_SET_TIMER:
|
||||
#if __riscv_xlen == 32
|
||||
sbi_timer_event_start((((u64)args[1] << 32) | (u64)args[0]));
|
||||
#else
|
||||
sbi_timer_event_start((u64)args[0]);
|
||||
#endif
|
||||
break;
|
||||
case SBI_EXT_0_1_CONSOLE_PUTCHAR:
|
||||
sbi_putc(args[0]);
|
||||
break;
|
||||
case SBI_EXT_0_1_CONSOLE_GETCHAR:
|
||||
ret = sbi_getc();
|
||||
break;
|
||||
case SBI_EXT_0_1_CLEAR_IPI:
|
||||
sbi_ipi_clear_smode();
|
||||
break;
|
||||
case SBI_EXT_0_1_SEND_IPI:
|
||||
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
|
||||
&hmask, out_trap);
|
||||
if (ret != SBI_ETRAP)
|
||||
ret = sbi_ipi_send_smode(hmask, 0);
|
||||
break;
|
||||
case SBI_EXT_0_1_REMOTE_FENCE_I:
|
||||
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
|
||||
&hmask, out_trap);
|
||||
if (ret != SBI_ETRAP) {
|
||||
SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, 0,
|
||||
SBI_ITLB_FLUSH, source_hart);
|
||||
ret = sbi_tlb_request(hmask, 0, &tlb_info);
|
||||
}
|
||||
break;
|
||||
case SBI_EXT_0_1_REMOTE_SFENCE_VMA:
|
||||
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
|
||||
&hmask, out_trap);
|
||||
if (ret != SBI_ETRAP) {
|
||||
SBI_TLB_INFO_INIT(&tlb_info, args[1], args[2], 0, 0,
|
||||
SBI_TLB_FLUSH_VMA, source_hart);
|
||||
ret = sbi_tlb_request(hmask, 0, &tlb_info);
|
||||
}
|
||||
break;
|
||||
case SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID:
|
||||
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
|
||||
&hmask, out_trap);
|
||||
if (ret != SBI_ETRAP) {
|
||||
SBI_TLB_INFO_INIT(&tlb_info, args[1], args[2], args[3],
|
||||
0, SBI_TLB_FLUSH_VMA_ASID,
|
||||
source_hart);
|
||||
ret = sbi_tlb_request(hmask, 0, &tlb_info);
|
||||
}
|
||||
break;
|
||||
case SBI_EXT_0_1_SHUTDOWN:
|
||||
sbi_system_reset(SBI_PLATFORM_RESET_SHUTDOWN);
|
||||
break;
|
||||
default:
|
||||
ret = SBI_ENOTSUPP;
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct sbi_ecall_extension ecall_legacy = {
|
||||
.extid_start = SBI_EXT_0_1_SET_TIMER,
|
||||
.extid_end = SBI_EXT_0_1_SHUTDOWN,
|
||||
.handle = sbi_ecall_legacy_handler,
|
||||
};
|
129
lib/sbi/sbi_ecall_replace.c
Normal file
129
lib/sbi/sbi_ecall_replace.c
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
* Atish Patra <atish.patra@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_ipi.h>
|
||||
#include <sbi/sbi_timer.h>
|
||||
#include <sbi/sbi_tlb.h>
|
||||
|
||||
static int sbi_ecall_time_handler(unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (funcid == SBI_EXT_TIME_SET_TIMER) {
|
||||
#if __riscv_xlen == 32
|
||||
sbi_timer_event_start((((u64)args[1] << 32) | (u64)args[0]));
|
||||
#else
|
||||
sbi_timer_event_start((u64)args[0]);
|
||||
#endif
|
||||
} else
|
||||
ret = SBI_ENOTSUPP;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct sbi_ecall_extension ecall_time = {
|
||||
.extid_start = SBI_EXT_TIME,
|
||||
.extid_end = SBI_EXT_TIME,
|
||||
.handle = sbi_ecall_time_handler,
|
||||
};
|
||||
|
||||
static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long vmid;
|
||||
struct sbi_tlb_info tlb_info;
|
||||
u32 source_hart = current_hartid();
|
||||
|
||||
if (funcid >= SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA &&
|
||||
funcid <= SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID)
|
||||
if (!misa_extension('H'))
|
||||
return SBI_ENOTSUPP;
|
||||
|
||||
switch (funcid) {
|
||||
case SBI_EXT_RFENCE_REMOTE_FENCE_I:
|
||||
SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, 0,
|
||||
SBI_ITLB_FLUSH, source_hart);
|
||||
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
||||
break;
|
||||
case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA:
|
||||
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0, 0,
|
||||
SBI_TLB_FLUSH_GVMA, source_hart);
|
||||
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
||||
break;
|
||||
case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID:
|
||||
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0, args[4],
|
||||
SBI_TLB_FLUSH_GVMA_VMID, source_hart);
|
||||
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
||||
break;
|
||||
case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA:
|
||||
vmid = (csr_read(CSR_HGATP) & HGATP_VMID_MASK);
|
||||
vmid = vmid >> HGATP_VMID_SHIFT;
|
||||
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0, vmid,
|
||||
SBI_TLB_FLUSH_VVMA, source_hart);
|
||||
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
||||
break;
|
||||
case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID:
|
||||
vmid = (csr_read(CSR_HGATP) & HGATP_VMID_MASK);
|
||||
vmid = vmid >> HGATP_VMID_SHIFT;
|
||||
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], args[4], vmid,
|
||||
SBI_TLB_FLUSH_VVMA_ASID, source_hart);
|
||||
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
||||
break;
|
||||
case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA:
|
||||
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0, 0,
|
||||
SBI_TLB_FLUSH_VMA, source_hart);
|
||||
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
||||
break;
|
||||
case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID:
|
||||
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], args[4], 0,
|
||||
SBI_TLB_FLUSH_VMA_ASID, source_hart);
|
||||
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
||||
break;
|
||||
default:
|
||||
ret = SBI_ENOTSUPP;
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct sbi_ecall_extension ecall_rfence = {
|
||||
.extid_start = SBI_EXT_RFENCE,
|
||||
.extid_end = SBI_EXT_RFENCE,
|
||||
.handle = sbi_ecall_rfence_handler,
|
||||
};
|
||||
|
||||
static int sbi_ecall_ipi_handler(unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (funcid == SBI_EXT_IPI_SEND_IPI)
|
||||
ret = sbi_ipi_send_smode(args[0], args[1]);
|
||||
else
|
||||
ret = SBI_ENOTSUPP;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct sbi_ecall_extension ecall_ipi = {
|
||||
.extid_start = SBI_EXT_IPI,
|
||||
.extid_end = SBI_EXT_IPI,
|
||||
.handle = sbi_ecall_ipi_handler,
|
||||
};
|
38
lib/sbi/sbi_ecall_vendor.c
Normal file
38
lib/sbi/sbi_ecall_vendor.c
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
* Atish Patra <atish.patra@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
|
||||
static int sbi_ecall_vendor_probe(unsigned long extid,
|
||||
unsigned long *out_val)
|
||||
{
|
||||
*out_val = sbi_platform_vendor_ext_check(sbi_platform_thishart_ptr(),
|
||||
extid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sbi_ecall_vendor_handler(unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
return sbi_platform_vendor_ext_provider(sbi_platform_thishart_ptr(),
|
||||
extid, funcid, args,
|
||||
out_val, out_trap);
|
||||
}
|
||||
|
||||
struct sbi_ecall_extension ecall_vendor = {
|
||||
.extid_start = SBI_EXT_VENDOR_START,
|
||||
.extid_end = SBI_EXT_VENDOR_END,
|
||||
.probe = sbi_ecall_vendor_probe,
|
||||
.handle = sbi_ecall_vendor_handler,
|
||||
};
|
@@ -9,21 +9,35 @@
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include <sbi/sbi_bits.h>
|
||||
#include <sbi/sbi_bitops.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_emulate_csr.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_timer.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
|
||||
int sbi_emulate_csr_read(int csr_num, u32 hartid, ulong mstatus,
|
||||
struct sbi_scratch *scratch, ulong *csr_val)
|
||||
int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs,
|
||||
ulong *csr_val)
|
||||
{
|
||||
int ret = 0;
|
||||
ulong cen = -1UL;
|
||||
ulong prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
|
||||
#if __riscv_xlen == 32
|
||||
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
|
||||
#else
|
||||
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
|
||||
#endif
|
||||
|
||||
if (EXTRACT_FIELD(mstatus, MSTATUS_MPP) == PRV_U)
|
||||
if (prev_mode == PRV_U)
|
||||
cen = csr_read(CSR_SCOUNTEREN);
|
||||
|
||||
switch (csr_num) {
|
||||
case CSR_HTIMEDELTA:
|
||||
if (prev_mode == PRV_S && !virt)
|
||||
*csr_val = sbi_timer_get_delta();
|
||||
else
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
case CSR_CYCLE:
|
||||
if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1))
|
||||
return -1;
|
||||
@@ -32,7 +46,8 @@ int sbi_emulate_csr_read(int csr_num, u32 hartid, ulong mstatus,
|
||||
case CSR_TIME:
|
||||
if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1))
|
||||
return -1;
|
||||
*csr_val = sbi_timer_value(scratch);
|
||||
*csr_val = (virt) ? sbi_timer_virt_value():
|
||||
sbi_timer_value();
|
||||
break;
|
||||
case CSR_INSTRET:
|
||||
if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
|
||||
@@ -50,6 +65,12 @@ int sbi_emulate_csr_read(int csr_num, u32 hartid, ulong mstatus,
|
||||
*csr_val = csr_read(CSR_MHPMCOUNTER4);
|
||||
break;
|
||||
#if __riscv_xlen == 32
|
||||
case CSR_HTIMEDELTAH:
|
||||
if (prev_mode == PRV_S && !virt)
|
||||
*csr_val = sbi_timer_get_delta() >> 32;
|
||||
else
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
case CSR_CYCLEH:
|
||||
if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1))
|
||||
return -1;
|
||||
@@ -58,7 +79,8 @@ int sbi_emulate_csr_read(int csr_num, u32 hartid, ulong mstatus,
|
||||
case CSR_TIMEH:
|
||||
if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1))
|
||||
return -1;
|
||||
*csr_val = sbi_timer_value(scratch) >> 32;
|
||||
*csr_val = (virt) ? sbi_timer_virt_value() >> 32:
|
||||
sbi_timer_value() >> 32;
|
||||
break;
|
||||
case CSR_INSTRETH:
|
||||
if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
|
||||
@@ -83,18 +105,35 @@ int sbi_emulate_csr_read(int csr_num, u32 hartid, ulong mstatus,
|
||||
*csr_val = csr_read(CSR_MHPMEVENT4);
|
||||
break;
|
||||
default:
|
||||
sbi_printf("%s: hartid%d: invalid csr_num=0x%x\n", __func__,
|
||||
hartid, csr_num);
|
||||
return SBI_ENOTSUPP;
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
};
|
||||
|
||||
return 0;
|
||||
if (ret)
|
||||
sbi_dprintf("%s: hartid%d: invalid csr_num=0x%x\n",
|
||||
__func__, current_hartid(), csr_num);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sbi_emulate_csr_write(int csr_num, u32 hartid, ulong mstatus,
|
||||
struct sbi_scratch *scratch, ulong csr_val)
|
||||
int sbi_emulate_csr_write(int csr_num, struct sbi_trap_regs *regs,
|
||||
ulong csr_val)
|
||||
{
|
||||
int ret = 0;
|
||||
ulong prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
|
||||
#if __riscv_xlen == 32
|
||||
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
|
||||
#else
|
||||
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
|
||||
#endif
|
||||
|
||||
switch (csr_num) {
|
||||
case CSR_HTIMEDELTA:
|
||||
if (prev_mode == PRV_S && !virt)
|
||||
sbi_timer_set_delta(csr_val);
|
||||
else
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
case CSR_CYCLE:
|
||||
csr_write(CSR_MCYCLE, csr_val);
|
||||
break;
|
||||
@@ -108,6 +147,12 @@ int sbi_emulate_csr_write(int csr_num, u32 hartid, ulong mstatus,
|
||||
csr_write(CSR_MHPMCOUNTER4, csr_val);
|
||||
break;
|
||||
#if __riscv_xlen == 32
|
||||
case CSR_HTIMEDELTAH:
|
||||
if (prev_mode == PRV_S && !virt)
|
||||
sbi_timer_set_delta_upper(csr_val);
|
||||
else
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
case CSR_CYCLEH:
|
||||
csr_write(CSR_MCYCLEH, csr_val);
|
||||
break;
|
||||
@@ -128,10 +173,13 @@ int sbi_emulate_csr_write(int csr_num, u32 hartid, ulong mstatus,
|
||||
csr_write(CSR_MHPMEVENT4, csr_val);
|
||||
break;
|
||||
default:
|
||||
sbi_printf("%s: hartid%d: invalid csr_num=0x%x\n", __func__,
|
||||
hartid, csr_num);
|
||||
return SBI_ENOTSUPP;
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
};
|
||||
|
||||
return 0;
|
||||
if (ret)
|
||||
sbi_dprintf("%s: hartid%d: invalid csr_num=0x%x\n",
|
||||
__func__, current_hartid(), csr_num);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
56
lib/sbi/sbi_expected_trap.S
Normal file
56
lib/sbi/sbi_expected_trap.S
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
|
||||
/*
|
||||
* We assume that faulting instruction is is 4-byte long and blindly
|
||||
* increment SEPC by 4.
|
||||
*
|
||||
* The trap info will be saved as follows:
|
||||
* A3 <- pointer struct sbi_trap_info
|
||||
* A4 <- temporary
|
||||
*/
|
||||
|
||||
.align 3
|
||||
.global __sbi_expected_trap
|
||||
__sbi_expected_trap:
|
||||
/* Without H-extension so, MTVAL2 and MTINST CSRs not available */
|
||||
csrr a4, CSR_MEPC
|
||||
REG_S a4, SBI_TRAP_INFO_OFFSET(epc)(a3)
|
||||
csrr a4, CSR_MCAUSE
|
||||
REG_S a4, SBI_TRAP_INFO_OFFSET(cause)(a3)
|
||||
csrr a4, CSR_MTVAL
|
||||
REG_S a4, SBI_TRAP_INFO_OFFSET(tval)(a3)
|
||||
REG_S zero, SBI_TRAP_INFO_OFFSET(tval2)(a3)
|
||||
REG_S zero, SBI_TRAP_INFO_OFFSET(tinst)(a3)
|
||||
csrr a4, CSR_MEPC
|
||||
addi a4, a4, 4
|
||||
csrw CSR_MEPC, a4
|
||||
mret
|
||||
|
||||
.align 3
|
||||
.global __sbi_expected_trap_hext
|
||||
__sbi_expected_trap_hext:
|
||||
/* With H-extension so, MTVAL2 and MTINST CSRs available */
|
||||
csrr a4, CSR_MEPC
|
||||
REG_S a4, SBI_TRAP_INFO_OFFSET(epc)(a3)
|
||||
csrr a4, CSR_MCAUSE
|
||||
REG_S a4, SBI_TRAP_INFO_OFFSET(cause)(a3)
|
||||
csrr a4, CSR_MTVAL
|
||||
REG_S a4, SBI_TRAP_INFO_OFFSET(tval)(a3)
|
||||
csrr a4, CSR_MTVAL2
|
||||
REG_S a4, SBI_TRAP_INFO_OFFSET(tval2)(a3)
|
||||
csrr a4, CSR_MTINST
|
||||
REG_S a4, SBI_TRAP_INFO_OFFSET(tinst)(a3)
|
||||
csrr a4, CSR_MEPC
|
||||
addi a4, a4, 4
|
||||
csrw CSR_MEPC, a4
|
||||
mret
|
@@ -20,7 +20,7 @@ void sbi_fifo_init(struct sbi_fifo *fifo, void *queue_mem, u16 entries,
|
||||
fifo->entry_size = entry_size;
|
||||
SPIN_LOCK_INIT(&fifo->qlock);
|
||||
fifo->avail = fifo->tail = 0;
|
||||
sbi_memset(fifo->queue, 0, entries * entry_size);
|
||||
sbi_memset(fifo->queue, 0, (size_t)entries * entry_size);
|
||||
}
|
||||
|
||||
/* Note: must be called with fifo->qlock held */
|
||||
@@ -54,6 +54,21 @@ bool sbi_fifo_is_full(struct sbi_fifo *fifo)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Note: must be called with fifo->qlock held */
|
||||
static inline void __sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data)
|
||||
{
|
||||
u32 head;
|
||||
|
||||
head = (u32)fifo->tail + fifo->avail;
|
||||
if (head >= fifo->num_entries)
|
||||
head = head - fifo->num_entries;
|
||||
|
||||
sbi_memcpy(fifo->queue + head * fifo->entry_size, data, fifo->entry_size);
|
||||
|
||||
fifo->avail++;
|
||||
}
|
||||
|
||||
|
||||
/* Note: must be called with fifo->qlock held */
|
||||
static inline bool __sbi_fifo_is_empty(struct sbi_fifo *fifo)
|
||||
{
|
||||
@@ -74,9 +89,11 @@ bool sbi_fifo_is_empty(struct sbi_fifo *fifo)
|
||||
/* Note: must be called with fifo->qlock held */
|
||||
static inline void __sbi_fifo_reset(struct sbi_fifo *fifo)
|
||||
{
|
||||
size_t size = (size_t)fifo->num_entries * fifo->entry_size;
|
||||
|
||||
fifo->avail = 0;
|
||||
fifo->tail = 0;
|
||||
sbi_memset(fifo->queue, 0, fifo->num_entries * fifo->entry_size);
|
||||
sbi_memset(fifo->queue, 0, size);
|
||||
}
|
||||
|
||||
bool sbi_fifo_reset(struct sbi_fifo *fifo)
|
||||
@@ -107,7 +124,9 @@ int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
|
||||
|
||||
if (!fifo || !in)
|
||||
return ret;
|
||||
|
||||
spin_lock(&fifo->qlock);
|
||||
|
||||
if (__sbi_fifo_is_empty(fifo)) {
|
||||
spin_unlock(&fifo->qlock);
|
||||
return ret;
|
||||
@@ -118,12 +137,10 @@ int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
|
||||
if (index >= fifo->num_entries)
|
||||
index = index - fifo->num_entries;
|
||||
entry = (void *)fifo->queue + (u32)index * fifo->entry_size;
|
||||
ret = fptr(in, entry);
|
||||
ret = fptr(in, entry);
|
||||
|
||||
if (ret == SBI_FIFO_SKIP || ret == SBI_FIFO_UPDATED) {
|
||||
break;
|
||||
} else if (ret == SBI_FIFO_RESET) {
|
||||
__sbi_fifo_reset(fifo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(&fifo->qlock);
|
||||
@@ -133,8 +150,6 @@ int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
|
||||
|
||||
int sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data)
|
||||
{
|
||||
u32 head;
|
||||
|
||||
if (!fifo || !data)
|
||||
return SBI_EINVAL;
|
||||
|
||||
@@ -144,14 +159,7 @@ int sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data)
|
||||
spin_unlock(&fifo->qlock);
|
||||
return SBI_ENOSPC;
|
||||
}
|
||||
|
||||
head = (u32)fifo->tail + fifo->avail;
|
||||
if (head >= fifo->num_entries)
|
||||
head = head - fifo->num_entries;
|
||||
|
||||
sbi_memcpy(fifo->queue + head * fifo->entry_size, data, fifo->entry_size);
|
||||
|
||||
fifo->avail++;
|
||||
__sbi_fifo_enqueue(fifo, data);
|
||||
|
||||
spin_unlock(&fifo->qlock);
|
||||
|
||||
|
@@ -11,33 +11,45 @@
|
||||
#include <sbi/riscv_barrier.h>
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include <sbi/riscv_fp.h>
|
||||
#include <sbi/riscv_locks.h>
|
||||
#include <sbi/sbi_bits.h>
|
||||
#include <sbi/sbi_bitops.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_csr_detect.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_math.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_string.h>
|
||||
|
||||
/**
|
||||
* Return HART ID of the caller.
|
||||
*/
|
||||
unsigned int sbi_current_hartid()
|
||||
{
|
||||
return (u32)csr_read(CSR_MHARTID);
|
||||
}
|
||||
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)
|
||||
{
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
unsigned long mstatus_val = 0;
|
||||
|
||||
/* Enable FPU */
|
||||
if (misa_extension('D') || misa_extension('F'))
|
||||
csr_write(CSR_MSTATUS, MSTATUS_FS);
|
||||
mstatus_val |= MSTATUS_FS;
|
||||
|
||||
/* Enable Vector context */
|
||||
if (misa_extension('V'))
|
||||
mstatus_val |= MSTATUS_VS;
|
||||
|
||||
csr_write(CSR_MSTATUS, mstatus_val);
|
||||
|
||||
/* Enable user/supervisor use of perf counters */
|
||||
if (misa_extension('S') && sbi_platform_has_scounteren(plat))
|
||||
if (misa_extension('S') &&
|
||||
sbi_hart_has_feature(scratch, SBI_HART_HAS_SCOUNTEREN))
|
||||
csr_write(CSR_SCOUNTEREN, -1);
|
||||
if (sbi_platform_has_mcounteren(plat))
|
||||
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTEREN))
|
||||
csr_write(CSR_MCOUNTEREN, -1);
|
||||
|
||||
/* Disable all interrupts */
|
||||
@@ -52,8 +64,6 @@ static int fp_init(u32 hartid)
|
||||
{
|
||||
#ifdef __riscv_flen
|
||||
int i;
|
||||
#else
|
||||
unsigned long fd_mask;
|
||||
#endif
|
||||
|
||||
if (!misa_extension('D') && !misa_extension('F'))
|
||||
@@ -66,11 +76,6 @@ static int fp_init(u32 hartid)
|
||||
for (i = 0; i < 32; i++)
|
||||
init_fp_reg(i);
|
||||
csr_write(CSR_FCSR, 0);
|
||||
#else
|
||||
fd_mask = (1 << ('F' - 'A')) | (1 << ('D' - 'A'));
|
||||
csr_clear(CSR_MISA, fd_mask);
|
||||
if (csr_read(CSR_MISA) & fd_mask)
|
||||
return SBI_ENOTSUPP;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
@@ -82,7 +87,7 @@ static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
|
||||
unsigned long interrupts, exceptions;
|
||||
|
||||
if (!misa_extension('S'))
|
||||
/* No delegation possible as mideleg does not exist*/
|
||||
/* No delegation possible as mideleg does not exist */
|
||||
return 0;
|
||||
|
||||
/* Send M-mode interrupts and most exceptions to S-mode */
|
||||
@@ -94,51 +99,77 @@ static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
|
||||
(1U << CAUSE_LOAD_PAGE_FAULT) |
|
||||
(1U << CAUSE_STORE_PAGE_FAULT);
|
||||
|
||||
/*
|
||||
* If hypervisor extension available then we only handle hypervisor
|
||||
* calls (i.e. ecalls from HS-mode) in M-mode.
|
||||
*
|
||||
* The HS-mode will additionally handle supervisor calls (i.e. ecalls
|
||||
* from VS-mode), Guest page faults and Virtual interrupts.
|
||||
*/
|
||||
if (misa_extension('H')) {
|
||||
exceptions |= (1U << CAUSE_SUPERVISOR_ECALL);
|
||||
exceptions |= (1U << CAUSE_FETCH_GUEST_PAGE_FAULT);
|
||||
exceptions |= (1U << CAUSE_LOAD_GUEST_PAGE_FAULT);
|
||||
exceptions |= (1U << CAUSE_VIRTUAL_INST_FAULT);
|
||||
exceptions |= (1U << CAUSE_STORE_GUEST_PAGE_FAULT);
|
||||
}
|
||||
|
||||
csr_write(CSR_MIDELEG, interrupts);
|
||||
csr_write(CSR_MEDELEG, exceptions);
|
||||
|
||||
if (csr_read(CSR_MIDELEG) != interrupts)
|
||||
return SBI_EFAIL;
|
||||
if (csr_read(CSR_MEDELEG) != exceptions)
|
||||
return SBI_EFAIL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long log2roundup(unsigned long x)
|
||||
void sbi_hart_delegation_dump(struct sbi_scratch *scratch)
|
||||
{
|
||||
unsigned long ret = 0;
|
||||
if (!misa_extension('S'))
|
||||
/* No delegation possible as mideleg does not exist*/
|
||||
return;
|
||||
|
||||
while (ret < __riscv_xlen) {
|
||||
if (x <= (1UL << ret))
|
||||
break;
|
||||
ret++;
|
||||
}
|
||||
#if __riscv_xlen == 32
|
||||
sbi_printf("MIDELEG : 0x%08lx\n", csr_read(CSR_MIDELEG));
|
||||
sbi_printf("MEDELEG : 0x%08lx\n", csr_read(CSR_MEDELEG));
|
||||
#else
|
||||
sbi_printf("MIDELEG : 0x%016lx\n", csr_read(CSR_MIDELEG));
|
||||
sbi_printf("MEDELEG : 0x%016lx\n", csr_read(CSR_MEDELEG));
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
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)
|
||||
{
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
unsigned long prot, addr, size, l2l;
|
||||
unsigned int i;
|
||||
unsigned long prot, addr, size;
|
||||
unsigned int i, pmp_count;
|
||||
|
||||
if (!sbi_platform_has_pmp(plat))
|
||||
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP))
|
||||
return;
|
||||
|
||||
for (i = 0; i < PMP_COUNT; i++) {
|
||||
pmp_get(i, &prot, &addr, &l2l);
|
||||
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;
|
||||
if (l2l < __riscv_xlen)
|
||||
size = (1UL << l2l);
|
||||
else
|
||||
size = 0;
|
||||
#if __riscv_xlen == 32
|
||||
sbi_printf("PMP%d: 0x%08lx-0x%08lx (A",
|
||||
sbi_printf("PMP%d : 0x%08lx-0x%08lx (A",
|
||||
#else
|
||||
sbi_printf("PMP%d: 0x%016lx-0x%016lx (A",
|
||||
sbi_printf("PMP%d : 0x%016lx-0x%016lx (A",
|
||||
#endif
|
||||
i, addr, addr + size - 1);
|
||||
if (prot & PMP_L)
|
||||
@@ -153,48 +184,243 @@ 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, tempaddr;
|
||||
unsigned int i, pmp_count;
|
||||
|
||||
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP))
|
||||
return SBI_OK;
|
||||
|
||||
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;
|
||||
if (tempaddr <= addr && addr <= tempaddr + size)
|
||||
if (!(prot & attr))
|
||||
return SBI_EINVALID_ADDR;
|
||||
}
|
||||
|
||||
return SBI_OK;
|
||||
}
|
||||
|
||||
static int pmp_init(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
u32 i, 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);
|
||||
|
||||
if (!sbi_platform_has_pmp(plat))
|
||||
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP))
|
||||
return 0;
|
||||
|
||||
/* Firmware PMP region to protect OpenSBI firmware */
|
||||
fw_size_log2 = log2roundup(scratch->fw_size);
|
||||
fw_start = scratch->fw_start & ~((1UL << fw_size_log2) - 1UL);
|
||||
|
||||
pmp_set(0, 0, fw_start, fw_size_log2);
|
||||
fw_start = scratch->fw_start & ~((1UL << fw_size_log2) - 1UL);
|
||||
pmp_set(pmp_idx++, 0, fw_start, fw_size_log2);
|
||||
|
||||
/* Platform specific PMP regions */
|
||||
count = sbi_platform_pmp_region_count(plat, hartid);
|
||||
if ((PMP_COUNT - 1) < count)
|
||||
count = (PMP_COUNT - 1);
|
||||
|
||||
for (i = 0; i < count; 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;
|
||||
pmp_set(i + 1, prot, addr, log2size);
|
||||
pmp_set(pmp_idx++, prot, addr, log2size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Default PMP region for allowing S-mode and U-mode access to
|
||||
* memory not covered by:
|
||||
* 1) Firmware PMP region
|
||||
* 2) Platform specific PMP regions
|
||||
*/
|
||||
pmp_set(pmp_idx++, PMP_R | PMP_W | PMP_X, 0, __riscv_xlen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long trap_info_offset;
|
||||
/**
|
||||
* Check whether a particular hart feature is available
|
||||
*
|
||||
* @param scratch pointer to the HART scratch space
|
||||
* @param feature the feature to check
|
||||
* @returns true (feature available) or false (feature not available)
|
||||
*/
|
||||
bool sbi_hart_has_feature(struct sbi_scratch *scratch, unsigned long feature)
|
||||
{
|
||||
struct hart_features *hfeatures =
|
||||
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||
|
||||
if (hfeatures->features & feature)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static unsigned long hart_get_features(struct sbi_scratch *scratch)
|
||||
{
|
||||
struct hart_features *hfeatures =
|
||||
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||
|
||||
return hfeatures->features;
|
||||
}
|
||||
|
||||
static inline char *sbi_hart_feature_id2string(unsigned long feature)
|
||||
{
|
||||
char *fstr = NULL;
|
||||
|
||||
if (!feature)
|
||||
return NULL;
|
||||
|
||||
switch (feature) {
|
||||
case SBI_HART_HAS_PMP:
|
||||
fstr = "pmp";
|
||||
break;
|
||||
case SBI_HART_HAS_SCOUNTEREN:
|
||||
fstr = "scounteren";
|
||||
break;
|
||||
case SBI_HART_HAS_MCOUNTEREN:
|
||||
fstr = "mcounteren";
|
||||
break;
|
||||
case SBI_HART_HAS_TIME:
|
||||
fstr = "time";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return fstr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the hart features in string format
|
||||
*
|
||||
* @param scratch pointer to the HART scratch space
|
||||
* @param features_str pointer to a char array where the features string will be
|
||||
* updated
|
||||
* @param nfstr length of the features_str. The feature string will be truncated
|
||||
* if nfstr is not long enough.
|
||||
*/
|
||||
void sbi_hart_get_features_str(struct sbi_scratch *scratch,
|
||||
char *features_str, int nfstr)
|
||||
{
|
||||
unsigned long features, feat = 1UL;
|
||||
char *temp;
|
||||
int offset = 0;
|
||||
|
||||
if (!features_str || nfstr <= 0)
|
||||
return;
|
||||
sbi_memset(features_str, 0, nfstr);
|
||||
|
||||
features = hart_get_features(scratch);
|
||||
if (!features)
|
||||
goto done;
|
||||
|
||||
do {
|
||||
if (features & feat) {
|
||||
temp = sbi_hart_feature_id2string(feat);
|
||||
if (temp) {
|
||||
sbi_snprintf(features_str + offset, nfstr,
|
||||
"%s,", temp);
|
||||
offset = offset + sbi_strlen(temp) + 1;
|
||||
}
|
||||
}
|
||||
feat = feat << 1;
|
||||
} while (feat <= SBI_HART_HAS_LAST_FEATURE);
|
||||
|
||||
done:
|
||||
if (offset)
|
||||
features_str[offset - 1] = '\0';
|
||||
else
|
||||
sbi_strncpy(features_str, "none", nfstr);
|
||||
}
|
||||
|
||||
static void hart_detect_features(struct sbi_scratch *scratch)
|
||||
{
|
||||
struct sbi_trap_info trap = {0};
|
||||
struct hart_features *hfeatures;
|
||||
unsigned long val;
|
||||
|
||||
/* 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 */
|
||||
#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;
|
||||
val = csr_read_allowed(CSR_SCOUNTEREN, (unsigned long)&trap);
|
||||
if (!trap.cause) {
|
||||
csr_write_allowed(CSR_SCOUNTEREN, (unsigned long)&trap, val);
|
||||
if (!trap.cause)
|
||||
hfeatures->features |= SBI_HART_HAS_SCOUNTEREN;
|
||||
}
|
||||
|
||||
/* Detect if hart supports MCOUNTEREN feature */
|
||||
trap.cause = 0;
|
||||
val = csr_read_allowed(CSR_MCOUNTEREN, (unsigned long)&trap);
|
||||
if (!trap.cause) {
|
||||
csr_write_allowed(CSR_MCOUNTEREN, (unsigned long)&trap, val);
|
||||
if (!trap.cause)
|
||||
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)
|
||||
hfeatures->features |= SBI_HART_HAS_TIME;
|
||||
}
|
||||
|
||||
int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (cold_boot) {
|
||||
trap_info_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__,
|
||||
"HART_TRAP_INFO");
|
||||
if (!trap_info_offset)
|
||||
if (misa_extension('H'))
|
||||
sbi_hart_expected_trap = &__sbi_expected_trap_hext;
|
||||
|
||||
hart_features_offset = sbi_scratch_alloc_offset(
|
||||
sizeof(struct hart_features),
|
||||
"HART_FEATURES");
|
||||
if (!hart_features_offset)
|
||||
return SBI_ENOMEM;
|
||||
}
|
||||
|
||||
hart_detect_features(scratch);
|
||||
|
||||
mstatus_init(scratch, hartid);
|
||||
|
||||
rc = fp_init(hartid);
|
||||
@@ -208,29 +434,6 @@ int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
|
||||
return pmp_init(scratch, hartid);
|
||||
}
|
||||
|
||||
void *sbi_hart_get_trap_info(struct sbi_scratch *scratch)
|
||||
{
|
||||
unsigned long *trap_info;
|
||||
|
||||
if (!trap_info_offset)
|
||||
return NULL;
|
||||
|
||||
trap_info = sbi_scratch_offset_ptr(scratch, trap_info_offset);
|
||||
|
||||
return (void *)(*trap_info);
|
||||
}
|
||||
|
||||
void sbi_hart_set_trap_info(struct sbi_scratch *scratch, void *data)
|
||||
{
|
||||
unsigned long *trap_info;
|
||||
|
||||
if (!trap_info_offset)
|
||||
return;
|
||||
|
||||
trap_info = sbi_scratch_offset_ptr(scratch, trap_info_offset);
|
||||
*trap_info = (unsigned long)data;
|
||||
}
|
||||
|
||||
void __attribute__((noreturn)) sbi_hart_hang(void)
|
||||
{
|
||||
while (1)
|
||||
@@ -240,9 +443,14 @@ void __attribute__((noreturn)) sbi_hart_hang(void)
|
||||
|
||||
void __attribute__((noreturn))
|
||||
sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
|
||||
unsigned long next_addr, unsigned long next_mode)
|
||||
unsigned long next_addr, unsigned long next_mode,
|
||||
bool next_virt)
|
||||
{
|
||||
#if __riscv_xlen == 32
|
||||
unsigned long val, valH;
|
||||
#else
|
||||
unsigned long val;
|
||||
#endif
|
||||
|
||||
switch (next_mode) {
|
||||
case PRV_M:
|
||||
@@ -262,7 +470,23 @@ sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
|
||||
val = csr_read(CSR_MSTATUS);
|
||||
val = INSERT_FIELD(val, MSTATUS_MPP, next_mode);
|
||||
val = INSERT_FIELD(val, MSTATUS_MPIE, 0);
|
||||
|
||||
#if __riscv_xlen == 32
|
||||
if (misa_extension('H')) {
|
||||
valH = csr_read(CSR_MSTATUSH);
|
||||
if (next_virt)
|
||||
valH = INSERT_FIELD(valH, MSTATUSH_MPV, 1);
|
||||
else
|
||||
valH = INSERT_FIELD(valH, MSTATUSH_MPV, 0);
|
||||
csr_write(CSR_MSTATUSH, valH);
|
||||
}
|
||||
#else
|
||||
if (misa_extension('H')) {
|
||||
if (next_virt)
|
||||
val = INSERT_FIELD(val, MSTATUS_MPV, 1);
|
||||
else
|
||||
val = INSERT_FIELD(val, MSTATUS_MPV, 0);
|
||||
}
|
||||
#endif
|
||||
csr_write(CSR_MSTATUS, val);
|
||||
csr_write(CSR_MEPC, next_addr);
|
||||
|
||||
@@ -282,85 +506,3 @@ sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
|
||||
__asm__ __volatile__("mret" : : "r"(a0), "r"(a1));
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
static spinlock_t avail_hart_mask_lock = SPIN_LOCK_INITIALIZER;
|
||||
static volatile unsigned long avail_hart_mask = 0;
|
||||
|
||||
void sbi_hart_mark_available(u32 hartid)
|
||||
{
|
||||
spin_lock(&avail_hart_mask_lock);
|
||||
avail_hart_mask |= (1UL << hartid);
|
||||
spin_unlock(&avail_hart_mask_lock);
|
||||
}
|
||||
|
||||
void sbi_hart_unmark_available(u32 hartid)
|
||||
{
|
||||
spin_lock(&avail_hart_mask_lock);
|
||||
avail_hart_mask &= ~(1UL << hartid);
|
||||
spin_unlock(&avail_hart_mask_lock);
|
||||
}
|
||||
|
||||
ulong sbi_hart_available_mask(void)
|
||||
{
|
||||
ulong ret;
|
||||
|
||||
spin_lock(&avail_hart_mask_lock);
|
||||
ret = avail_hart_mask;
|
||||
spin_unlock(&avail_hart_mask_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef struct sbi_scratch *(*h2s)(ulong hartid);
|
||||
|
||||
struct sbi_scratch *sbi_hart_id_to_scratch(struct sbi_scratch *scratch,
|
||||
u32 hartid)
|
||||
{
|
||||
return ((h2s)scratch->hartid_to_scratch)(hartid);
|
||||
}
|
||||
|
||||
#define COLDBOOT_WAIT_BITMAP_SIZE __riscv_xlen
|
||||
static spinlock_t coldboot_wait_bitmap_lock = SPIN_LOCK_INITIALIZER;
|
||||
static unsigned long coldboot_wait_bitmap = 0;
|
||||
|
||||
void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
unsigned long mipval;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
if ((sbi_platform_hart_count(plat) <= hartid) ||
|
||||
(COLDBOOT_WAIT_BITMAP_SIZE <= hartid))
|
||||
sbi_hart_hang();
|
||||
|
||||
/* Set MSIE bit to receive IPI */
|
||||
csr_set(CSR_MIE, MIP_MSIP);
|
||||
|
||||
do {
|
||||
spin_lock(&coldboot_wait_bitmap_lock);
|
||||
coldboot_wait_bitmap |= (1UL << hartid);
|
||||
spin_unlock(&coldboot_wait_bitmap_lock);
|
||||
|
||||
wfi();
|
||||
mipval = csr_read(CSR_MIP);
|
||||
|
||||
spin_lock(&coldboot_wait_bitmap_lock);
|
||||
coldboot_wait_bitmap &= ~(1UL << hartid);
|
||||
spin_unlock(&coldboot_wait_bitmap_lock);
|
||||
} while (!(mipval && MIP_MSIP));
|
||||
|
||||
csr_clear(CSR_MIP, MIP_MSIP);
|
||||
}
|
||||
|
||||
void sbi_hart_wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
int max_hart = sbi_platform_hart_count(plat);
|
||||
|
||||
for (int i = 0; i < max_hart; i++) {
|
||||
/* send an IPI to every other hart */
|
||||
spin_lock(&coldboot_wait_bitmap_lock);
|
||||
if ((i != hartid) && (coldboot_wait_bitmap & (1UL << i)))
|
||||
sbi_platform_ipi_send(plat, i);
|
||||
spin_unlock(&coldboot_wait_bitmap_lock);
|
||||
}
|
||||
}
|
||||
|
135
lib/sbi/sbi_hfence.S
Normal file
135
lib/sbi/sbi_hfence.S
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
* Atish Patra <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* HFENCE.GVMA rs1, rs2
|
||||
* HFENCE.GVMA zero, rs2
|
||||
* HFENCE.GVMA rs1
|
||||
* HFENCE.GVMA
|
||||
*
|
||||
* rs1!=zero and rs2!=zero ==> HFENCE.GVMA rs1, rs2
|
||||
* rs1==zero and rs2!=zero ==> HFENCE.GVMA zero, rs2
|
||||
* rs1!=zero and rs2==zero ==> HFENCE.GVMA rs1
|
||||
* rs1==zero and rs2==zero ==> HFENCE.GVMA
|
||||
*
|
||||
* Instruction encoding of HFENCE.GVMA is:
|
||||
* 0110001 rs2(5) rs1(5) 000 00000 1110011
|
||||
*/
|
||||
|
||||
.align 3
|
||||
.global __sbi_hfence_gvma_vmid_gpa
|
||||
__sbi_hfence_gvma_vmid_gpa:
|
||||
/*
|
||||
* rs1 = a0 (GPA)
|
||||
* rs2 = a1 (VMID)
|
||||
* HFENCE.GVMA a0, a1
|
||||
* 0110001 01011 01010 000 00000 1110011
|
||||
*/
|
||||
.word 0x62b50073
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.global __sbi_hfence_gvma_vmid
|
||||
__sbi_hfence_gvma_vmid:
|
||||
/*
|
||||
* rs1 = zero
|
||||
* rs2 = a0 (VMID)
|
||||
* HFENCE.GVMA zero, a0
|
||||
* 0110001 01010 00000 000 00000 1110011
|
||||
*/
|
||||
.word 0x62a00073
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.global __sbi_hfence_gvma_gpa
|
||||
__sbi_hfence_gvma_gpa:
|
||||
/*
|
||||
* rs1 = a0 (GPA)
|
||||
* rs2 = zero
|
||||
* HFENCE.GVMA a0
|
||||
* 0110001 00000 01010 000 00000 1110011
|
||||
*/
|
||||
.word 0x62050073
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.global __sbi_hfence_gvma_all
|
||||
__sbi_hfence_gvma_all:
|
||||
/*
|
||||
* rs1 = zero
|
||||
* rs2 = zero
|
||||
* HFENCE.GVMA
|
||||
* 0110001 00000 00000 000 00000 1110011
|
||||
*/
|
||||
.word 0x62000073
|
||||
ret
|
||||
|
||||
/*
|
||||
* HFENCE.VVMA rs1, rs2
|
||||
* HFENCE.VVMA zero, rs2
|
||||
* HFENCE.VVMA rs1
|
||||
* HFENCE.VVMA
|
||||
*
|
||||
* rs1!=zero and rs2!=zero ==> HFENCE.VVMA rs1, rs2
|
||||
* rs1==zero and rs2!=zero ==> HFENCE.VVMA zero, rs2
|
||||
* rs1!=zero and rs2==zero ==> HFENCE.VVMA rs1
|
||||
* rs1==zero and rs2==zero ==> HFENCE.vVMA
|
||||
*
|
||||
* Instruction encoding of HFENCE.VVMA is:
|
||||
* 0010001 rs2(5) rs1(5) 000 00000 1110011
|
||||
*/
|
||||
|
||||
.align 3
|
||||
.global __sbi_hfence_vvma_asid_va
|
||||
__sbi_hfence_vvma_asid_va:
|
||||
/*
|
||||
* rs1 = a0 (VA)
|
||||
* rs2 = a1 (ASID)
|
||||
* HFENCE.VVMA a0, a1
|
||||
* 0010001 01011 01010 000 00000 1110011
|
||||
*/
|
||||
.word 0x22b50073
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.global __sbi_hfence_vvma_asid
|
||||
__sbi_hfence_vvma_asid:
|
||||
/*
|
||||
* rs1 = zero
|
||||
* rs2 = a0 (ASID)
|
||||
* HFENCE.VVMA zero, a0
|
||||
* 0010001 01010 00000 000 00000 1110011
|
||||
*/
|
||||
.word 0x22a00073
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.global __sbi_hfence_vvma_va
|
||||
__sbi_hfence_vvma_va:
|
||||
/*
|
||||
* rs1 = a0 (VA)
|
||||
* rs2 = zero
|
||||
* HFENCE.VVMA zero, a0
|
||||
* 0010001 00000 01010 000 00000 1110011
|
||||
*/
|
||||
.word 0x22050073
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.global __sbi_hfence_vvma_all
|
||||
__sbi_hfence_vvma_all:
|
||||
/*
|
||||
* rs1 = zero
|
||||
* rs2 = zero
|
||||
* HFENCE.VVMA
|
||||
* 0010001 00000 00000 000 00000 1110011
|
||||
*/
|
||||
.word 0x22000073
|
||||
ret
|
273
lib/sbi/sbi_hsm.c
Normal file
273
lib/sbi/sbi_hsm.c
Normal file
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Atish Patra <atish.patra@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/riscv_barrier.h>
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include <sbi/riscv_atomic.h>
|
||||
#include <sbi/sbi_bitops.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_hartmask.h>
|
||||
#include <sbi/sbi_hsm.h>
|
||||
#include <sbi/sbi_init.h>
|
||||
#include <sbi/sbi_ipi.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_system.h>
|
||||
#include <sbi/sbi_timer.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
|
||||
static unsigned long hart_data_offset;
|
||||
|
||||
/** Per hart specific data to manage state transition **/
|
||||
struct sbi_hsm_data {
|
||||
atomic_t state;
|
||||
};
|
||||
|
||||
int sbi_hsm_hart_state_to_status(int state)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (state) {
|
||||
case SBI_HART_STOPPED:
|
||||
ret = SBI_HSM_HART_STATUS_STOPPED;
|
||||
break;
|
||||
case SBI_HART_STOPPING:
|
||||
ret = SBI_HSM_HART_STATUS_STOP_PENDING;
|
||||
break;
|
||||
case SBI_HART_STARTING:
|
||||
ret = SBI_HSM_HART_STATUS_START_PENDING;
|
||||
break;
|
||||
case SBI_HART_STARTED:
|
||||
ret = SBI_HSM_HART_STATUS_STARTED;
|
||||
break;
|
||||
default:
|
||||
ret = SBI_EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sbi_hsm_hart_get_state(u32 hartid)
|
||||
{
|
||||
struct sbi_hsm_data *hdata;
|
||||
struct sbi_scratch *scratch;
|
||||
|
||||
scratch = sbi_hartid_to_scratch(hartid);
|
||||
if (!scratch)
|
||||
return SBI_HART_UNKNOWN;
|
||||
|
||||
hdata = sbi_scratch_offset_ptr(scratch, hart_data_offset);
|
||||
|
||||
return atomic_read(&hdata->state);
|
||||
}
|
||||
|
||||
bool sbi_hsm_hart_started(u32 hartid)
|
||||
{
|
||||
if (sbi_hsm_hart_get_state(hartid) == SBI_HART_STARTED)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ulong HART mask for given HART base ID
|
||||
* @param hbase the HART base ID
|
||||
* @param out_hmask the output ulong HART mask
|
||||
* @return 0 on success and SBI_Exxx (< 0) on failure
|
||||
* Note: the output HART mask will be set to zero on failure as well.
|
||||
*/
|
||||
int sbi_hsm_hart_started_mask(ulong hbase, ulong *out_hmask)
|
||||
{
|
||||
ulong i;
|
||||
ulong hcount = sbi_scratch_last_hartid() + 1;
|
||||
|
||||
*out_hmask = 0;
|
||||
if (hcount <= hbase)
|
||||
return SBI_EINVAL;
|
||||
if (BITS_PER_LONG < (hcount - hbase))
|
||||
hcount = BITS_PER_LONG;
|
||||
|
||||
for (i = hbase; i < hcount; i++) {
|
||||
if (sbi_hsm_hart_get_state(i) == SBI_HART_STARTED)
|
||||
*out_hmask |= 1UL << (i - hbase);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sbi_hsm_prepare_next_jump(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
u32 oldstate;
|
||||
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
|
||||
hart_data_offset);
|
||||
|
||||
oldstate = atomic_cmpxchg(&hdata->state, SBI_HART_STARTING,
|
||||
SBI_HART_STARTED);
|
||||
if (oldstate != SBI_HART_STARTING)
|
||||
sbi_hart_hang();
|
||||
}
|
||||
|
||||
static void sbi_hsm_hart_wait(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
unsigned long saved_mie;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
|
||||
hart_data_offset);
|
||||
/* Save MIE CSR */
|
||||
saved_mie = csr_read(CSR_MIE);
|
||||
|
||||
/* Set MSIE bit to receive IPI */
|
||||
csr_set(CSR_MIE, MIP_MSIP);
|
||||
|
||||
/* Wait for hart_add call*/
|
||||
while (atomic_read(&hdata->state) != SBI_HART_STARTING) {
|
||||
wfi();
|
||||
};
|
||||
|
||||
/* Restore MIE CSR */
|
||||
csr_write(CSR_MIE, saved_mie);
|
||||
|
||||
/* Clear current HART IPI */
|
||||
sbi_platform_ipi_clear(plat, hartid);
|
||||
}
|
||||
|
||||
int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
|
||||
{
|
||||
u32 i;
|
||||
struct sbi_scratch *rscratch;
|
||||
struct sbi_hsm_data *hdata;
|
||||
|
||||
if (cold_boot) {
|
||||
hart_data_offset = sbi_scratch_alloc_offset(sizeof(*hdata),
|
||||
"HART_DATA");
|
||||
if (!hart_data_offset)
|
||||
return SBI_ENOMEM;
|
||||
|
||||
/* Initialize hart state data for every hart */
|
||||
for (i = 0; i <= sbi_scratch_last_hartid(); i++) {
|
||||
rscratch = sbi_hartid_to_scratch(i);
|
||||
if (!rscratch)
|
||||
continue;
|
||||
|
||||
hdata = sbi_scratch_offset_ptr(rscratch,
|
||||
hart_data_offset);
|
||||
ATOMIC_INIT(&hdata->state,
|
||||
(i == hartid) ? SBI_HART_STARTING : SBI_HART_STOPPED);
|
||||
}
|
||||
} else {
|
||||
sbi_hsm_hart_wait(scratch, hartid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __noreturn sbi_hsm_exit(struct sbi_scratch *scratch)
|
||||
{
|
||||
u32 hstate;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
|
||||
hart_data_offset);
|
||||
void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr;
|
||||
|
||||
hstate = atomic_cmpxchg(&hdata->state, SBI_HART_STOPPING,
|
||||
SBI_HART_STOPPED);
|
||||
if (hstate != SBI_HART_STOPPING)
|
||||
goto fail_exit;
|
||||
|
||||
if (sbi_platform_has_hart_hotplug(plat)) {
|
||||
sbi_platform_hart_stop(plat);
|
||||
/* It should never reach here */
|
||||
goto fail_exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* As platform is lacking support for hotplug, directly jump to warmboot
|
||||
* and wait for interrupts in warmboot. We do it preemptively in order
|
||||
* preserve the hart states and reuse the code path for hotplug.
|
||||
*/
|
||||
jump_warmboot();
|
||||
|
||||
fail_exit:
|
||||
/* It should never reach here */
|
||||
sbi_printf("ERR: Failed stop hart [%u]\n", current_hartid());
|
||||
sbi_hart_hang();
|
||||
}
|
||||
|
||||
int sbi_hsm_hart_start(struct sbi_scratch *scratch, u32 hartid,
|
||||
ulong saddr, ulong priv)
|
||||
{
|
||||
int rc;
|
||||
unsigned long init_count;
|
||||
unsigned int hstate;
|
||||
struct sbi_scratch *rscratch;
|
||||
struct sbi_hsm_data *hdata;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
rscratch = sbi_hartid_to_scratch(hartid);
|
||||
if (!rscratch)
|
||||
return SBI_EINVAL;
|
||||
hdata = sbi_scratch_offset_ptr(rscratch, hart_data_offset);
|
||||
hstate = atomic_cmpxchg(&hdata->state, SBI_HART_STOPPED,
|
||||
SBI_HART_STARTING);
|
||||
if (hstate == SBI_HART_STARTED)
|
||||
return SBI_EALREADY;
|
||||
|
||||
/**
|
||||
* if a hart is already transition to start or stop, another start call
|
||||
* is considered as invalid request.
|
||||
*/
|
||||
if (hstate != SBI_HART_STOPPED)
|
||||
return SBI_EINVAL;
|
||||
|
||||
rc = sbi_hart_pmp_check_addr(scratch, saddr, PMP_X);
|
||||
if (rc)
|
||||
return rc;
|
||||
//TODO: We also need to check saddr for valid physical address as well.
|
||||
|
||||
init_count = sbi_init_count(hartid);
|
||||
rscratch->next_arg1 = priv;
|
||||
rscratch->next_addr = saddr;
|
||||
|
||||
if (sbi_platform_has_hart_hotplug(plat) ||
|
||||
(sbi_platform_has_hart_secondary_boot(plat) && !init_count)) {
|
||||
return sbi_platform_hart_start(plat, hartid,
|
||||
scratch->warmboot_addr);
|
||||
} else {
|
||||
sbi_platform_ipi_send(plat, hartid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow)
|
||||
{
|
||||
int oldstate;
|
||||
u32 hartid = current_hartid();
|
||||
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
|
||||
hart_data_offset);
|
||||
|
||||
if (!sbi_hsm_hart_started(hartid))
|
||||
return SBI_EINVAL;
|
||||
|
||||
oldstate = atomic_cmpxchg(&hdata->state, SBI_HART_STARTED,
|
||||
SBI_HART_STOPPING);
|
||||
if (oldstate != SBI_HART_STARTED) {
|
||||
sbi_printf("%s: ERR: The hart is in invalid state [%u]\n",
|
||||
__func__, oldstate);
|
||||
return SBI_EDENIED;
|
||||
}
|
||||
|
||||
if (exitnow)
|
||||
sbi_exit(scratch);
|
||||
|
||||
return 0;
|
||||
}
|
@@ -9,36 +9,39 @@
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include <sbi/riscv_unpriv.h>
|
||||
#include <sbi/sbi_bits.h>
|
||||
#include <sbi/sbi_bitops.h>
|
||||
#include <sbi/sbi_emulate_csr.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_illegal_insn.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
#include <sbi/sbi_unpriv.h>
|
||||
|
||||
typedef int (*illegal_insn_func)(ulong insn, u32 hartid, ulong mcause,
|
||||
struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch);
|
||||
typedef int (*illegal_insn_func)(ulong insn, struct sbi_trap_regs *regs);
|
||||
|
||||
static int truly_illegal_insn(ulong insn, u32 hartid, ulong mcause,
|
||||
struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch)
|
||||
static int truly_illegal_insn(ulong insn, struct sbi_trap_regs *regs)
|
||||
{
|
||||
return sbi_trap_redirect(regs, scratch, regs->mepc, mcause, insn);
|
||||
struct sbi_trap_info trap;
|
||||
|
||||
trap.epc = regs->mepc;
|
||||
trap.cause = CAUSE_ILLEGAL_INSTRUCTION;
|
||||
trap.tval = insn;
|
||||
trap.tval2 = 0;
|
||||
trap.tinst = 0;
|
||||
|
||||
return sbi_trap_redirect(regs, &trap);
|
||||
}
|
||||
|
||||
static int system_opcode_insn(ulong insn, u32 hartid, ulong mcause,
|
||||
struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch)
|
||||
static int system_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
|
||||
{
|
||||
int do_write, rs1_num = (insn >> 15) & 0x1f;
|
||||
ulong rs1_val = GET_RS1(insn, regs);
|
||||
int csr_num = (u32)insn >> 20;
|
||||
ulong csr_val, new_csr_val;
|
||||
|
||||
if (sbi_emulate_csr_read(csr_num, hartid, regs->mstatus, scratch,
|
||||
&csr_val))
|
||||
return truly_illegal_insn(insn, hartid, mcause, regs, scratch);
|
||||
/* TODO: Ensure that we got CSR read/write instruction */
|
||||
|
||||
if (sbi_emulate_csr_read(csr_num, regs, &csr_val))
|
||||
return truly_illegal_insn(insn, regs);
|
||||
|
||||
do_write = rs1_num;
|
||||
switch (GET_RM(insn)) {
|
||||
@@ -63,12 +66,11 @@ static int system_opcode_insn(ulong insn, u32 hartid, ulong mcause,
|
||||
new_csr_val = csr_val & ~rs1_num;
|
||||
break;
|
||||
default:
|
||||
return truly_illegal_insn(insn, hartid, mcause, regs, scratch);
|
||||
return truly_illegal_insn(insn, regs);
|
||||
};
|
||||
|
||||
if (do_write && sbi_emulate_csr_write(csr_num, hartid, regs->mstatus,
|
||||
scratch, new_csr_val))
|
||||
return truly_illegal_insn(insn, hartid, mcause, regs, scratch);
|
||||
if (do_write && sbi_emulate_csr_write(csr_num, regs, new_csr_val))
|
||||
return truly_illegal_insn(insn, regs);
|
||||
|
||||
SET_RD(insn, regs, csr_val);
|
||||
|
||||
@@ -112,20 +114,21 @@ static illegal_insn_func illegal_insn_table[32] = {
|
||||
truly_illegal_insn /* 31 */
|
||||
};
|
||||
|
||||
int sbi_illegal_insn_handler(u32 hartid, ulong mcause,
|
||||
struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch)
|
||||
int sbi_illegal_insn_handler(ulong insn, struct sbi_trap_regs *regs)
|
||||
{
|
||||
ulong insn = csr_read(mbadaddr);
|
||||
struct sbi_trap_info uptrap;
|
||||
|
||||
if (unlikely((insn & 3) != 3)) {
|
||||
if (insn == 0)
|
||||
insn = get_insn(regs->mepc, NULL);
|
||||
if (insn == 0) {
|
||||
insn = sbi_get_insn(regs->mepc, &uptrap);
|
||||
if (uptrap.cause) {
|
||||
uptrap.epc = regs->mepc;
|
||||
return sbi_trap_redirect(regs, &uptrap);
|
||||
}
|
||||
}
|
||||
if ((insn & 3) != 3)
|
||||
return truly_illegal_insn(insn, hartid, mcause, regs,
|
||||
scratch);
|
||||
return truly_illegal_insn(insn, regs);
|
||||
}
|
||||
|
||||
return illegal_insn_table[(insn & 0x7c) >> 2](insn, hartid, mcause,
|
||||
regs, scratch);
|
||||
return illegal_insn_table[(insn & 0x7c) >> 2](insn, regs);
|
||||
}
|
||||
|
@@ -9,13 +9,18 @@
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/riscv_atomic.h>
|
||||
#include <sbi/riscv_locks.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_hartmask.h>
|
||||
#include <sbi/sbi_hsm.h>
|
||||
#include <sbi/sbi_ipi.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_system.h>
|
||||
#include <sbi/sbi_string.h>
|
||||
#include <sbi/sbi_timer.h>
|
||||
#include <sbi/sbi_tlb.h>
|
||||
#include <sbi/sbi_version.h>
|
||||
|
||||
#define BANNER \
|
||||
@@ -30,39 +35,143 @@
|
||||
|
||||
static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
char str[64];
|
||||
int xlen;
|
||||
char str[128];
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
misa_string(str, sizeof(str));
|
||||
sbi_printf("\nOpenSBI v%d.%d (%s %s)\n", OPENSBI_VERSION_MAJOR,
|
||||
OPENSBI_VERSION_MINOR, __DATE__, __TIME__);
|
||||
#ifdef OPENSBI_VERSION_GIT
|
||||
sbi_printf("\nOpenSBI %s\n", OPENSBI_VERSION_GIT);
|
||||
#else
|
||||
sbi_printf("\nOpenSBI v%d.%d\n", OPENSBI_VERSION_MAJOR,
|
||||
OPENSBI_VERSION_MINOR);
|
||||
#endif
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/* Platform details */
|
||||
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 Max HARTs : %d\n",
|
||||
sbi_printf("Platform Name : %s\n", sbi_platform_name(plat));
|
||||
sbi_platform_get_features_str(plat, str, sizeof(str));
|
||||
sbi_printf("Platform Features : %s\n", str);
|
||||
sbi_printf("Platform HART Count : %u\n",
|
||||
sbi_platform_hart_count(plat));
|
||||
sbi_printf("Current Hart : %u\n", hartid);
|
||||
|
||||
/* Boot HART details */
|
||||
sbi_printf("Boot HART ID : %u\n", hartid);
|
||||
misa_string(xlen, str, sizeof(str));
|
||||
sbi_printf("Boot HART ISA : %s\n", str);
|
||||
sbi_hart_get_features_str(scratch, str, sizeof(str));
|
||||
sbi_printf("BOOT HART Features : %s\n", str);
|
||||
sbi_printf("BOOT HART PMP Count : %d\n", sbi_hart_pmp_count(scratch));
|
||||
|
||||
/* Firmware details */
|
||||
sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start);
|
||||
sbi_printf("Firmware Size : %d KB\n",
|
||||
sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start);
|
||||
sbi_printf("Firmware Size : %d KB\n",
|
||||
(u32)(scratch->fw_size / 1024));
|
||||
|
||||
/* Generic details */
|
||||
sbi_printf("Runtime SBI Version : %d.%d\n",
|
||||
sbi_printf("Runtime SBI Version : %d.%d\n",
|
||||
sbi_ecall_version_major(), sbi_ecall_version_minor());
|
||||
sbi_printf("\n");
|
||||
|
||||
sbi_hart_delegation_dump(scratch);
|
||||
sbi_hart_pmp_dump(scratch);
|
||||
}
|
||||
|
||||
static spinlock_t coldboot_lock = SPIN_LOCK_INITIALIZER;
|
||||
static unsigned long coldboot_done = 0;
|
||||
static struct sbi_hartmask coldboot_wait_hmask = { 0 };
|
||||
|
||||
static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
unsigned long saved_mie, cmip;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
/* Save MIE CSR */
|
||||
saved_mie = csr_read(CSR_MIE);
|
||||
|
||||
/* Set MSIE bit to receive IPI */
|
||||
csr_set(CSR_MIE, MIP_MSIP);
|
||||
|
||||
/* Acquire coldboot lock */
|
||||
spin_lock(&coldboot_lock);
|
||||
|
||||
/* Mark current HART as waiting */
|
||||
sbi_hartmask_set_hart(hartid, &coldboot_wait_hmask);
|
||||
|
||||
/* Wait for coldboot to finish using WFI */
|
||||
while (!coldboot_done) {
|
||||
spin_unlock(&coldboot_lock);
|
||||
do {
|
||||
wfi();
|
||||
cmip = csr_read(CSR_MIP);
|
||||
} while (!(cmip & MIP_MSIP));
|
||||
spin_lock(&coldboot_lock);
|
||||
};
|
||||
|
||||
/* Unmark current HART as waiting */
|
||||
sbi_hartmask_clear_hart(hartid, &coldboot_wait_hmask);
|
||||
|
||||
/* Release coldboot lock */
|
||||
spin_unlock(&coldboot_lock);
|
||||
|
||||
/* Restore MIE CSR */
|
||||
csr_write(CSR_MIE, saved_mie);
|
||||
|
||||
/* Clear current HART IPI */
|
||||
sbi_platform_ipi_clear(plat, hartid);
|
||||
}
|
||||
|
||||
static void wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
/* Acquire coldboot lock */
|
||||
spin_lock(&coldboot_lock);
|
||||
|
||||
/* Mark coldboot done */
|
||||
coldboot_done = 1;
|
||||
|
||||
/* Send an IPI to all HARTs waiting for coldboot */
|
||||
for (int i = 0; i <= sbi_scratch_last_hartid(); i++) {
|
||||
if ((i != hartid) &&
|
||||
sbi_hartmask_test_hart(i, &coldboot_wait_hmask))
|
||||
sbi_platform_ipi_send(plat, i);
|
||||
}
|
||||
|
||||
/* Release coldboot lock */
|
||||
spin_unlock(&coldboot_lock);
|
||||
}
|
||||
|
||||
static unsigned long init_count_offset;
|
||||
|
||||
static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
int rc;
|
||||
unsigned long *init_count;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
rc = sbi_system_early_init(scratch, TRUE);
|
||||
/* Note: This has to be first thing in coldboot init sequence */
|
||||
rc = sbi_scratch_init(scratch);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
init_count_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__,
|
||||
"INIT_COUNT");
|
||||
if (!init_count_offset)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_hsm_init(scratch, hartid, TRUE);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_platform_early_init(plat, TRUE);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
@@ -82,36 +191,51 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_tlb_init(scratch, TRUE);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_timer_init(scratch, TRUE);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_system_final_init(scratch, TRUE);
|
||||
rc = sbi_ecall_init();
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_platform_final_init(plat, TRUE);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
if (!(scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS))
|
||||
sbi_boot_prints(scratch, hartid);
|
||||
|
||||
if (!sbi_platform_has_hart_hotplug(plat))
|
||||
sbi_hart_wake_coldboot_harts(scratch, hartid);
|
||||
sbi_hart_mark_available(hartid);
|
||||
wake_coldboot_harts(scratch, hartid);
|
||||
|
||||
init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
|
||||
(*init_count)++;
|
||||
|
||||
sbi_hsm_prepare_next_jump(scratch, hartid);
|
||||
sbi_hart_switch_mode(hartid, scratch->next_arg1, scratch->next_addr,
|
||||
scratch->next_mode);
|
||||
scratch->next_mode, FALSE);
|
||||
}
|
||||
|
||||
static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
int rc;
|
||||
unsigned long *init_count;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
if (!sbi_platform_has_hart_hotplug(plat))
|
||||
sbi_hart_wait_for_coldboot(scratch, hartid);
|
||||
wait_for_coldboot(scratch, hartid);
|
||||
|
||||
if (sbi_platform_hart_disabled(plat, hartid))
|
||||
if (!init_count_offset)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_system_early_init(scratch, FALSE);
|
||||
rc = sbi_hsm_init(scratch, hartid, FALSE);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_platform_early_init(plat, FALSE);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
@@ -127,22 +251,25 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_tlb_init(scratch, FALSE);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_timer_init(scratch, FALSE);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_system_final_init(scratch, FALSE);
|
||||
rc = sbi_platform_final_init(plat, FALSE);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
sbi_hart_mark_available(hartid);
|
||||
init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
|
||||
(*init_count)++;
|
||||
|
||||
if (sbi_platform_has_hart_hotplug(plat))
|
||||
/* TODO: To be implemented in-future. */
|
||||
sbi_hart_hang();
|
||||
else
|
||||
sbi_hart_switch_mode(hartid, scratch->next_arg1,
|
||||
scratch->next_addr, scratch->next_mode);
|
||||
sbi_hsm_prepare_next_jump(scratch, hartid);
|
||||
sbi_hart_switch_mode(hartid, scratch->next_arg1,
|
||||
scratch->next_addr,
|
||||
scratch->next_mode, FALSE);
|
||||
}
|
||||
|
||||
static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);
|
||||
@@ -162,13 +289,14 @@ static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);
|
||||
void __noreturn sbi_init(struct sbi_scratch *scratch)
|
||||
{
|
||||
bool coldboot = FALSE;
|
||||
u32 hartid = sbi_current_hartid();
|
||||
u32 hartid = current_hartid();
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
if (sbi_platform_hart_disabled(plat, hartid))
|
||||
if ((SBI_HARTMASK_MAX_BITS <= hartid) ||
|
||||
sbi_platform_hart_invalid(plat, hartid))
|
||||
sbi_hart_hang();
|
||||
|
||||
if (atomic_add_return(&coldboot_lottery, 1) == 1)
|
||||
if (atomic_xchg(&coldboot_lottery, 1) == 0)
|
||||
coldboot = TRUE;
|
||||
|
||||
if (coldboot)
|
||||
@@ -176,3 +304,50 @@ void __noreturn sbi_init(struct sbi_scratch *scratch)
|
||||
else
|
||||
init_warmboot(scratch, hartid);
|
||||
}
|
||||
|
||||
unsigned long sbi_init_count(u32 hartid)
|
||||
{
|
||||
struct sbi_scratch *scratch;
|
||||
unsigned long *init_count;
|
||||
|
||||
if (!init_count_offset)
|
||||
return 0;
|
||||
|
||||
scratch = sbi_hartid_to_scratch(hartid);
|
||||
if (!scratch)
|
||||
return 0;
|
||||
|
||||
init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
|
||||
|
||||
return *init_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit OpenSBI library for current HART and stop HART
|
||||
*
|
||||
* The function expects following:
|
||||
* 1. The 'mscratch' CSR is pointing to sbi_scratch of current HART
|
||||
* 2. Stack pointer (SP) is setup for current HART
|
||||
*
|
||||
* @param scratch pointer to sbi_scratch of current HART
|
||||
*/
|
||||
void __noreturn sbi_exit(struct sbi_scratch *scratch)
|
||||
{
|
||||
u32 hartid = current_hartid();
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
if (sbi_platform_hart_invalid(plat, hartid))
|
||||
sbi_hart_hang();
|
||||
|
||||
sbi_platform_early_exit(plat);
|
||||
|
||||
sbi_timer_exit(scratch);
|
||||
|
||||
sbi_ipi_exit(scratch);
|
||||
|
||||
sbi_platform_irqchip_exit(plat);
|
||||
|
||||
sbi_platform_final_exit(plat);
|
||||
|
||||
sbi_hsm_exit(scratch);
|
||||
}
|
||||
|
@@ -9,118 +9,194 @@
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/riscv_barrier.h>
|
||||
#include <sbi/riscv_atomic.h>
|
||||
#include <sbi/riscv_unpriv.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/riscv_barrier.h>
|
||||
#include <sbi/sbi_bitops.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_hsm.h>
|
||||
#include <sbi/sbi_init.h>
|
||||
#include <sbi/sbi_ipi.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_timer.h>
|
||||
#include <sbi/sbi_tlb.h>
|
||||
|
||||
struct sbi_ipi_data {
|
||||
unsigned long ipi_type;
|
||||
};
|
||||
|
||||
static unsigned long ipi_data_off;
|
||||
|
||||
static int sbi_ipi_send(struct sbi_scratch *scratch, u32 hartid, u32 event,
|
||||
void *data)
|
||||
static const struct sbi_ipi_event_ops *ipi_ops_array[SBI_IPI_EVENT_MAX];
|
||||
|
||||
static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid,
|
||||
u32 event, void *data)
|
||||
{
|
||||
int ret;
|
||||
struct sbi_scratch *remote_scratch = NULL;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
struct sbi_ipi_data *ipi_data;
|
||||
const struct sbi_ipi_event_ops *ipi_ops;
|
||||
|
||||
if (sbi_platform_hart_disabled(plat, hartid))
|
||||
return -1;
|
||||
if ((SBI_IPI_EVENT_MAX <= event) ||
|
||||
!ipi_ops_array[event])
|
||||
return SBI_EINVAL;
|
||||
ipi_ops = ipi_ops_array[event];
|
||||
|
||||
remote_scratch = sbi_hartid_to_scratch(remote_hartid);
|
||||
if (!remote_scratch)
|
||||
return SBI_EINVAL;
|
||||
|
||||
ipi_data = sbi_scratch_offset_ptr(remote_scratch, ipi_data_off);
|
||||
|
||||
if (ipi_ops->update) {
|
||||
ret = ipi_ops->update(scratch, remote_scratch,
|
||||
remote_hartid, data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set IPI type on remote hart's scratch area and
|
||||
* trigger the interrupt
|
||||
*/
|
||||
remote_scratch = sbi_hart_id_to_scratch(scratch, hartid);
|
||||
ipi_data = sbi_scratch_offset_ptr(remote_scratch, ipi_data_off);
|
||||
if (event == SBI_IPI_EVENT_SFENCE_VMA ||
|
||||
event == SBI_IPI_EVENT_SFENCE_VMA_ASID) {
|
||||
ret = sbi_tlb_fifo_update(remote_scratch, event, data);
|
||||
if (ret > 0)
|
||||
goto done;
|
||||
else if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
atomic_raw_set_bit(event, &ipi_data->ipi_type);
|
||||
mb();
|
||||
sbi_platform_ipi_send(plat, hartid);
|
||||
if (event != SBI_IPI_EVENT_SOFT)
|
||||
sbi_platform_ipi_sync(plat, hartid);
|
||||
smp_wmb();
|
||||
sbi_platform_ipi_send(plat, remote_hartid);
|
||||
|
||||
if (ipi_ops->sync)
|
||||
ipi_ops->sync(scratch);
|
||||
|
||||
done:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sbi_ipi_send_many(struct sbi_scratch *scratch, struct unpriv_trap *uptrap,
|
||||
ulong *pmask, u32 event, void *data)
|
||||
/**
|
||||
* As this this function only handlers scalar values of hart mask, it must be
|
||||
* set to all online harts if the intention is to send IPIs to all the harts.
|
||||
* If hmask is zero, no IPIs will be sent.
|
||||
*/
|
||||
int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
|
||||
{
|
||||
int rc;
|
||||
ulong i, m;
|
||||
ulong mask = sbi_hart_available_mask();
|
||||
u32 hartid = sbi_current_hartid();
|
||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||
|
||||
if (pmask) {
|
||||
mask &= load_ulong(pmask, scratch, uptrap);
|
||||
if (uptrap->cause)
|
||||
return SBI_ETRAP;
|
||||
if (hbase != -1UL) {
|
||||
rc = sbi_hsm_hart_started_mask(hbase, &m);
|
||||
if (rc)
|
||||
return rc;
|
||||
m &= hmask;
|
||||
|
||||
/* Send IPIs */
|
||||
for (i = hbase; m; i++, m >>= 1) {
|
||||
if (m & 1UL)
|
||||
sbi_ipi_send(scratch, i, event, data);
|
||||
}
|
||||
} else {
|
||||
hbase = 0;
|
||||
while (!sbi_hsm_hart_started_mask(hbase, &m)) {
|
||||
/* Send IPIs */
|
||||
for (i = hbase; m; i++, m >>= 1) {
|
||||
if (m & 1UL)
|
||||
sbi_ipi_send(scratch, i, event, data);
|
||||
}
|
||||
hbase += BITS_PER_LONG;
|
||||
}
|
||||
}
|
||||
|
||||
/* send IPIs to every other hart on the set */
|
||||
for (i = 0, m = mask; m; i++, m >>= 1)
|
||||
if ((m & 1UL) && (i != hartid))
|
||||
sbi_ipi_send(scratch, i, event, data);
|
||||
|
||||
/* If the current hart is on the set, send an IPI
|
||||
* to it as well
|
||||
*/
|
||||
if (mask & (1UL << hartid))
|
||||
sbi_ipi_send(scratch, hartid, event, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sbi_ipi_clear_smode(struct sbi_scratch *scratch)
|
||||
int sbi_ipi_event_create(const struct sbi_ipi_event_ops *ops)
|
||||
{
|
||||
int i, ret = SBI_ENOSPC;
|
||||
|
||||
if (!ops || !ops->process)
|
||||
return SBI_EINVAL;
|
||||
|
||||
for (i = 0; i < SBI_IPI_EVENT_MAX; i++) {
|
||||
if (!ipi_ops_array[i]) {
|
||||
ret = i;
|
||||
ipi_ops_array[i] = ops;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void sbi_ipi_event_destroy(u32 event)
|
||||
{
|
||||
if (SBI_IPI_EVENT_MAX <= event)
|
||||
return;
|
||||
|
||||
ipi_ops_array[event] = NULL;
|
||||
}
|
||||
|
||||
static void sbi_ipi_process_smode(struct sbi_scratch *scratch)
|
||||
{
|
||||
csr_set(CSR_MIP, MIP_SSIP);
|
||||
}
|
||||
|
||||
static struct sbi_ipi_event_ops ipi_smode_ops = {
|
||||
.name = "IPI_SMODE",
|
||||
.process = sbi_ipi_process_smode,
|
||||
};
|
||||
|
||||
static u32 ipi_smode_event = SBI_IPI_EVENT_MAX;
|
||||
|
||||
int sbi_ipi_send_smode(ulong hmask, ulong hbase)
|
||||
{
|
||||
return sbi_ipi_send_many(hmask, hbase, ipi_smode_event, NULL);
|
||||
}
|
||||
|
||||
void sbi_ipi_clear_smode(void)
|
||||
{
|
||||
csr_clear(CSR_MIP, MIP_SSIP);
|
||||
}
|
||||
|
||||
void sbi_ipi_process(struct sbi_scratch *scratch)
|
||||
static void sbi_ipi_process_halt(struct sbi_scratch *scratch)
|
||||
{
|
||||
volatile unsigned long ipi_type;
|
||||
sbi_hsm_hart_stop(scratch, TRUE);
|
||||
}
|
||||
|
||||
static struct sbi_ipi_event_ops ipi_halt_ops = {
|
||||
.name = "IPI_HALT",
|
||||
.process = sbi_ipi_process_halt,
|
||||
};
|
||||
|
||||
static u32 ipi_halt_event = SBI_IPI_EVENT_MAX;
|
||||
|
||||
int sbi_ipi_send_halt(ulong hmask, ulong hbase)
|
||||
{
|
||||
return sbi_ipi_send_many(hmask, hbase, ipi_halt_event, NULL);
|
||||
}
|
||||
|
||||
void sbi_ipi_process(void)
|
||||
{
|
||||
unsigned long ipi_type;
|
||||
unsigned int ipi_event;
|
||||
const struct sbi_ipi_event_ops *ipi_ops;
|
||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
struct sbi_ipi_data *ipi_data =
|
||||
sbi_scratch_offset_ptr(scratch, ipi_data_off);
|
||||
|
||||
u32 hartid = sbi_current_hartid();
|
||||
u32 hartid = current_hartid();
|
||||
sbi_platform_ipi_clear(plat, hartid);
|
||||
|
||||
do {
|
||||
ipi_type = ipi_data->ipi_type;
|
||||
rmb();
|
||||
ipi_event = __ffs(ipi_type);
|
||||
switch (ipi_event) {
|
||||
case SBI_IPI_EVENT_SOFT:
|
||||
csr_set(CSR_MIP, MIP_SSIP);
|
||||
break;
|
||||
case SBI_IPI_EVENT_FENCE_I:
|
||||
__asm__ __volatile("fence.i");
|
||||
break;
|
||||
case SBI_IPI_EVENT_SFENCE_VMA:
|
||||
case SBI_IPI_EVENT_SFENCE_VMA_ASID:
|
||||
sbi_tlb_fifo_process(scratch, ipi_event);
|
||||
break;
|
||||
case SBI_IPI_EVENT_HALT:
|
||||
sbi_hart_hang();
|
||||
break;
|
||||
};
|
||||
ipi_type = atomic_raw_clear_bit(ipi_event, &ipi_data->ipi_type);
|
||||
} while (ipi_type > 0);
|
||||
ipi_type = atomic_raw_xchg_ulong(&ipi_data->ipi_type, 0);
|
||||
ipi_event = 0;
|
||||
while (ipi_type) {
|
||||
if (!(ipi_type & 1UL))
|
||||
goto skip;
|
||||
|
||||
ipi_ops = ipi_ops_array[ipi_event];
|
||||
if (ipi_ops && ipi_ops->process)
|
||||
ipi_ops->process(scratch);
|
||||
|
||||
skip:
|
||||
ipi_type = ipi_type >> 1;
|
||||
ipi_event++;
|
||||
};
|
||||
}
|
||||
|
||||
int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||
@@ -133,20 +209,44 @@ int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||
"IPI_DATA");
|
||||
if (!ipi_data_off)
|
||||
return SBI_ENOMEM;
|
||||
ret = sbi_ipi_event_create(&ipi_smode_ops);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ipi_smode_event = ret;
|
||||
ret = sbi_ipi_event_create(&ipi_halt_ops);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ipi_halt_event = ret;
|
||||
} else {
|
||||
if (!ipi_data_off)
|
||||
return SBI_ENOMEM;
|
||||
if (SBI_IPI_EVENT_MAX <= ipi_smode_event ||
|
||||
SBI_IPI_EVENT_MAX <= ipi_halt_event)
|
||||
return SBI_ENOSPC;
|
||||
}
|
||||
|
||||
ipi_data = sbi_scratch_offset_ptr(scratch, ipi_data_off);
|
||||
ipi_data->ipi_type = 0x00;
|
||||
|
||||
ret = sbi_tlb_fifo_init(scratch, cold_boot);
|
||||
/* Platform init */
|
||||
ret = sbi_platform_ipi_init(sbi_platform_ptr(scratch), cold_boot);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enable software interrupts */
|
||||
csr_set(CSR_MIE, MIP_MSIP);
|
||||
|
||||
return sbi_platform_ipi_init(sbi_platform_ptr(scratch), cold_boot);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sbi_ipi_exit(struct sbi_scratch *scratch)
|
||||
{
|
||||
/* Disable software interrupts */
|
||||
csr_clear(CSR_MIE, MIP_MSIP);
|
||||
|
||||
/* Process pending IPIs */
|
||||
sbi_ipi_process();
|
||||
|
||||
/* Platform exit */
|
||||
sbi_platform_ipi_exit(sbi_platform_ptr(scratch));
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user