mirror of
https://github.com/riscv-software-src/opensbi.git
synced 2025-08-24 15:31:22 +01:00
Compare commits
291 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
48f91ee9c9 | ||
![]() |
d30bde36d5 | ||
![]() |
2082153fc9 | ||
![]() |
f270359810 | ||
![]() |
d249d6544c | ||
![]() |
69d7e53613 | ||
![]() |
460041c816 | ||
![]() |
66fbcc03df | ||
![]() |
2428987cc0 | ||
![]() |
14faee6916 | ||
![]() |
7e77706966 | ||
![]() |
7a22c780df | ||
![]() |
22d556d268 | ||
![]() |
52af6e4b52 | ||
![]() |
d335a178d8 | ||
![]() |
f3744967c6 | ||
![]() |
13a1158d24 | ||
![]() |
6ca6bcafb7 | ||
![]() |
2c964a2e15 | ||
![]() |
1d462e0397 | ||
![]() |
94eba23376 | ||
![]() |
31fe5a7a3d | ||
![]() |
b8845e4204 | ||
![]() |
15906a3984 | ||
![]() |
b28f07005c | ||
![]() |
b628cfd6a0 | ||
![]() |
1e147324f0 | ||
![]() |
0c304b6619 | ||
![]() |
2363f950bc | ||
![]() |
730f01bb41 | ||
![]() |
9134c3643e | ||
![]() |
867c65360d | ||
![]() |
7084ad9f42 | ||
![]() |
a74daf2cb9 | ||
![]() |
be245acfff | ||
![]() |
57f094e67e | ||
![]() |
2fe2f55d50 | ||
![]() |
0979ffda12 | ||
![]() |
013ba4ef3d | ||
![]() |
c891acca17 | ||
![]() |
723aa88ff4 | ||
![]() |
309e8bdf85 | ||
![]() |
78c2b19218 | ||
![]() |
422eda499c | ||
![]() |
67cbbcb100 | ||
![]() |
c38973e087 | ||
![]() |
9283d503bd | ||
![]() |
516161c46f | ||
![]() |
754d51192b | ||
![]() |
fa59dd317a | ||
![]() |
9d0ab35ab4 | ||
![]() |
6355155f51 | ||
![]() |
12e7af9ab7 | ||
![]() |
72154f4708 | ||
![]() |
51113fe2a5 | ||
![]() |
12753d2256 | ||
![]() |
3477f08b08 | ||
![]() |
395ff7eede | ||
![]() |
0274a96004 | ||
![]() |
bd355213bf | ||
![]() |
1718b1642e | ||
![]() |
c262306533 | ||
![]() |
bd316e2c9b | ||
![]() |
b1d3e91e9a | ||
![]() |
ee274377b2 | ||
![]() |
33eac764f2 | ||
![]() |
7aa6c9aa96 | ||
![]() |
b35f7826b0 | ||
![]() |
f3a0eb8583 | ||
![]() |
7a3a0cce4d | ||
![]() |
e0d1b9db8a | ||
![]() |
47a47654e8 | ||
![]() |
d244f3dbd6 | ||
![]() |
e928472e67 | ||
![]() |
ce03c88ee1 | ||
![]() |
217d5e4880 | ||
![]() |
74db0acbe5 | ||
![]() |
989039117f | ||
![]() |
81eb7088b6 | ||
![]() |
2c74dc3c47 | ||
![]() |
a4555e5698 | ||
![]() |
8a1475b5a1 | ||
![]() |
f3a8f603a7 | ||
![]() |
7210e90785 | ||
![]() |
e3d6919d10 | ||
![]() |
4c3df2ab96 | ||
![]() |
c14f1fe0df | ||
![]() |
36b8effe4a | ||
![]() |
e931f387b2 | ||
![]() |
17729d44da | ||
![]() |
2942777425 | ||
![]() |
09ad811ec4 | ||
![]() |
a3d328ae33 | ||
![]() |
397afe5ba1 | ||
![]() |
7f1be8a624 | ||
![]() |
a76ac4449b | ||
![]() |
b88b3661d4 | ||
![]() |
dcb756b01a | ||
![]() |
abfce9b25c | ||
![]() |
dafaa0f54b | ||
![]() |
14c7f71c0d | ||
![]() |
0e12aa8dee | ||
![]() |
ec1b8bb763 | ||
![]() |
764a17d852 | ||
![]() |
37f9b0f2f2 | ||
![]() |
ae72ec0915 | ||
![]() |
13d40f21d5 | ||
![]() |
e7cc7a3ab2 | ||
![]() |
49966db306 | ||
![]() |
fd9116bd46 | ||
![]() |
41ae63cd0a | ||
![]() |
9c9b4ad24b | ||
![]() |
0829f2bc28 | ||
![]() |
d3a96cc469 | ||
![]() |
fde28fadc2 | ||
![]() |
3e8b31aca9 | ||
![]() |
17e23b678d | ||
![]() |
197e08941b | ||
![]() |
b7f2cd268b | ||
![]() |
a731c7e369 | ||
![]() |
03d6bb51ba | ||
![]() |
56fc5f7618 | ||
![]() |
bd5d2089b8 | ||
![]() |
5a049fe1d6 | ||
![]() |
4519e29c51 | ||
![]() |
11c345f14a | ||
![]() |
99017946f3 | ||
![]() |
cdcf907b19 | ||
![]() |
eb90e0a16c | ||
![]() |
79f9b4220f | ||
![]() |
360ab88569 | ||
![]() |
1da3d80b5b | ||
![]() |
434198e3be | ||
![]() |
de446ccf18 | ||
![]() |
b32fac4b65 | ||
![]() |
a03ea2e2b1 | ||
![]() |
f30b18944e | ||
![]() |
66c4fca532 | ||
![]() |
d9ba6536d3 | ||
![]() |
54d7def6c2 | ||
![]() |
b2dbbc0577 | ||
![]() |
fe92347b9f | ||
![]() |
ee7c2b27ea | ||
![]() |
c9ef2bc7e4 | ||
![]() |
6139ab272b | ||
![]() |
e822b7504d | ||
![]() |
f90c4c2e02 | ||
![]() |
26998f3d11 | ||
![]() |
d4177e7217 | ||
![]() |
552f53f360 | ||
![]() |
117fb6dcb1 | ||
![]() |
632e27bb91 | ||
![]() |
e9a27ab8ea | ||
![]() |
a84a1ddbba | ||
![]() |
043d088e39 | ||
![]() |
dc39c7b630 | ||
![]() |
559a8f1d3b | ||
![]() |
068ca086af | ||
![]() |
a3689db92a | ||
![]() |
6d1642f856 | ||
![]() |
1db843622a | ||
![]() |
bf3ef53bb7 | ||
![]() |
0d56293817 | ||
![]() |
49e422c5ad | ||
![]() |
c5d0645052 | ||
![]() |
f41196a9d2 | ||
![]() |
e7e4bcd5b9 | ||
![]() |
fc37c9712d | ||
![]() |
8b56980347 | ||
![]() |
4dc0001b09 | ||
![]() |
7495bce6f9 | ||
![]() |
b1df1acd20 | ||
![]() |
27a16b1545 | ||
![]() |
70ffc3e2e6 | ||
![]() |
4d8e2f135d | ||
![]() |
d0e406fa44 | ||
![]() |
d4a94ea471 | ||
![]() |
e71a7c10a9 | ||
![]() |
3d8a952737 | ||
![]() |
4ef2f5d3e6 | ||
![]() |
4edc822407 | ||
![]() |
ca3f35821b | ||
![]() |
9190ad12f7 | ||
![]() |
bfc85c70e7 | ||
![]() |
ddad02d625 | ||
![]() |
0f20e8adcf | ||
![]() |
22d8ee9758 | ||
![]() |
ff5bd949d5 | ||
![]() |
50d4fde1c5 | ||
![]() |
b9cf617a9f | ||
![]() |
74756891cc | ||
![]() |
807d71c4ff | ||
![]() |
4b05df6700 | ||
![]() |
6290a22e34 | ||
![]() |
ca864a978d | ||
![]() |
638c948ab9 | ||
![]() |
7c867fd19f | ||
![]() |
8df1f9a0d3 | ||
![]() |
5487cf095d | ||
![]() |
ec5274b04c | ||
![]() |
234ed8e427 | ||
![]() |
da5293f742 | ||
![]() |
1bbf36183e | ||
![]() |
386eba21bf | ||
![]() |
e884416650 | ||
![]() |
db56341dfa | ||
![]() |
0d49c3bc18 | ||
![]() |
12394a269b | ||
![]() |
b7df5e4392 | ||
![]() |
80bc5065bb | ||
![]() |
7dcb1e1753 | ||
![]() |
a029bd90c6 | ||
![]() |
6fc1986f50 | ||
![]() |
7baccfca79 | ||
![]() |
2179777364 | ||
![]() |
e7da0b4204 | ||
![]() |
4fffb53269 | ||
![]() |
ba741ea0ad | ||
![]() |
c0d2baa8c0 | ||
![]() |
9b65dcaedd | ||
![]() |
555e73778a | ||
![]() |
62ea4f4e2a | ||
![]() |
c1f6d89678 | ||
![]() |
c709d40a67 | ||
![]() |
4e370224df | ||
![]() |
3d921fad0d | ||
![]() |
8d2edc4fc9 | ||
![]() |
2677324f90 | ||
![]() |
548d03e577 | ||
![]() |
5c429ae213 | ||
![]() |
da074796df | ||
![]() |
c4acc60a46 | ||
![]() |
54a7734d86 | ||
![]() |
781cafdbee | ||
![]() |
48616b3de2 | ||
![]() |
914f81fbee | ||
![]() |
a809f406b9 | ||
![]() |
bf21632860 | ||
![]() |
74c0ea1e83 | ||
![]() |
fdf5d5c322 | ||
![]() |
c347408a39 | ||
![]() |
c10c30b485 | ||
![]() |
e856462ac2 | ||
![]() |
5fd99dbdaa | ||
![]() |
5edbb7cda1 | ||
![]() |
3e200370ee | ||
![]() |
530e95bd63 | ||
![]() |
3a30d2c34d | ||
![]() |
e73b92d862 | ||
![]() |
b1678af210 | ||
![]() |
8b650050ec | ||
![]() |
f81d6f6f43 | ||
![]() |
a126886bfa | ||
![]() |
a12d46a5e7 | ||
![]() |
dbeeacb878 | ||
![]() |
a0f2d4a10c | ||
![]() |
e9a4bfb7b5 | ||
![]() |
9c07c513aa | ||
![]() |
6ca096977d | ||
![]() |
af4b50f896 | ||
![]() |
a04c46506a | ||
![]() |
79bf80b44e | ||
![]() |
7701ea13be | ||
![]() |
aaeca7eb4e | ||
![]() |
172fa1601c | ||
![]() |
9f935a4a43 | ||
![]() |
7ccf6bf54c | ||
![]() |
6734304f8c | ||
![]() |
c1c7c3ee9e | ||
![]() |
bef63d6848 | ||
![]() |
dcb10c0056 | ||
![]() |
ebc8ebc0f8 | ||
![]() |
162d453b49 | ||
![]() |
2c341f7844 | ||
![]() |
74d1db7062 | ||
![]() |
7b0b289887 | ||
![]() |
4f3bad6e43 | ||
![]() |
e435ba0524 | ||
![]() |
d7f87d99a3 | ||
![]() |
9d56961b23 | ||
![]() |
4b18a2acc2 | ||
![]() |
937caee083 | ||
![]() |
2cfd2fc904 | ||
![]() |
2845d2d2cf | ||
![]() |
8e47649eff | ||
![]() |
ec1abf6657 | ||
![]() |
a5f9104330 | ||
![]() |
7d61a68775 | ||
![]() |
ec3e5b14d5 | ||
![]() |
78afe11ba2 | ||
![]() |
35bc810252 |
171
Makefile
171
Makefile
@@ -76,24 +76,54 @@ OPENSBI_VERSION_MINOR=`grep "define OPENSBI_VERSION_MINOR" $(include_dir)/sbi/sb
|
||||
OPENSBI_VERSION_GIT=$(shell if [ -d $(src_dir)/.git ]; then git describe 2> /dev/null; fi)
|
||||
|
||||
# Setup compilation commands
|
||||
ifneq ($(LLVM),)
|
||||
CC = clang
|
||||
AR = llvm-ar
|
||||
LD = ld.lld
|
||||
OBJCOPY = llvm-objcopy
|
||||
else
|
||||
ifdef CROSS_COMPILE
|
||||
CC = $(CROSS_COMPILE)gcc
|
||||
CPP = $(CROSS_COMPILE)cpp
|
||||
AR = $(CROSS_COMPILE)ar
|
||||
LD = $(CROSS_COMPILE)ld
|
||||
OBJCOPY = $(CROSS_COMPILE)objcopy
|
||||
else
|
||||
CC ?= gcc
|
||||
CPP ?= cpp
|
||||
AR ?= ar
|
||||
LD ?= ld
|
||||
OBJCOPY ?= objcopy
|
||||
endif
|
||||
endif
|
||||
CPP = $(CC) -E
|
||||
AS = $(CC)
|
||||
DTC = dtc
|
||||
|
||||
# Guess the compillers xlen
|
||||
OPENSBI_CC_XLEN := $(shell TMP=`$(CC) -dumpmachine | sed 's/riscv\([0-9][0-9]\).*/\1/'`; echo $${TMP})
|
||||
ifneq ($(shell $(CC) --version 2>&1 | head -n 1 | grep clang),)
|
||||
CC_IS_CLANG = y
|
||||
else
|
||||
CC_IS_CLANG = n
|
||||
endif
|
||||
|
||||
ifneq ($(shell $(LD) --version 2>&1 | head -n 1 | grep LLD),)
|
||||
LD_IS_LLD = y
|
||||
else
|
||||
LD_IS_LLD = n
|
||||
endif
|
||||
|
||||
ifeq ($(CC_IS_CLANG),y)
|
||||
ifneq ($(CROSS_COMPILE),)
|
||||
CLANG_TARGET = --target=$(notdir $(CROSS_COMPILE:%-=%))
|
||||
endif
|
||||
endif
|
||||
|
||||
# Guess the compiler's XLEN
|
||||
OPENSBI_CC_XLEN := $(shell TMP=`$(CC) $(CLANG_TARGET) -dumpmachine | sed 's/riscv\([0-9][0-9]\).*/\1/'`; echo $${TMP})
|
||||
|
||||
# Guess the compiler's ABI and ISA
|
||||
ifneq ($(CC_IS_CLANG),y)
|
||||
OPENSBI_CC_ABI := $(shell TMP=`$(CC) -v 2>&1 | sed -n 's/.*\(with\-abi=\([a-zA-Z0-9]*\)\).*/\2/p'`; echo $${TMP})
|
||||
OPENSBI_CC_ISA := $(shell TMP=`$(CC) -v 2>&1 | sed -n 's/.*\(with\-arch=\([a-zA-Z0-9]*\)\).*/\2/p'`; echo $${TMP})
|
||||
endif
|
||||
|
||||
# Setup platform XLEN
|
||||
ifndef PLATFORM_RISCV_XLEN
|
||||
@@ -104,6 +134,44 @@ ifndef PLATFORM_RISCV_XLEN
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CC_IS_CLANG),y)
|
||||
ifeq ($(CROSS_COMPILE),)
|
||||
CLANG_TARGET = --target=riscv$(PLATFORM_RISCV_XLEN)-unknown-elf
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(LD_IS_LLD),y)
|
||||
RELAX_FLAG = -mno-relax
|
||||
USE_LD_FLAG = -fuse-ld=lld
|
||||
else
|
||||
USE_LD_FLAG = -fuse-ld=bfd
|
||||
endif
|
||||
|
||||
# Check whether the linker supports creating PIEs
|
||||
OPENSBI_LD_PIE := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) $(USE_LD_FLAG) -fPIE -nostdlib -Wl,-pie -x c /dev/null -o /dev/null >/dev/null 2>&1 && echo y || echo n)
|
||||
|
||||
# Check whether the compiler supports -m(no-)save-restore
|
||||
CC_SUPPORT_SAVE_RESTORE := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -mno-save-restore -x c /dev/null -o /dev/null 2>&1 | grep "\-save\-restore" >/dev/null && echo n || echo y)
|
||||
|
||||
# Build Info:
|
||||
# OPENSBI_BUILD_TIME_STAMP -- the compilation time stamp
|
||||
# OPENSBI_BUILD_COMPILER_VERSION -- the compiler version info
|
||||
BUILD_INFO ?= n
|
||||
ifeq ($(BUILD_INFO),y)
|
||||
OPENSBI_BUILD_DATE_FMT = +%Y-%m-%d %H:%M:%S %z
|
||||
ifdef SOURCE_DATE_EPOCH
|
||||
OPENSBI_BUILD_TIME_STAMP ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" \
|
||||
"$(OPENSBI_BUILD_DATE_FMT)" 2>/dev/null || \
|
||||
date -u -r "$(SOURCE_DATE_EPOCH)" \
|
||||
"$(OPENSBI_BUILD_DATE_FMT)" 2>/dev/null || \
|
||||
date -u "$(OPENSBI_BUILD_DATE_FMT)")
|
||||
else
|
||||
OPENSBI_BUILD_TIME_STAMP ?= $(shell date "$(OPENSBI_BUILD_DATE_FMT)")
|
||||
endif
|
||||
OPENSBI_BUILD_COMPILER_VERSION=$(shell $(CC) -v 2>&1 | grep ' version ' | \
|
||||
sed 's/[[:space:]]*$$//')
|
||||
endif
|
||||
|
||||
# Setup list of objects.mk files
|
||||
ifdef PLATFORM
|
||||
platform-object-mks=$(shell if [ -d $(platform_src_dir)/ ]; then find $(platform_src_dir) -iname "objects.mk" | sort -r; fi)
|
||||
@@ -143,14 +211,22 @@ deps-y+=$(firmware-objs-path-y:.o=.dep)
|
||||
|
||||
# Setup platform ABI, ISA and Code Model
|
||||
ifndef PLATFORM_RISCV_ABI
|
||||
ifeq ($(PLATFORM_RISCV_XLEN), 32)
|
||||
PLATFORM_RISCV_ABI = ilp$(PLATFORM_RISCV_XLEN)
|
||||
ifneq ($(PLATFORM_RISCV_TOOLCHAIN_DEFAULT), 1)
|
||||
ifeq ($(PLATFORM_RISCV_XLEN), 32)
|
||||
PLATFORM_RISCV_ABI = ilp$(PLATFORM_RISCV_XLEN)
|
||||
else
|
||||
PLATFORM_RISCV_ABI = lp$(PLATFORM_RISCV_XLEN)
|
||||
endif
|
||||
else
|
||||
PLATFORM_RISCV_ABI = lp$(PLATFORM_RISCV_XLEN)
|
||||
PLATFORM_RISCV_ABI = $(OPENSBI_CC_ABI)
|
||||
endif
|
||||
endif
|
||||
ifndef PLATFORM_RISCV_ISA
|
||||
PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc
|
||||
ifneq ($(PLATFORM_RISCV_TOOLCHAIN_DEFAULT), 1)
|
||||
PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc
|
||||
else
|
||||
PLATFORM_RISCV_ISA = $(OPENSBI_CC_ISA)
|
||||
endif
|
||||
endif
|
||||
ifndef PLATFORM_RISCV_CODE_MODEL
|
||||
PLATFORM_RISCV_CODE_MODEL = medany
|
||||
@@ -184,46 +260,72 @@ else
|
||||
endif
|
||||
|
||||
# Setup compilation commands flags
|
||||
GENFLAGS = -I$(platform_src_dir)/include
|
||||
ifeq ($(CC_IS_CLANG),y)
|
||||
GENFLAGS += $(CLANG_TARGET)
|
||||
GENFLAGS += -Wno-unused-command-line-argument
|
||||
endif
|
||||
GENFLAGS += -I$(platform_src_dir)/include
|
||||
GENFLAGS += -I$(include_dir)
|
||||
ifneq ($(OPENSBI_VERSION_GIT),)
|
||||
GENFLAGS += -DOPENSBI_VERSION_GIT="\"$(OPENSBI_VERSION_GIT)\""
|
||||
endif
|
||||
ifeq ($(BUILD_INFO),y)
|
||||
GENFLAGS += -DOPENSBI_BUILD_TIME_STAMP="\"$(OPENSBI_BUILD_TIME_STAMP)\""
|
||||
GENFLAGS += -DOPENSBI_BUILD_COMPILER_VERSION="\"$(OPENSBI_BUILD_COMPILER_VERSION)\""
|
||||
endif
|
||||
GENFLAGS += $(libsbiutils-genflags-y)
|
||||
GENFLAGS += $(platform-genflags-y)
|
||||
GENFLAGS += $(firmware-genflags-y)
|
||||
|
||||
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 = -g -Wall -Werror -ffreestanding -nostdlib -fno-stack-protector -fno-strict-aliasing -O2
|
||||
CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls -mstrict-align
|
||||
# enable -m(no-)save-restore option by CC_SUPPORT_SAVE_RESTORE
|
||||
ifeq ($(CC_SUPPORT_SAVE_RESTORE),y)
|
||||
CFLAGS += -mno-save-restore
|
||||
endif
|
||||
CFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
|
||||
CFLAGS += -mcmodel=$(PLATFORM_RISCV_CODE_MODEL)
|
||||
CFLAGS += $(RELAX_FLAG)
|
||||
CFLAGS += $(GENFLAGS)
|
||||
CFLAGS += $(platform-cflags-y)
|
||||
CFLAGS += $(firmware-cflags-y)
|
||||
CFLAGS += -fno-pie -no-pie
|
||||
CFLAGS += $(firmware-cflags-y)
|
||||
|
||||
CPPFLAGS += $(GENFLAGS)
|
||||
CPPFLAGS += $(platform-cppflags-y)
|
||||
CPPFLAGS += $(firmware-cppflags-y)
|
||||
|
||||
ASFLAGS = -g -Wall -nostdlib -D__ASSEMBLY__
|
||||
ASFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
|
||||
ASFLAGS += -mno-save-restore -mstrict-align
|
||||
ASFLAGS = -g -Wall -nostdlib
|
||||
ASFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls -mstrict-align
|
||||
# enable -m(no-)save-restore option by CC_SUPPORT_SAVE_RESTORE
|
||||
ifeq ($(CC_SUPPORT_SAVE_RESTORE),y)
|
||||
ASFLAGS += -mno-save-restore
|
||||
endif
|
||||
ASFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
|
||||
ASFLAGS += -mcmodel=$(PLATFORM_RISCV_CODE_MODEL)
|
||||
ASFLAGS += $(RELAX_FLAG)
|
||||
ifneq ($(CC_IS_CLANG),y)
|
||||
ifneq ($(RELAX_FLAG),)
|
||||
ASFLAGS += -Wa,$(RELAX_FLAG)
|
||||
endif
|
||||
endif
|
||||
ASFLAGS += $(GENFLAGS)
|
||||
ASFLAGS += $(platform-asflags-y)
|
||||
ASFLAGS += $(firmware-asflags-y)
|
||||
|
||||
ARFLAGS = rcs
|
||||
|
||||
ELFFLAGS += -Wl,--build-id=none -N -static-libgcc -lgcc
|
||||
ELFFLAGS += $(USE_LD_FLAG)
|
||||
ELFFLAGS += -Wl,--build-id=none -Wl,-N
|
||||
ELFFLAGS += $(platform-ldflags-y)
|
||||
ELFFLAGS += $(firmware-ldflags-y)
|
||||
|
||||
MERGEFLAGS += -r
|
||||
ifeq ($(LD_IS_LLD),y)
|
||||
MERGEFLAGS += -b elf
|
||||
else
|
||||
MERGEFLAGS += -b elf$(PLATFORM_RISCV_XLEN)-littleriscv
|
||||
endif
|
||||
MERGEFLAGS += -m elf$(PLATFORM_RISCV_XLEN)lriscv
|
||||
|
||||
DTSCPPFLAGS = $(CPPFLAGS) -nostdinc -nostdlib -fno-builtin -D__DTS__ -x assembler-with-cpp
|
||||
@@ -291,7 +393,10 @@ compile_dts = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
||||
$(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)
|
||||
$(if $($(2)-varalign-$(3)),$(eval D2C_ALIGN_BYTES := $($(2)-varalign-$(3))),$(eval D2C_ALIGN_BYTES := $(4))) \
|
||||
$(if $($(2)-varprefix-$(3)),$(eval D2C_NAME_PREFIX := $($(2)-varprefix-$(3))),$(eval D2C_NAME_PREFIX := $(5))) \
|
||||
$(if $($(2)-padding-$(3)),$(eval D2C_PADDING_BYTES := $($(2)-padding-$(3))),$(eval D2C_PADDING_BYTES := 0)) \
|
||||
$(src_dir)/scripts/d2c.sh -i $(6) -a $(D2C_ALIGN_BYTES) -p $(D2C_NAME_PREFIX) -t $(D2C_PADDING_BYTES) > $(1)
|
||||
compile_gen_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
||||
echo " GEN-DEP $(subst $(build_dir)/,,$(1))"; \
|
||||
echo "$(1:.dep=$(2)): $(3)" >> $(1)
|
||||
@@ -310,15 +415,6 @@ all: $(targets-y)
|
||||
# Preserve all intermediate files
|
||||
.SECONDARY:
|
||||
|
||||
$(build_dir)/%.bin: $(build_dir)/%.elf
|
||||
$(call compile_objcopy,$@,$<)
|
||||
|
||||
$(build_dir)/%.elf: $(build_dir)/%.o $(build_dir)/%.elf.ld $(platform_build_dir)/lib/libplatsbi.a
|
||||
$(call compile_elf,$@,$@.ld,$< $(platform_build_dir)/lib/libplatsbi.a)
|
||||
|
||||
$(platform_build_dir)/%.ld: $(src_dir)/%.ldS
|
||||
$(call compile_cpp,$@,$<)
|
||||
|
||||
$(build_dir)/lib/libsbi.a: $(libsbi-objs-path-y)
|
||||
$(call compile_ar,$@,$^)
|
||||
|
||||
@@ -334,12 +430,26 @@ $(build_dir)/%.dep: $(src_dir)/%.c
|
||||
$(build_dir)/%.o: $(src_dir)/%.c
|
||||
$(call compile_cc,$@,$<)
|
||||
|
||||
ifeq ($(BUILD_INFO),y)
|
||||
$(build_dir)/lib/sbi/sbi_init.o: $(libsbi_dir)/sbi_init.c FORCE
|
||||
$(call compile_cc,$@,$<)
|
||||
endif
|
||||
|
||||
$(build_dir)/%.dep: $(src_dir)/%.S
|
||||
$(call compile_as_dep,$@,$<)
|
||||
|
||||
$(build_dir)/%.o: $(src_dir)/%.S
|
||||
$(call compile_as,$@,$<)
|
||||
|
||||
$(platform_build_dir)/%.bin: $(platform_build_dir)/%.elf
|
||||
$(call compile_objcopy,$@,$<)
|
||||
|
||||
$(platform_build_dir)/%.elf: $(platform_build_dir)/%.o $(platform_build_dir)/%.elf.ld $(platform_build_dir)/lib/libplatsbi.a
|
||||
$(call compile_elf,$@,$@.ld,$< $(platform_build_dir)/lib/libplatsbi.a)
|
||||
|
||||
$(platform_build_dir)/%.ld: $(src_dir)/%.ldS
|
||||
$(call compile_cpp,$@,$<)
|
||||
|
||||
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.c
|
||||
$(call compile_cc_dep,$@,$<)
|
||||
|
||||
@@ -361,7 +471,7 @@ $(platform_build_dir)/%.dep: $(platform_src_dir)/%.dts
|
||||
$(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,$<)
|
||||
$(call compile_d2c,$@,platform,$(subst .dtb,.o,$(subst /,-,$(subst $(platform_build_dir)/,,$<))),16,dt,$<)
|
||||
|
||||
$(platform_build_dir)/%.dtb: $(platform_src_dir)/%.dts
|
||||
$(call compile_dts,$@,$<)
|
||||
@@ -461,6 +571,8 @@ clean:
|
||||
$(CMD_PREFIX)find $(build_dir) -type f -name "*.elf" -exec rm -rf {} +
|
||||
$(if $(V), @echo " RM $(build_dir)/*.bin")
|
||||
$(CMD_PREFIX)find $(build_dir) -type f -name "*.bin" -exec rm -rf {} +
|
||||
$(if $(V), @echo " RM $(build_dir)/*.dtb")
|
||||
$(CMD_PREFIX)find $(build_dir) -type f -name "*.dtb" -exec rm -rf {} +
|
||||
|
||||
# Rule for "make distclean"
|
||||
.PHONY: distclean
|
||||
@@ -476,3 +588,6 @@ 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
|
||||
|
||||
.PHONY: FORCE
|
||||
FORCE:
|
||||
|
97
README.md
97
README.md
@@ -45,7 +45,7 @@ between:
|
||||
executing in VS-mode.
|
||||
|
||||
The *RISC-V SBI specification* is maintained as an independent project by the
|
||||
RISC-V Foundation on [Github] (https://github.com/riscv/riscv-sbi-doc).
|
||||
RISC-V Foundation on [Github].
|
||||
|
||||
The goal of the OpenSBI project is to provide an open-source reference
|
||||
implementation of the RISC-V SBI specifications for platform-specific firmwares
|
||||
@@ -69,7 +69,7 @@ platform-dependent hardware manipulation functions. For all supported platforms,
|
||||
OpenSBI also provides several runtime firmware examples built using the platform
|
||||
*libplatsbi.a*. These example firmwares can be used to replace the legacy
|
||||
*riscv-pk* bootloader (aka BBL) and enable the use of well-known bootloaders
|
||||
such as [U-Boot] (https://git.denx.de/u-boot.git).
|
||||
such as [U-Boot].
|
||||
|
||||
Supported SBI version
|
||||
---------------------
|
||||
@@ -96,9 +96,21 @@ Required Toolchain
|
||||
------------------
|
||||
|
||||
OpenSBI can be compiled natively or cross-compiled on a x86 host. For
|
||||
cross-compilation, you can build your own toolchain or just download
|
||||
a prebuilt one from the
|
||||
[Bootlin toolchain repository] (https://toolchains.bootlin.com/).
|
||||
cross-compilation, you can build your own toolchain, download a prebuilt one
|
||||
from the [Bootlin toolchain repository] or install a distribution-provided
|
||||
toolchain; if you opt to use LLVM/Clang, most distribution toolchains will
|
||||
support cross-compiling for RISC-V using the same toolchain as your native
|
||||
LLVM/Clang toolchain due to LLVM's ability to support multiple backends in the
|
||||
same binary, so is often an easy way to obtain a working cross-compilation
|
||||
toolchain.
|
||||
|
||||
Basically, we prefer toolchains with Position Independent Executable (PIE)
|
||||
support like *riscv64-linux-gnu-gcc*, *riscv64-unknown-freebsd-gcc*, or
|
||||
*Clang/LLVM* as they generate PIE firmware images that can run at arbitrary
|
||||
address with appropriate alignment. If a bare-metal GNU toolchain (e.g.
|
||||
*riscv64-unknown-elf-gcc*) is used, static linked firmware images are
|
||||
generated instead. *Clang/LLVM* can still generate PIE images if a bare-metal
|
||||
triple is used (e.g. *-target riscv64-unknown-elf*).
|
||||
|
||||
Please note that only a 64-bit version of the toolchain is available in
|
||||
the Bootlin toolchain repository for now.
|
||||
@@ -112,7 +124,7 @@ architecture than RISC-V.
|
||||
|
||||
For cross-compiling, the environment variable *CROSS_COMPILE* must be defined
|
||||
to specify the name prefix of the RISC-V compiler toolchain executables, e.g.
|
||||
*riscv64-unknown-elf-* if the gcc executable used is *riscv64-unknown-elf-gcc*.
|
||||
*riscv64-linux-gnu-* if the gcc executable used is *riscv64-linux-gnu-gcc*.
|
||||
|
||||
To build *libsbi.a* simply execute:
|
||||
```
|
||||
@@ -188,21 +200,83 @@ 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
|
||||
to *riscv64-linux-gnu-*, 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-*.
|
||||
pre-configured to generate 32-bit RISC-V codes, like *riscv32-linux-gnu-*.
|
||||
|
||||
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:
|
||||
|
||||
```
|
||||
export CROSS_COMPILE=riscv64-unknown-elf-
|
||||
export CROSS_COMPILE=riscv64-linux-gnu-
|
||||
export PLATFORM_RISCV_XLEN=32
|
||||
```
|
||||
|
||||
will generate 32-bit OpenSBI images. And vice vesa.
|
||||
|
||||
Building with Clang/LLVM
|
||||
------------------------
|
||||
|
||||
OpenSBI can also be built with Clang/LLVM. To build with just Clang but keep
|
||||
the default binutils (which will still use the *CROSS_COMPILE* prefix if
|
||||
defined), override the *CC* make variable with:
|
||||
```
|
||||
make CC=clang
|
||||
```
|
||||
|
||||
To build with a full LLVM-based toolchain, not just Clang, enable the *LLVM*
|
||||
option with:
|
||||
```
|
||||
make LLVM=1
|
||||
```
|
||||
|
||||
When using Clang, *CROSS_COMPILE* often does not need to be defined unless
|
||||
using GNU binutils with prefixed binary names. *PLATFORM_RISCV_XLEN* will be
|
||||
used to infer a default triple to pass to Clang, so if *PLATFORM_RISCV_XLEN*
|
||||
itself defaults to an undesired value then prefer setting that rather than the
|
||||
full triple via *CROSS_COMPILE*. If *CROSS_COMPILE* is nonetheless defined,
|
||||
rather than being used as a prefix for the executable name, it will instead be
|
||||
passed via the `--target` option with the trailing `-` removed, so must be a
|
||||
valid triple.
|
||||
|
||||
These can also be mixed; for example using a GCC cross-compiler but LLVM
|
||||
binutils would be:
|
||||
```
|
||||
make CC=riscv64-linux-gnu-gcc LLVM=1
|
||||
```
|
||||
|
||||
These variables must be passed for all the make invocations described in this
|
||||
document.
|
||||
|
||||
NOTE: Using Clang with a `riscv*-linux-gnu` GNU binutils linker has been seen
|
||||
to produce broken binaries with missing relocations; it is therefore currently
|
||||
recommended that this combination be avoided or *FW_PIC=n* be used to disable
|
||||
building OpenSBI as a position-independent binary.
|
||||
|
||||
Building with timestamp and compiler info
|
||||
-----------------------------------------
|
||||
|
||||
When doing development, we may want to know the build time and compiler info
|
||||
for debug purpose. OpenSBI can also be built with timestamp and compiler info.
|
||||
To build with those info and print it out at boot time, we can just simply add
|
||||
`BUILD_INFO=y`, like:
|
||||
```
|
||||
make BUILD_INFO=y
|
||||
```
|
||||
|
||||
But if you have used `BUILD_INFO=y`, and want to switch back to `BUILD_INFO=n`,
|
||||
you must do
|
||||
```
|
||||
make clean
|
||||
```
|
||||
before the next build.
|
||||
|
||||
NOTE: Using `BUILD_INFO=y` without specifying SOURCE_DATE_EPOCH will violate
|
||||
[reproducible builds]. This definition is ONLY for development and debug
|
||||
purpose, and should NOT be used in a product which follows "reproducible
|
||||
builds".
|
||||
|
||||
Contributing to OpenSBI
|
||||
-----------------------
|
||||
|
||||
@@ -226,6 +300,8 @@ Detailed documentation of various aspects of OpenSBI can be found under the
|
||||
* [Platform Documentation]: Documentation of the platforms currently supported.
|
||||
* [Firmware Documentation]: Documentation for the different types of firmware
|
||||
examples build supported by OpenSBI.
|
||||
* [Domain Support]: Documentation for the OpenSBI domain support which helps
|
||||
users achieve system-level partitioning using OpenSBI.
|
||||
|
||||
OpenSBI source code is also well documented. For source level documentation,
|
||||
doxygen style is used. Please refer to the [Doxygen manual] for details on this
|
||||
@@ -269,6 +345,7 @@ make I=<install_directory> install_docs
|
||||
|
||||
[Github]: https://github.com/riscv/riscv-sbi-doc
|
||||
[U-Boot]: https://www.denx.de/wiki/U-Boot/SourceCode
|
||||
[Bootlin toolchain repository]: https://toolchains.bootlin.com/
|
||||
[COPYING.BSD]: COPYING.BSD
|
||||
[SPDX]: http://spdx.org/licenses/
|
||||
[Contribution Guideline]: docs/contributing.md
|
||||
@@ -278,6 +355,8 @@ make I=<install_directory> install_docs
|
||||
[Platform Support Guide]: docs/platform_guide.md
|
||||
[Platform Documentation]: docs/platform/platform.md
|
||||
[Firmware Documentation]: docs/firmware/fw.md
|
||||
[Domain Support]: docs/domain_support.md
|
||||
[Doxygen manual]: http://www.doxygen.nl/manual/index.html
|
||||
[Kendryte standalone SDK]: https://github.com/kendryte/kendryte-standalone-sdk
|
||||
[third party notices]: ThirdPartyNotices.md
|
||||
[reproducible builds]: https://reproducible-builds.org
|
||||
|
314
docs/domain_support.md
Normal file
314
docs/domain_support.md
Normal file
@@ -0,0 +1,314 @@
|
||||
OpenSBI Domain Support
|
||||
======================
|
||||
|
||||
An OpenSBI domain is a system-level partition (subset) of underlying hardware
|
||||
having it's own memory regions (RAM and MMIO devices) and HARTs. The OpenSBI
|
||||
will try to achieve secure isolation between domains using RISC-V platform
|
||||
features such as PMP, ePMP, IOPMP, SiFive Shield, etc.
|
||||
|
||||
Important entities which help implement OpenSBI domain support are:
|
||||
|
||||
* **struct sbi_domain_memregion** - Representation of a domain memory region
|
||||
* **struct sbi_hartmask** - Representation of domain HART set
|
||||
* **struct sbi_domain** - Representation of a domain instance
|
||||
|
||||
Each HART of a RISC-V platform must have an OpenSBI domain assigned to it.
|
||||
The OpenSBI platform support is responsible for populating domains and
|
||||
providing HART id to domain mapping. The OpenSBI domain support will by
|
||||
default assign **the ROOT domain** to all HARTs of a RISC-V platform so
|
||||
it is not mandatory for the OpenSBI platform support to populate domains.
|
||||
|
||||
Domain Memory Region
|
||||
--------------------
|
||||
|
||||
A domain memory region is represented by **struct sbi_domain_memregion** in
|
||||
OpenSBI and has following details:
|
||||
|
||||
* **order** - The size of a memory region is **2 ^ order** where **order**
|
||||
must be **3 <= order <= __riscv_xlen**
|
||||
* **base** - The base address of a memory region is **2 ^ order**
|
||||
aligned start address
|
||||
* **flags** - The flags of a memory region represent memory type (i.e.
|
||||
RAM or MMIO) and allowed accesses (i.e. READ, WRITE, EXECUTE, etc)
|
||||
|
||||
Domain Instance
|
||||
---------------
|
||||
|
||||
A domain instance is represented by **struct sbi_domain** in OpenSBI and
|
||||
has following details:
|
||||
|
||||
* **index** - Logical index of this domain
|
||||
* **name** - Name of this domain
|
||||
* **assigned_harts** - HARTs assigned to this domain
|
||||
* **possible_harts** - HARTs possible in this domain
|
||||
* **regions** - Array of memory regions terminated by a memory region
|
||||
with order zero
|
||||
* **boot_hartid** - HART id of the HART booting this domain. The domain
|
||||
boot HART will be started at boot-time if boot HART is possible and
|
||||
assigned for this domain.
|
||||
* **next_addr** - Address of the next booting stage for this domain
|
||||
* **next_arg1** - Arg1 (or 'a1' register) of the next booting stage for
|
||||
this domain
|
||||
* **next_mode** - Privilege mode of the next booting stage for this
|
||||
domain. This can be either S-mode or U-mode.
|
||||
* **system_reset_allowed** - Is domain allowed to reset the system?
|
||||
|
||||
The memory regions represented by **regions** in **struct sbi_domain** have
|
||||
following additional constraints to align with RISC-V PMP requirements:
|
||||
|
||||
* A memory region to protect OpenSBI firmware from S-mode and U-mode
|
||||
should always be present
|
||||
* For two overlapping memory regions, one should be sub-region of another
|
||||
* Two overlapping memory regions should not be of same size
|
||||
* Two overlapping memory regions cannot have same flags
|
||||
* Memory access checks on overlapping address should prefer smallest
|
||||
overlapping memory region flags.
|
||||
|
||||
ROOT Domain
|
||||
-----------
|
||||
|
||||
**The ROOT domain** is the default OpenSBI domain which is assigned by
|
||||
default to all HARTs of a RISC-V platform. The OpenSBI domain support
|
||||
will hand-craft **the ROOT domain** very early at boot-time in the
|
||||
following manner:
|
||||
|
||||
* **index** - Logical index of the ROOT domain is always zero
|
||||
* **name** - Name of the ROOT domain is "root"
|
||||
* **assigned_harts** - At boot-time all valid HARTs of a RISC-V platform
|
||||
are assigned the ROOT domain which changes later based on OpenSBI
|
||||
platform support
|
||||
* **possible_harts** - All valid HARTs of a RISC-V platform are possible
|
||||
HARTs of the ROOT domain
|
||||
* **regions** - Two memory regions available to the ROOT domain:
|
||||
**A)** A memory region to protect OpenSBI firmware from S-mode and U-mode
|
||||
**B)** A memory region of **order=__riscv_xlen** allowing S-mode and
|
||||
U-mode access to full memory address space
|
||||
* **boot_hartid** - Coldboot HART is the HART booting the ROOT domain
|
||||
* **next_addr** - Next booting stage address in coldboot HART scratch
|
||||
space is the next address for the ROOT domain
|
||||
* **next_arg1** - Next booting stage arg1 in coldboot HART scratch space
|
||||
is the next arg1 for the ROOT domain
|
||||
* **next_mode** - Next booting stage mode in coldboot HART scratch space
|
||||
is the next mode for the ROOT domain
|
||||
* **system_reset_allowed** - The ROOT domain is allowed to reset the system
|
||||
|
||||
Domain Effects
|
||||
--------------
|
||||
|
||||
Few noteworthy effects of a system partitioned into domains are as follows:
|
||||
|
||||
* At any point in time, a HART is running in exactly one OpenSBI domain context
|
||||
* The SBI IPI and RFENCE calls from HART A are restricted to the HARTs in
|
||||
domain assigned to HART A
|
||||
* The SBI HSM calls which try to change/read state of HART B from HART A will
|
||||
only work if both HART A and HART B are assigned same domain
|
||||
* A HART running in S-mode or U-mode can only access memory based on the
|
||||
memory regions of the domain assigned to the HART
|
||||
|
||||
Domain Device Tree Bindings
|
||||
---------------------------
|
||||
|
||||
The OpenSBI domains can be described in the **device tree (DT) blob** (or
|
||||
flattened device tree) passed to the OpenSBI firmwares by the previous
|
||||
booting stage. This allows OpenSBI platform support to parse and populate
|
||||
OpenSBI domains from the device tree blob (or flattened device tree).
|
||||
|
||||
### Domain Configuration Node
|
||||
|
||||
All OpenSBI domain description related DT nodes should be under the domain
|
||||
configuration DT node. The **/chosen** DT node is the preferred parent of
|
||||
the domain configuration DT node.
|
||||
|
||||
The DT properties of a domain configuration DT node are as follows:
|
||||
|
||||
* **compatible** (Mandatory) - The compatible string of the domain
|
||||
configuration. This DT property should have value *"opensbi,domain,config"*
|
||||
|
||||
### Domain Memory Region Node
|
||||
|
||||
The domain memory region DT node describes details of a memory region and
|
||||
can be pointed by multiple domain instance DT nodes. The access permissions
|
||||
of the memory region are specified separately in domain instance node.
|
||||
|
||||
The DT properties of a domain memory region DT node are as follows:
|
||||
|
||||
* **compatible** (Mandatory) - The compatible string of the domain memory
|
||||
region. This DT property should have value *"opensbi,domain,memregion"*
|
||||
* **base** (Mandatory) - The base address of the domain memory region. This
|
||||
DT property should have a **2 ^ order** aligned 64 bit address (i.e. two
|
||||
DT cells).
|
||||
* **order** (Mandatory) - The order of the domain memory region. This DT
|
||||
property should have a 32 bit value (i.e. one DT cell) in the range
|
||||
**3 <= order <= __riscv_xlen**.
|
||||
* **mmio** (Optional) - A boolean flag representing whether the domain
|
||||
memory region is a memory-mapped I/O (MMIO) region.
|
||||
* **devices** (Optional) - The list of device DT node phandles for devices
|
||||
which fall under this domain memory region.
|
||||
|
||||
### Domain Instance Node
|
||||
|
||||
The domain instance DT node describes set of possible HARTs, set of memory
|
||||
regions, and other details of a domain instance.
|
||||
|
||||
The DT properties of a domain instance DT node are as follows:
|
||||
|
||||
* **compatible** (Mandatory) - The compatible string of the domain instance.
|
||||
This DT property should have value *"opensbi,domain,instance"*
|
||||
* **possible-harts** (Optional) - The list of CPU DT node phandles for the
|
||||
the domain instance. This list represents the possible HARTs of the
|
||||
domain instance.
|
||||
* **regions** (Optional) - The list of domain memory region DT node phandle
|
||||
and access permissions for the domain instance. Each list entry is a pair
|
||||
of DT node phandle and access permissions. The access permissions are
|
||||
represented as a 32bit bitmask having bits: **readable** (BIT[0]),
|
||||
**writeable** (BIT[1]), **executable** (BIT[2]), and **m-mode** (BIT[3]).
|
||||
* **boot-hart** (Optional) - The DT node phandle of the HART booting the
|
||||
domain instance. If coldboot HART is assigned to the domain instance then
|
||||
this DT property is ignored and the coldboot HART is assumed to be the
|
||||
boot HART of the domain instance.
|
||||
* **next-arg1** (Optional) - The 64 bit next booting stage arg1 for the
|
||||
domain instance. If this DT property is not available and coldboot HART
|
||||
is not assigned to the domain instance then **0x0** is used as default
|
||||
value. If this DT property is not available and coldboot HART is assigned
|
||||
to the domain instance then **next booting stage arg1 of coldboot HART**
|
||||
is used as default value.
|
||||
* **next-addr** (Optional) - The 64 bit next booting stage address for the
|
||||
domain instance. If this DT property is not available and coldboot HART
|
||||
is not assigned to the domain instance then **0x0** is used as default
|
||||
value. If this DT property is not available and coldboot HART is assigned
|
||||
to the domain instance then **next booting stage address of coldboot HART**
|
||||
is used as default value.
|
||||
* **next-mode** (Optional) - The 32 bit next booting stage mode for the
|
||||
domain instance. The possible values of this DT property are: **0x1**
|
||||
(s-mode), and **0x0** (u-mode). If this DT property is not available
|
||||
and coldboot HART is not assigned to the domain instance then **0x1**
|
||||
is used as default value. If this DT property is not available and
|
||||
coldboot HART is assigned to the domain instance then **next booting
|
||||
stage mode of coldboot HART** is used as default value.
|
||||
* **system-reset-allowed** (Optional) - A boolean flag representing
|
||||
whether the domain instance is allowed to do system reset.
|
||||
|
||||
### Assigning HART To Domain Instance
|
||||
|
||||
By default, all HARTs are assigned to **the ROOT domain**. The OpenSBI
|
||||
platform support can provide the HART to domain instance assignment using
|
||||
platform specific callback.
|
||||
|
||||
The HART to domain instance assignment can be parsed from the device tree
|
||||
using optional DT property **opensbi,domain** in each CPU DT node. The
|
||||
value of DT property **opensbi,domain** is the DT phandle of the domain
|
||||
instance DT node. If **opensbi,domain** DT property is not specified then
|
||||
corresponding HART is assigned to **the ROOT domain**.
|
||||
|
||||
### Domain Configuration Only Accessible to OpenSBI
|
||||
|
||||
The software running inside a domain instance should only be aware of
|
||||
devices and hardware resources accessible to itself.
|
||||
|
||||
To hide domain configuration from domain instances, the following should
|
||||
be done:
|
||||
|
||||
* The previous booting stage should preferably provide a separate device
|
||||
tree for each domain instance and mention location of device tree in
|
||||
respective domain instance DT nodes using **next-arg1** DT property.
|
||||
* If domain assigned to a HART does not have separate device tree then
|
||||
OpenSBI platform support should remove all domain configuration details
|
||||
from the device tree passed by previous booting stage before passing it
|
||||
to the next booting stage.
|
||||
|
||||
### Example
|
||||
|
||||
```
|
||||
chosen {
|
||||
opensbi-domains {
|
||||
compatible = "opensbi,domain,config";
|
||||
|
||||
tmem: tmem {
|
||||
compatible = "opensbi,domain,memregion";
|
||||
base = <0x0 0x80100000>;
|
||||
order = <20>;
|
||||
};
|
||||
|
||||
tuart: tuart {
|
||||
compatible = "opensbi,domain,memregion";
|
||||
base = <0x0 0x10011000>;
|
||||
order = <12>;
|
||||
mmio;
|
||||
devices = <&uart1>;
|
||||
};
|
||||
|
||||
allmem: allmem {
|
||||
compatible = "opensbi,domain,memregion";
|
||||
base = <0x0 0x0>;
|
||||
order = <64>;
|
||||
};
|
||||
|
||||
tdomain: trusted-domain {
|
||||
compatible = "opensbi,domain,instance";
|
||||
possible-harts = <&cpu0>;
|
||||
regions = <&tmem 0x7>, <&tuart 0x7>;
|
||||
boot-hart = <&cpu0>;
|
||||
next-arg1 = <0x0 0x0>;
|
||||
next-addr = <0x0 0x80100000>;
|
||||
next-mode = <0x0>;
|
||||
system-reset-allowed;
|
||||
};
|
||||
|
||||
udomain: untrusted-domain {
|
||||
compatible = "opensbi,domain,instance";
|
||||
possible-harts = <&cpu1 &cpu2 &cpu3 &cpu4>;
|
||||
regions = <&tmem 0x0>, <&tuart 0x0>, <&allmem 0x7>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
timebase-frequency = <10000000>;
|
||||
|
||||
cpu0: cpu@0 {
|
||||
device_type = "cpu";
|
||||
reg = <0x00>;
|
||||
compatible = "riscv";
|
||||
opensbi-domain = <&tdomain>;
|
||||
...
|
||||
};
|
||||
|
||||
cpu1: cpu@1 {
|
||||
device_type = "cpu";
|
||||
reg = <0x01>;
|
||||
compatible = "riscv";
|
||||
opensbi-domain = <&udomain>;
|
||||
...
|
||||
};
|
||||
|
||||
cpu2: cpu@2 {
|
||||
device_type = "cpu";
|
||||
reg = <0x02>;
|
||||
compatible = "riscv";
|
||||
opensbi-domain = <&udomain>;
|
||||
...
|
||||
};
|
||||
|
||||
cpu3: cpu@3 {
|
||||
device_type = "cpu";
|
||||
reg = <0x03>;
|
||||
compatible = "riscv";
|
||||
opensbi-domain = <&udomain>;
|
||||
...
|
||||
};
|
||||
|
||||
cpu4: cpu@4 {
|
||||
device_type = "cpu";
|
||||
reg = <0x04>;
|
||||
compatible = "riscv";
|
||||
opensbi-domain = <&udomain>;
|
||||
...
|
||||
};
|
||||
};
|
||||
|
||||
uart1: serial@10011000 {
|
||||
...
|
||||
};
|
||||
```
|
@@ -795,6 +795,7 @@ INPUT = @@SRC_DIR@@/README.md \
|
||||
@@SRC_DIR@@/docs/platform_guide.md \
|
||||
@@SRC_DIR@@/docs/platform_requirements.md \
|
||||
@@SRC_DIR@@/docs/library_usage.md \
|
||||
@@SRC_DIR@@/docs/domain_support.md \
|
||||
@@SRC_DIR@@/docs/firmware \
|
||||
@@SRC_DIR@@/docs/platform \
|
||||
@@SRC_DIR@@/include \
|
||||
|
@@ -9,6 +9,13 @@ OpenSBI generic library code. The supported firmwares type will differ in how
|
||||
the arguments passed by the platform early boot stage are handled, as well as
|
||||
how the boot stage following the firmware will be handled and executed.
|
||||
|
||||
The previous booting stage will pass information via the following registers
|
||||
of RISC-V CPU:
|
||||
|
||||
* hartid via *a0* register
|
||||
* device tree blob address in memory via *a1* register. The address must
|
||||
be aligned to 8 bytes.
|
||||
|
||||
OpenSBI currently supports three different types of firmwares.
|
||||
|
||||
Firmware with Dynamic Information (*FW_DYNAMIC*)
|
||||
@@ -51,11 +58,23 @@ case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree in the
|
||||
Firmware Configuration and Compilation
|
||||
--------------------------------------
|
||||
|
||||
All firmware types mandate the definition of the following compile time
|
||||
configuration parameter.
|
||||
All firmware types support the following common compile time configuration
|
||||
parameters:
|
||||
|
||||
* **FW_TEXT_ADDR** - Defines the address at which the previous booting stage
|
||||
loads OpenSBI firmware.
|
||||
* **FW_TEXT_ADDR** - Defines the execution address of the OpenSBI firmware.
|
||||
This configuration parameter is mandatory.
|
||||
* **FW_FDT_PATH** - Path to an external flattened device tree binary file to
|
||||
be embedded in the *.rodata* section of the final firmware. If this option
|
||||
is not provided then the firmware will expect the FDT to be passed as an
|
||||
argument by the prior booting stage.
|
||||
* **FW_FDT_PADDING** - Optional zero bytes padding to the embedded flattened
|
||||
device tree binary file specified by **FW_FDT_PATH** option.
|
||||
* **FW_PIC** - "FW_PIC=y" generates position independent executable firmware
|
||||
images. OpenSBI can run at arbitrary address with appropriate alignment.
|
||||
Therefore, the original relocation mechanism ("FW_PIC=n") will be skipped.
|
||||
In other words, OpenSBI will directly run at the load address without any
|
||||
code movement. This option requires a toolchain with PIE support, and it
|
||||
is on by default.
|
||||
|
||||
Additionally, each firmware type as a set of type specific configuration
|
||||
parameters. Detailed information for each firmware type can be found in the
|
||||
|
@@ -6,8 +6,9 @@ information about next booting stage (e.g. a bootloader or an OS) and runtime
|
||||
OpenSBI library options from previous booting stage.
|
||||
|
||||
The previous booting stage will pass information to *FW_DYNAMIC* by creating
|
||||
*struct fw_dynamic_info* in memory and passing it's address to *FW_DYNAMIC*
|
||||
via *a2* register of RISC-V CPU.
|
||||
*struct fw_dynamic_info* in memory and passing its address to *FW_DYNAMIC*
|
||||
via *a2* register of RISC-V CPU. The address must be aligned to 8 bytes on
|
||||
RV64 and 4 bytes on RV32.
|
||||
|
||||
A *FW_DYNAMIC* firmware is particularly useful when the booting stage executed
|
||||
prior to OpenSBI firmware is capable of loading both the OpenSBI firmware and
|
||||
|
@@ -55,14 +55,9 @@ file. The parameters currently defined are as follows:
|
||||
automatically generated and used as a payload. This test payload executes
|
||||
an infinite `while (1)` loop after printing a message on the platform console.
|
||||
|
||||
* **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 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,
|
||||
stage or specified by the *FW_FDT_PATH* parameter and embedded in the
|
||||
*.rodata* 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 the FDT address passed by the previous booting stage
|
||||
to the next booting stage.
|
||||
|
@@ -1,9 +1,9 @@
|
||||
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
|
||||
memories, interrupt controller, debug module, AXI and AHB Bus Matrix Controller,
|
||||
AXI-to-AHB Bridge and a collection of fundamental AHB/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.
|
||||
|
||||
@@ -19,12 +19,12 @@ 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.
|
||||
the compile time option FW_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>
|
||||
make PLATFORM=andes/ae350 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<ae350.dtb path>
|
||||
```
|
||||
|
@@ -46,9 +46,13 @@ 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]*)
|
||||
* **SiFive HiFive Unleashed** (*[sifive_fu540.md]*)
|
||||
* **Spike** (*[spike.md]*)
|
||||
* **T-HEAD C9xx series Processors** (*[thead-c9xx.md]*)
|
||||
|
||||
[qemu_virt.md]: qemu_virt.md
|
||||
[spike.md]: spike.md
|
||||
[shakti_cclass.md]: shakti_cclass.md
|
||||
[sifive_fu540.md]: sifive_fu540.md
|
||||
[spike.md]: spike.md
|
||||
[thead-c9xx.md]: thead-c9xx.md
|
||||
|
@@ -28,15 +28,12 @@ OpenSBI currently supports the following virtual and hardware platforms:
|
||||
* **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]*.
|
||||
*[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
|
||||
@@ -55,5 +52,5 @@ facilitate the implementation.
|
||||
[andes-ae350.md]: andes-ae350.md
|
||||
[thead-c910.md]: thead-c910.md
|
||||
[spike.md]: spike.md
|
||||
[fpga_openpiton.md]: fpga_openpiton.md
|
||||
[fpga-openpiton.md]: fpga-openpiton.md
|
||||
[shakti_cclass.md]: shakti_cclass.md
|
||||
|
@@ -28,7 +28,7 @@ make PLATFORM=generic
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv64 -M virt -m 256M -nographic \
|
||||
-kernel build/platform/generic/firmware/fw_payload.bin
|
||||
-bios build/platform/generic/firmware/fw_payload.bin
|
||||
```
|
||||
|
||||
**U-Boot Payload**
|
||||
@@ -44,7 +44,7 @@ make PLATFORM=generic FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv64 -M virt -m 256M -nographic \
|
||||
-kernel build/platform/generic/firmware/fw_payload.elf
|
||||
-bios build/platform/generic/firmware/fw_payload.elf
|
||||
```
|
||||
or
|
||||
```
|
||||
@@ -66,7 +66,7 @@ make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Im
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv64 -M virt -m 256M -nographic \
|
||||
-kernel build/platform/generic/firmware/fw_payload.elf \
|
||||
-bios 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"
|
||||
@@ -95,7 +95,7 @@ make PLATFORM=generic PLATFORM_RISCV_XLEN=32
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv32 -M virt -m 256M -nographic \
|
||||
-kernel build/platform/generic/firmware/fw_payload.bin
|
||||
-bios build/platform/generic/firmware/fw_payload.bin
|
||||
```
|
||||
|
||||
**U-Boot Payload**
|
||||
@@ -111,7 +111,7 @@ make PLATFORM=generic PLATFORM_RISCV_XLEN=32 FW_PAYLOAD_PATH=<uboot_build_direct
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv32 -M virt -m 256M -nographic \
|
||||
-kernel build/platform/generic/firmware/fw_payload.elf
|
||||
-bios build/platform/generic/firmware/fw_payload.elf
|
||||
```
|
||||
or
|
||||
```
|
||||
@@ -133,7 +133,7 @@ make PLATFORM=generic PLATFORM_RISCV_XLEN=32 FW_PAYLOAD_PATH=<linux_build_direct
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv32 -M virt -m 256M -nographic \
|
||||
-kernel build/platform/generic/firmware/fw_payload.elf \
|
||||
-bios 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"
|
||||
@@ -147,3 +147,27 @@ qemu-system-riscv32 -M virt -m 256M -nographic \
|
||||
-device virtio-blk-device,drive=hd0 \
|
||||
-append "root=/dev/vda rw console=ttyS0"
|
||||
```
|
||||
|
||||
Debugging with GDB
|
||||
------------------
|
||||
|
||||
In a first console start OpenSBI with QEMU:
|
||||
|
||||
```
|
||||
qemu-system-riscv64 -M virt -m 256M -nographic \
|
||||
-bios build/platform/generic/firmware/fw_payload.bin \
|
||||
-gdb tcp::1234 \
|
||||
-S
|
||||
|
||||
```
|
||||
|
||||
Parameter *-gdb tcp::1234* specifies 1234 as the debug port.
|
||||
Parameter *-S* lets QEMU wait at the first instruction.
|
||||
|
||||
In a second console start GDB:
|
||||
|
||||
```
|
||||
gdb build/platform/generic/firmware/fw_payload.elf \
|
||||
-ex 'target remote localhost:1234'
|
||||
|
||||
```
|
||||
|
@@ -23,11 +23,11 @@ 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>
|
||||
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<shakti.dtb path>
|
||||
```
|
||||
|
||||
**Test Payload**
|
||||
|
||||
```
|
||||
make PLATFORM=generic FW_PAYLOAD_FDT_PATH=<shakti.dtb path>
|
||||
make PLATFORM=generic FW_FDT_PATH=<shakti.dtb path>
|
||||
```
|
||||
|
@@ -8,7 +8,7 @@ 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=generic* parameter to the top level `make` command.
|
||||
|
||||
Platform Options
|
||||
----------------
|
||||
@@ -27,27 +27,28 @@ U-Boot v2020.01 (or higher) should be used.
|
||||
The HiFive Unleashed device tree(DT) is merged in Linux v5.2 release. This
|
||||
DT (device tree) is not backward compatible with the DT passed from FSBL.
|
||||
|
||||
To use Linux v5.2 (or higher, the pre-built DTB (DT binary) from Linux v5.2
|
||||
To use Linux v5.2 (or higher), the pre-built DTB (DT binary) from Linux v5.2
|
||||
(or higher) should be used to build SiFive FU540 OpenSBI binaries by using
|
||||
the compile time option *FW_PAYLOAD_FDT_PATH*.
|
||||
the compile time option *FW_FDT_PATH*.
|
||||
|
||||
```
|
||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
||||
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
||||
or
|
||||
(For Linux v5.2 or higher)
|
||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_PAYLOAD_FDT_PATH=<hifive-unleashed-a00.dtb path from Linux kernel>
|
||||
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<hifive-unleashed-a00.dtb path from Linux kernel>
|
||||
```
|
||||
|
||||
**U-Boot Payload**
|
||||
|
||||
The command-line example here assumes that U-Boot was compiled using the
|
||||
sifive_fu540_defconfig configuration and with U-Boot v2020.01 (or higher).
|
||||
|
||||
The detailed U-Boot booting guide is avaialble at [U-Boot].
|
||||
sifive_fu540_defconfig configuration and with U-Boot v2020.01, and up to
|
||||
v2021.04. sifive_unleashed_defconfig shall be used with v2021.07 or above.
|
||||
|
||||
```
|
||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot-dtb.bin
|
||||
make PLATFORM=generic FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot-dtb.bin
|
||||
```
|
||||
For U-Boot v2020.07-rc4 or later releases, SPL support was added in U-Boot.
|
||||
Please refer to the detailed U-Boot booting guide available at [U-Boot].
|
||||
|
||||
Flashing the OpenSBI firmware binary to storage media:
|
||||
------------------------------------------------------
|
||||
@@ -63,7 +64,7 @@ That's why the generated firmware binary in above steps should be copied to
|
||||
the partition of the sdcard with above GUID.
|
||||
|
||||
```
|
||||
dd if=build/platform/sifive/fu540/firmware/fw_payload.bin of=/dev/disk2s1 bs=1024
|
||||
dd if=build/platform/generic/firmware/fw_payload.bin of=/dev/disk2s1 bs=1024
|
||||
```
|
||||
|
||||
In my case, it is the first partition is **disk2s1** that has been formatted
|
||||
@@ -146,20 +147,45 @@ 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.
|
||||
same instructions above, with the exception of not passing FW_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
|
||||
When U-Boot v2021.07 (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:
|
||||
reason above, we need to switch the U-Boot sifive_unleashed_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
|
||||
make PLATFORM=generic FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin
|
||||
```
|
||||
|
||||
U-Boot v2020.07 release added SPL support to SiFive HiFive Unleashed board,
|
||||
hence a build error will be seen after you switch to **CONFIG_OF_PRIOR_STAGE**.
|
||||
|
||||
```
|
||||
./tools/mkimage: Can't open arch/riscv/dts/hifive-unleashed-a00.dtb: No such file or directory
|
||||
./tools/mkimage: failed to build FIT
|
||||
Makefile:1402: recipe for target 'u-boot.img' failed
|
||||
make: *** [u-boot.img] Error 1
|
||||
```
|
||||
|
||||
The above errors can be safely ignored as we don't run U-Boot SPL under QEMU.
|
||||
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv64 -M sifive_u -m 256M -nographic \
|
||||
-bios build/platform/generic/firmware/fw_payload.bin
|
||||
```
|
||||
or
|
||||
```
|
||||
qemu-system-riscv64 -M sifive_u -m 256M -nographic \
|
||||
-bios build/platform/generic/firmware/fw_jump.bin \
|
||||
-kernel <uboot_build_dir>/u-boot.bin
|
||||
```
|
||||
|
||||
While the real hardware operates at the 64-bit mode, it's possible for QEMU to
|
||||
|
@@ -43,7 +43,18 @@ make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Im
|
||||
|
||||
Run:
|
||||
```
|
||||
spike --initrd <path_to_cpio_ramdisk> build/platform/generic/firmware/fw_payload.elf
|
||||
spike -m256 \
|
||||
--initrd <path_to_cpio_ramdisk> \
|
||||
--bootargs 'root=/dev/ram rw console=hvc0 earlycon=sbi' \
|
||||
build/platform/generic/firmware/fw_payload.elf
|
||||
```
|
||||
or
|
||||
```
|
||||
spike -m256 \
|
||||
--kernel <linux_build_directory>/arch/riscv/boot/Image \
|
||||
--initrd <path_to_cpio_ramdisk> \
|
||||
--bootargs 'root=/dev/ram rw console=hvc0 earlycon=sbi' \
|
||||
build/platform/generic/firmware/fw_jump.elf
|
||||
```
|
||||
|
||||
Execution on QEMU RISC-V 64-bit
|
||||
@@ -59,7 +70,7 @@ make PLATFORM=generic
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv64 -M spike -m 256M -nographic \
|
||||
-kernel build/platform/generic/firmware/fw_payload.elf
|
||||
-bios build/platform/generic/firmware/fw_payload.elf
|
||||
```
|
||||
|
||||
**Linux Kernel Payload**
|
||||
@@ -75,7 +86,7 @@ make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Im
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv64 -M spike -m 256M -nographic \
|
||||
-kernel build/platform/generic/firmware/fw_payload.elf \
|
||||
-bios build/platform/generic/firmware/fw_payload.elf \
|
||||
-initrd <path_to_cpio_ramdisk> \
|
||||
-append "root=/dev/ram rw console=hvc0 earlycon=sbi"
|
||||
```
|
||||
|
@@ -1,34 +0,0 @@
|
||||
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.
|
198
docs/platform/thead-c9xx.md
Normal file
198
docs/platform/thead-c9xx.md
Normal file
@@ -0,0 +1,198 @@
|
||||
T-HEAD C9xx Series Processors
|
||||
=============================
|
||||
|
||||
The **C9xx** series processors are high-performance RISC-V architecture
|
||||
multi-core processors with AI vector acceleration engine.
|
||||
|
||||
For more details, refer [T-HEAD.CN](https://www.t-head.cn/)
|
||||
|
||||
To build the platform-specific library and firmware images, provide the
|
||||
*PLATFORM=generic* parameter to the top level `make` command.
|
||||
|
||||
Platform Options
|
||||
----------------
|
||||
|
||||
The *T-HEAD C9xx* does not have any platform-specific compile options
|
||||
because it use generic platform.
|
||||
|
||||
```
|
||||
CROSS_COMPILE=riscv64-linux-gnu- PLATFORM=generic /usr/bin/make
|
||||
```
|
||||
|
||||
The *T-HEAD C9xx* DTB provided to OpenSBI generic firmwares will usually have
|
||||
"riscv,clint0", "riscv,plic0", "thead,reset-sample" compatible strings.
|
||||
|
||||
DTS Example1: (Single core, eg: Allwinner D1 - c906)
|
||||
----------------------------------------------------
|
||||
|
||||
```
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
timebase-frequency = <3000000>;
|
||||
cpu@0 {
|
||||
device_type = "cpu";
|
||||
reg = <0>;
|
||||
status = "okay";
|
||||
compatible = "riscv";
|
||||
riscv,isa = "rv64imafdcv";
|
||||
mmu-type = "riscv,sv39";
|
||||
cpu0_intc: interrupt-controller {
|
||||
#interrupt-cells = <1>;
|
||||
compatible = "riscv,cpu-intc";
|
||||
interrupt-controller;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
compatible = "simple-bus";
|
||||
ranges;
|
||||
|
||||
clint0: clint@14000000 {
|
||||
compatible = "riscv,clint0";
|
||||
interrupts-extended = <
|
||||
&cpu0_intc 3 &cpu0_intc 7
|
||||
>;
|
||||
reg = <0x0 0x14000000 0x0 0x04000000>;
|
||||
clint,has-no-64bit-mmio;
|
||||
};
|
||||
|
||||
intc: interrupt-controller@10000000 {
|
||||
#interrupt-cells = <1>;
|
||||
compatible = "allwinner,sun20i-d1-plic",
|
||||
"thead,c900-plic";
|
||||
interrupt-controller;
|
||||
interrupts-extended = <
|
||||
&cpu0_intc 0xffffffff &cpu0_intc 9
|
||||
>;
|
||||
reg = <0x0 0x10000000 0x0 0x04000000>;
|
||||
reg-names = "control";
|
||||
riscv,max-priority = <7>;
|
||||
riscv,ndev = <200>;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
DTS Example2: (Multi cores with soc reset-regs)
|
||||
-----------------------------------------------
|
||||
|
||||
```
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
timebase-frequency = <3000000>;
|
||||
cpu@0 {
|
||||
device_type = "cpu";
|
||||
reg = <0>;
|
||||
status = "okay";
|
||||
compatible = "riscv";
|
||||
riscv,isa = "rv64imafdc";
|
||||
mmu-type = "riscv,sv39";
|
||||
cpu0_intc: interrupt-controller {
|
||||
#interrupt-cells = <1>;
|
||||
compatible = "riscv,cpu-intc";
|
||||
interrupt-controller;
|
||||
};
|
||||
};
|
||||
cpu@1 {
|
||||
device_type = "cpu";
|
||||
reg = <1>;
|
||||
status = "fail";
|
||||
compatible = "riscv";
|
||||
riscv,isa = "rv64imafdc";
|
||||
mmu-type = "riscv,sv39";
|
||||
cpu1_intc: interrupt-controller {
|
||||
#interrupt-cells = <1>;
|
||||
compatible = "riscv,cpu-intc";
|
||||
interrupt-controller;
|
||||
};
|
||||
};
|
||||
cpu@2 {
|
||||
device_type = "cpu";
|
||||
reg = <2>;
|
||||
status = "fail";
|
||||
compatible = "riscv";
|
||||
riscv,isa = "rv64imafdc";
|
||||
mmu-type = "riscv,sv39";
|
||||
cpu2_intc: interrupt-controller {
|
||||
#interrupt-cells = <1>;
|
||||
compatible = "riscv,cpu-intc";
|
||||
interrupt-controller;
|
||||
};
|
||||
};
|
||||
cpu@3 {
|
||||
device_type = "cpu";
|
||||
reg = <3>;
|
||||
status = "fail";
|
||||
compatible = "riscv";
|
||||
riscv,isa = "rv64imafdc";
|
||||
mmu-type = "riscv,sv39";
|
||||
cpu3_intc: interrupt-controller {
|
||||
#interrupt-cells = <1>;
|
||||
compatible = "riscv,cpu-intc";
|
||||
interrupt-controller;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
compatible = "simple-bus";
|
||||
ranges;
|
||||
|
||||
reset: reset-sample {
|
||||
compatible = "thead,reset-sample";
|
||||
entry-reg = <0xff 0xff019050>;
|
||||
entry-cnt = <4>;
|
||||
control-reg = <0xff 0xff015004>;
|
||||
control-val = <0x1c>;
|
||||
csr-copy = <0x7f3 0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc>;
|
||||
};
|
||||
|
||||
clint0: clint@ffdc000000 {
|
||||
compatible = "riscv,clint0";
|
||||
interrupts-extended = <
|
||||
&cpu0_intc 3 &cpu0_intc 7
|
||||
&cpu1_intc 3 &cpu1_intc 7
|
||||
&cpu2_intc 3 &cpu2_intc 7
|
||||
&cpu3_intc 3 &cpu3_intc 7
|
||||
&cpu4_intc 3 &cpu4_intc 7
|
||||
>;
|
||||
reg = <0xff 0xdc000000 0x0 0x04000000>;
|
||||
clint,has-no-64bit-mmio;
|
||||
};
|
||||
|
||||
intc: interrupt-controller@ffd8000000 {
|
||||
#interrupt-cells = <1>;
|
||||
compatible = "thead,c900-plic";
|
||||
interrupt-controller;
|
||||
interrupts-extended = <
|
||||
&cpu0_intc 0xffffffff &cpu0_intc 9
|
||||
&cpu1_intc 0xffffffff &cpu1_intc 9
|
||||
&cpu2_intc 0xffffffff &cpu2_intc 9
|
||||
&cpu3_intc 0xffffffff &cpu3_intc 9
|
||||
>;
|
||||
reg = <0xff 0xd8000000 0x0 0x04000000>;
|
||||
reg-names = "control";
|
||||
riscv,max-priority = <7>;
|
||||
riscv,ndev = <80>;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
DTS Example2: (Multi cores with old reset csrs)
|
||||
-----------------------------------------------
|
||||
```
|
||||
reset: reset-sample {
|
||||
compatible = "thead,reset-sample";
|
||||
using-csr-reset;
|
||||
csr-copy = <0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc
|
||||
0x3b0 0x3b1 0x3b2 0x3b3
|
||||
0x3b4 0x3b5 0x3b6 0x3b7
|
||||
0x3a0>;
|
||||
};
|
||||
```
|
@@ -17,7 +17,7 @@ the supported platforms. These firmwares are linked against *libplatsbi.a*.
|
||||
Firmware binaries are installed in
|
||||
*<install_directory>/platform/<platform_subdir>/bin*. These firmwares can be
|
||||
used as executable runtime firmwares on the supported platforms as a replacement
|
||||
for the legacy *riskv-pk* boot loader (BBL).
|
||||
for the legacy *riscv-pk* boot loader (BBL).
|
||||
|
||||
A complete doxygen-style documentation of *struct sbi_platform* and related
|
||||
APIs is available in the file *include/sbi/sbi_platform.h*.
|
||||
@@ -25,18 +25,18 @@ APIs is available in the file *include/sbi/sbi_platform.h*.
|
||||
Adding support for a new platform
|
||||
---------------------------------
|
||||
|
||||
Support for a new platform named *<xyz>* can be added as follows:
|
||||
Support for a new platform named *<xyz>* can be added as follows:
|
||||
|
||||
1. Create a directory named *<xyz>* under the *platform/* directory.
|
||||
1. Create a directory named *<xyz>* under the *platform/* directory.
|
||||
2. Create a platform configuration file named *config.mk* under the
|
||||
*platform/<xyz>/* directory. This configuration file will provide
|
||||
*platform/<xyz>/* directory. This configuration file will provide
|
||||
compiler flags, and select firmware options.
|
||||
3. Create a *platform/<xyz>/objects.mk* file for listing the
|
||||
3. Create a *platform/<xyz>/objects.mk* file for listing the
|
||||
platform-specific object files to be compiled.
|
||||
4. Create a *platform/<xyz>/platform.c* file providing a *struct sbi_platform*
|
||||
instance.
|
||||
4. Create a *platform/<xyz>/platform.c* file providing a
|
||||
*struct sbi_platform* instance.
|
||||
|
||||
A platform support code template is available under the *platform/template*
|
||||
directory. Copying this directory and its content as a new directory named
|
||||
*<xyz>* under the *platform/* directory will create all the files mentioned
|
||||
above.
|
||||
*<xyz>* under the *platform/* directory will create all the files
|
||||
mentioned above.
|
||||
|
87
docs/pmu_support.md
Normal file
87
docs/pmu_support.md
Normal file
@@ -0,0 +1,87 @@
|
||||
OpenSBI SBI PMU extension support
|
||||
==================================
|
||||
SBI PMU extension supports allow supervisor software to configure/start/stop
|
||||
any performance counter at anytime. Thus, an user can leverage full
|
||||
capability of performance analysis tools such as perf if SBI PMU extension is
|
||||
enabled. The OpenSBI implementation makes the following assumptions about the
|
||||
hardware platform.
|
||||
|
||||
* MCOUNTINHIBIT CSR must be implemented in the hardware. Otherwise, SBI PMU
|
||||
extension will not be enabled.
|
||||
|
||||
* The platform must provide information about PMU event to counter mapping
|
||||
via device tree or platform specific hooks. Otherwise, SBI PMU extension will
|
||||
not be enabled.
|
||||
|
||||
* The platforms should provide information about the PMU event selector values
|
||||
that should be encoded in the expected value of MHPMEVENTx while configuring
|
||||
MHPMCOUNTERx for that specific event. This can be done via a device tree or
|
||||
platform specific hooks. The exact value to be written to he MHPMEVENTx is
|
||||
completely depends on platform. Generic platform writes the zero-extended event_idx
|
||||
as the expected value for hardware cache/generic events as suggested by the SBI
|
||||
specification.
|
||||
|
||||
SBI PMU Device Tree Bindings
|
||||
----------------------------
|
||||
|
||||
Platforms may choose to describe PMU event selector and event to counter mapping
|
||||
values via device tree. The following sections describes the PMU DT node
|
||||
bindings in details.
|
||||
|
||||
* **compatible** (Mandatory) - The compatible string of SBI PMU device tree node.
|
||||
This DT property must have the value **riscv,pmu**.
|
||||
|
||||
* **riscv,event-to-mhpmevent**(Optional) - It represents an ONE-to-ONE mapping
|
||||
between a PMU event and the event selector value that platform expects to be
|
||||
written to the MHPMEVENTx CSR for that event. The mapping is encoded in a
|
||||
table format where each row represents an event. The first column represent the
|
||||
event idx where the 2nd & 3rd column represent the event selector value that
|
||||
should be encoded in the expected value to be written in MHPMEVENTx.
|
||||
This property shouldn't encode any raw hardware event.
|
||||
|
||||
* **riscv,event-to-mhpmcounters**(Optional) - It represents a MANY-to-MANY
|
||||
mapping between a range of events and all the MHPMCOUNTERx in a bitmap format
|
||||
that can be used to monitor these range of events. The information is encoded in
|
||||
a table format where each row represent a certain range of events and
|
||||
corresponding counters. The first column represents starting of the pmu event id
|
||||
and 2nd column represents the end of the pmu event id. The third column
|
||||
represent a bitmap of all the MHPMCOUNTERx. This property is mandatory if
|
||||
event-to-mhpmevent is present. Otherwise, it can be omitted. This property
|
||||
shouldn't encode any raw event.
|
||||
|
||||
* **riscv,raw-event-to-mhpmcounters**(Optional) - It represents an ONE-to-MANY
|
||||
or MANY-to-MANY mapping between the raw event(s) and all the MHPMCOUNTERx in
|
||||
a bitmap format that can be used to monitor that raw event, which depends on
|
||||
how the platform encodes the monitor events. Currently, only the following three
|
||||
encoding methods are supported, encoding each event as a number, using a bitmap
|
||||
to encode monitor events, and mixing the previous two methods. The information
|
||||
is encoded in a table format where each row represent the specific raw event(s).
|
||||
The first column represents a 64-bit selector value which can indicate an
|
||||
monitor event ID (encoded by a number) or an event set (encoded by a bitmap).
|
||||
In case of the latter, the lower bits used to encode a set of events should be
|
||||
set to zero. The second column is a 64-bit selector mask where any bits used
|
||||
for event encoding will be cleared. If a platform directly encodes each raw PMU
|
||||
event as a unique ID, the value of select_mask will be 0xffffffff_ffffffff.
|
||||
The third column represent a bitmap of all the MHPMCOUNTERx that can be used for
|
||||
monitoring the specified event(s).
|
||||
|
||||
*Note:* A platform may choose to provide the mapping between event & counters
|
||||
via platform hooks rather than the device tree.
|
||||
|
||||
### Example
|
||||
|
||||
```
|
||||
pmu {
|
||||
compatible = "riscv,pmu";
|
||||
interrupts = <0x100>;
|
||||
interrupt-parent = <&plic>
|
||||
riscv,event-to-mhpmevent = <0x0000B 0x0000 0x0001>,
|
||||
riscv,event-to-mhpmcounters = <0x00001 0x00001 0x00000001>,
|
||||
<0x00002 0x00002 0x00000004>,
|
||||
<0x00003 0x0000A 0x00000ff8>,
|
||||
<0x10000 0x10033 0x000ff000>,
|
||||
riscv,raw-event-to-mhpmcounters = <0x0000 0x0002 0xffffffff 0xffffffff 0x00000f8>,
|
||||
<0xffffffff 0xfffffff0 0xffffffff 0xfffffff0 0x00000ff0>,
|
||||
};
|
||||
|
||||
```
|
@@ -7,5 +7,8 @@
|
||||
# Anup Patel <anup.patel@wdc.com>
|
||||
#
|
||||
|
||||
$(platform_build_dir)/firmware/fw_dynamic.o: $(FW_FDT_PATH)
|
||||
$(platform_build_dir)/firmware/fw_jump.o: $(FW_FDT_PATH)
|
||||
$(platform_build_dir)/firmware/fw_payload.o: $(FW_FDT_PATH)
|
||||
|
||||
$(platform_build_dir)/firmware/fw_payload.o: $(FW_PAYLOAD_PATH_FINAL)
|
||||
$(platform_build_dir)/firmware/fw_payload.o: $(FW_PAYLOAD_FDT_PATH)
|
||||
|
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include <sbi/riscv_elf.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
@@ -57,39 +58,91 @@ _start:
|
||||
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
|
||||
lla a6, _relocate_lottery
|
||||
li a7, 1
|
||||
amoadd.w a6, a7, (a6)
|
||||
bnez a6, _wait_relocate_copy_done
|
||||
|
||||
/* Save load address */
|
||||
la t0, _load_start
|
||||
la t1, _start
|
||||
lla t0, _load_start
|
||||
lla t1, _fw_start
|
||||
REG_S t1, 0(t0)
|
||||
|
||||
#ifdef FW_PIC
|
||||
/* relocate the global table content */
|
||||
lla t0, _link_start
|
||||
REG_L t0, 0(t0)
|
||||
/* t1 shall has the address of _fw_start */
|
||||
sub t2, t1, t0
|
||||
lla t3, _runtime_offset
|
||||
REG_S t2, (t3)
|
||||
lla t0, __rel_dyn_start
|
||||
lla t1, __rel_dyn_end
|
||||
beq t0, t1, _relocate_done
|
||||
j 5f
|
||||
2:
|
||||
REG_L t5, -(REGBYTES*2)(t0) /* t5 <-- relocation info:type */
|
||||
li t3, R_RISCV_RELATIVE /* reloc type R_RISCV_RELATIVE */
|
||||
bne t5, t3, 3f
|
||||
REG_L t3, -(REGBYTES*3)(t0)
|
||||
REG_L t5, -(REGBYTES)(t0) /* t5 <-- addend */
|
||||
add t5, t5, t2
|
||||
add t3, t3, t2
|
||||
REG_S t5, 0(t3) /* store runtime address to the GOT entry */
|
||||
j 5f
|
||||
|
||||
3:
|
||||
lla t4, __dyn_sym_start
|
||||
|
||||
4:
|
||||
REG_L t5, -(REGBYTES*2)(t0) /* t5 <-- relocation info:type */
|
||||
srli t6, t5, SYM_INDEX /* t6 <--- sym table index */
|
||||
andi t5, t5, 0xFF /* t5 <--- relocation type */
|
||||
li t3, RELOC_TYPE
|
||||
bne t5, t3, 5f
|
||||
|
||||
/* address R_RISCV_64 or R_RISCV_32 cases*/
|
||||
REG_L t3, -(REGBYTES*3)(t0)
|
||||
li t5, SYM_SIZE
|
||||
mul t6, t6, t5
|
||||
add s5, t4, t6
|
||||
REG_L t6, -(REGBYTES)(t0) /* t0 <-- addend */
|
||||
REG_L t5, REGBYTES(s5)
|
||||
add t5, t5, t6
|
||||
add t5, t5, t2 /* t5 <-- location to fix up in RAM */
|
||||
add t3, t3, t2 /* t3 <-- location to fix up in RAM */
|
||||
REG_S t5, 0(t3) /* store runtime address to the variable */
|
||||
|
||||
5:
|
||||
addi t0, t0, (REGBYTES*3)
|
||||
ble t0, t1, 2b
|
||||
j _relocate_done
|
||||
_wait_relocate_copy_done:
|
||||
j _wait_for_boot_hart
|
||||
#else
|
||||
/* Relocate if load address != link address */
|
||||
_relocate:
|
||||
la t0, _link_start
|
||||
lla t0, _link_start
|
||||
REG_L t0, 0(t0)
|
||||
la t1, _link_end
|
||||
lla t1, _link_end
|
||||
REG_L t1, 0(t1)
|
||||
la t2, _load_start
|
||||
lla t2, _load_start
|
||||
REG_L t2, 0(t2)
|
||||
sub t3, t1, t0
|
||||
add t3, t3, t2
|
||||
beq t0, t2, _relocate_done
|
||||
la t4, _relocate_done
|
||||
lla t4, _relocate_done
|
||||
sub t4, t4, t2
|
||||
add t4, t4, t0
|
||||
blt t2, t0, _relocate_copy_to_upper
|
||||
_relocate_copy_to_lower:
|
||||
ble t1, t2, _relocate_copy_to_lower_loop
|
||||
la t3, _relocate_lottery
|
||||
lla t3, _relocate_lottery
|
||||
BRANGE t2, t1, t3, _start_hang
|
||||
la t3, _boot_status
|
||||
lla t3, _boot_status
|
||||
BRANGE t2, t1, t3, _start_hang
|
||||
la t3, _relocate
|
||||
la t5, _relocate_done
|
||||
lla t3, _relocate
|
||||
lla t5, _relocate_done
|
||||
BRANGE t2, t1, t3, _start_hang
|
||||
BRANGE t2, t1, t5, _start_hang
|
||||
BRANGE t3, t5, t2, _start_hang
|
||||
@@ -102,12 +155,12 @@ _relocate_copy_to_lower_loop:
|
||||
jr t4
|
||||
_relocate_copy_to_upper:
|
||||
ble t3, t0, _relocate_copy_to_upper_loop
|
||||
la t2, _relocate_lottery
|
||||
lla t2, _relocate_lottery
|
||||
BRANGE t0, t3, t2, _start_hang
|
||||
la t2, _boot_status
|
||||
lla t2, _boot_status
|
||||
BRANGE t0, t3, t2, _start_hang
|
||||
la t2, _relocate
|
||||
la t5, _relocate_done
|
||||
lla t2, _relocate
|
||||
lla t5, _relocate_done
|
||||
BRANGE t0, t3, t2, _start_hang
|
||||
BRANGE t0, t3, t5, _start_hang
|
||||
BRANGE t2, t5, t0, _start_hang
|
||||
@@ -119,12 +172,12 @@ _relocate_copy_to_upper_loop:
|
||||
blt t0, t1, _relocate_copy_to_upper_loop
|
||||
jr t4
|
||||
_wait_relocate_copy_done:
|
||||
la t0, _start
|
||||
la t1, _link_start
|
||||
lla t0, _fw_start
|
||||
lla t1, _link_start
|
||||
REG_L t1, 0(t1)
|
||||
beq t0, t1, _wait_for_boot_hart
|
||||
la t2, _boot_status
|
||||
la t3, _wait_for_boot_hart
|
||||
lla t2, _boot_status
|
||||
lla t3, _wait_for_boot_hart
|
||||
sub t3, t3, t0
|
||||
add t3, t3, t1
|
||||
1:
|
||||
@@ -137,19 +190,22 @@ _wait_relocate_copy_done:
|
||||
nop
|
||||
bgt t4, t5, 1b
|
||||
jr t3
|
||||
#endif
|
||||
_relocate_done:
|
||||
|
||||
/*
|
||||
* Mark relocate copy done
|
||||
* Use _boot_status copy relative to the load address
|
||||
*/
|
||||
la t0, _boot_status
|
||||
la t1, _link_start
|
||||
lla t0, _boot_status
|
||||
#ifndef FW_PIC
|
||||
lla t1, _link_start
|
||||
REG_L t1, 0(t1)
|
||||
la t2, _load_start
|
||||
lla t2, _load_start
|
||||
REG_L t2, 0(t2)
|
||||
sub t0, t0, t1
|
||||
add t0, t0, t2
|
||||
#endif
|
||||
li t1, BOOT_STATUS_RELOCATE_DONE
|
||||
REG_S t1, 0(t0)
|
||||
fence rw, rw
|
||||
@@ -161,19 +217,19 @@ _relocate_done:
|
||||
call _reset_regs
|
||||
|
||||
/* Zero-out BSS */
|
||||
la s4, _bss_start
|
||||
la s5, _bss_end
|
||||
lla s4, _bss_start
|
||||
lla 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
|
||||
lla s4, _start_hang
|
||||
csrw CSR_MTVEC, s4
|
||||
|
||||
/* Setup temporary stack */
|
||||
la s4, _fw_end
|
||||
lla s4, _fw_end
|
||||
li s5, (SBI_SCRATCH_SIZE * 2)
|
||||
add sp, s4, s5
|
||||
|
||||
@@ -182,14 +238,10 @@ _bss_zero:
|
||||
call fw_save_info
|
||||
MOV_5R a0, s0, a1, s1, a2, s2, a3, s3, a4, s4
|
||||
|
||||
#ifdef FW_FDT_PATH
|
||||
/* 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:
|
||||
lla a1, fw_fdt_bin
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialize platform
|
||||
@@ -206,7 +258,7 @@ _prev_arg1_override_done:
|
||||
* s7 -> HART Count
|
||||
* s8 -> HART Stack Size
|
||||
*/
|
||||
la a4, platform
|
||||
lla a4, platform
|
||||
#if __riscv_xlen == 64
|
||||
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
|
||||
lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
|
||||
@@ -216,7 +268,7 @@ _prev_arg1_override_done:
|
||||
#endif
|
||||
|
||||
/* Setup scratch space for all the HARTs*/
|
||||
la tp, _fw_end
|
||||
lla tp, _fw_end
|
||||
mul a5, s7, s8
|
||||
add tp, tp, a5
|
||||
/* Keep a copy of tp */
|
||||
@@ -226,6 +278,14 @@ _prev_arg1_override_done:
|
||||
/* hartid 0 is mandated by ISA */
|
||||
li t1, 0
|
||||
_scratch_init:
|
||||
/*
|
||||
* The following registers hold values that are computed before
|
||||
* entering this block, and should remain unchanged.
|
||||
*
|
||||
* t3 -> the firmware end address
|
||||
* s7 -> HART count
|
||||
* s8 -> HART stack size
|
||||
*/
|
||||
add tp, t3, zero
|
||||
mul a5, s8, t1
|
||||
sub tp, tp, a5
|
||||
@@ -234,11 +294,8 @@ _scratch_init:
|
||||
|
||||
/* Initialize scratch space */
|
||||
/* Store fw_start and fw_size in scratch space */
|
||||
la a4, _fw_start
|
||||
la a5, _fw_end
|
||||
mul t0, s7, s8
|
||||
add a5, a5, t0
|
||||
sub a5, a5, a4
|
||||
lla a4, _fw_start
|
||||
sub a5, t3, a4
|
||||
REG_S a4, SBI_SCRATCH_FW_START_OFFSET(tp)
|
||||
REG_S a5, SBI_SCRATCH_FW_SIZE_OFFSET(tp)
|
||||
/* Store next arg1 in scratch space */
|
||||
@@ -257,14 +314,17 @@ _scratch_init:
|
||||
REG_S a0, SBI_SCRATCH_NEXT_MODE_OFFSET(tp)
|
||||
MOV_3R a0, s0, a1, s1, a2, s2
|
||||
/* Store warm_boot address in scratch space */
|
||||
la a4, _start_warm
|
||||
lla a4, _start_warm
|
||||
REG_S a4, SBI_SCRATCH_WARMBOOT_ADDR_OFFSET(tp)
|
||||
/* Store platform address in scratch space */
|
||||
la a4, platform
|
||||
lla a4, platform
|
||||
REG_S a4, SBI_SCRATCH_PLATFORM_ADDR_OFFSET(tp)
|
||||
/* Store hartid-to-scratch function address in scratch space */
|
||||
la a4, _hartid_to_scratch
|
||||
lla a4, _hartid_to_scratch
|
||||
REG_S a4, SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET(tp)
|
||||
/* Store trap-exit function address in scratch space */
|
||||
lla a4, _trap_exit
|
||||
REG_S a4, SBI_SCRATCH_TRAP_EXIT_OFFSET(tp)
|
||||
/* Clear tmp0 in scratch space */
|
||||
REG_S zero, SBI_SCRATCH_TMP0_OFFSET(tp)
|
||||
/* Store firmware options in scratch space */
|
||||
@@ -289,8 +349,7 @@ _scratch_init:
|
||||
* previous booting stage.
|
||||
*/
|
||||
beqz a1, _fdt_reloc_done
|
||||
/* Mask values in a3 and a4 */
|
||||
li a3, ~(__SIZEOF_POINTER__ - 1)
|
||||
/* Mask values in a4 */
|
||||
li a4, 0xff
|
||||
/* t1 = destination FDT start address */
|
||||
MOV_3R s0, a0, s1, a1, s2, a2
|
||||
@@ -299,10 +358,8 @@ _scratch_init:
|
||||
MOV_3R a0, s0, a1, s1, a2, s2
|
||||
beqz t1, _fdt_reloc_done
|
||||
beq t1, a1, _fdt_reloc_done
|
||||
and t1, t1, a3
|
||||
/* t0 = source FDT start address */
|
||||
add t0, a1, zero
|
||||
and t0, t0, a3
|
||||
/* t2 = source FDT size in big-endian */
|
||||
#if __riscv_xlen == 64
|
||||
lwu t2, 4(t0)
|
||||
@@ -344,7 +401,7 @@ _fdt_reloc_done:
|
||||
|
||||
/* mark boot hart done */
|
||||
li t0, BOOT_STATUS_BOOT_HART_DONE
|
||||
la t1, _boot_status
|
||||
lla t1, _boot_status
|
||||
REG_S t0, 0(t1)
|
||||
fence rw, rw
|
||||
j _start_warm
|
||||
@@ -352,7 +409,7 @@ _fdt_reloc_done:
|
||||
/* waiting for boot hart to be done (_boot_status == 2) */
|
||||
_wait_for_boot_hart:
|
||||
li t0, BOOT_STATUS_BOOT_HART_DONE
|
||||
la t1, _boot_status
|
||||
lla t1, _boot_status
|
||||
REG_L t1, 0(t1)
|
||||
/* Reduce the bus traffic so that boot hart may proceed faster */
|
||||
nop
|
||||
@@ -370,7 +427,7 @@ _start_warm:
|
||||
csrw CSR_MIP, zero
|
||||
|
||||
/* Find HART count and HART stack size */
|
||||
la a4, platform
|
||||
lla a4, platform
|
||||
#if __riscv_xlen == 64
|
||||
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
|
||||
lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
|
||||
@@ -401,7 +458,7 @@ _start_warm:
|
||||
3: bge s6, s7, _start_hang
|
||||
|
||||
/* Find the scratch space based on HART index */
|
||||
la tp, _fw_end
|
||||
lla tp, _fw_end
|
||||
mul a5, s7, s8
|
||||
add tp, tp, a5
|
||||
mul a5, s8, s6
|
||||
@@ -416,9 +473,29 @@ _start_warm:
|
||||
add sp, tp, zero
|
||||
|
||||
/* Setup trap handler */
|
||||
la a4, _trap_handler
|
||||
lla a4, _trap_handler
|
||||
#if __riscv_xlen == 32
|
||||
csrr a5, CSR_MISA
|
||||
srli a5, a5, ('H' - 'A')
|
||||
andi a5, a5, 0x1
|
||||
beq a5, zero, _skip_trap_handler_rv32_hyp
|
||||
lla a4, _trap_handler_rv32_hyp
|
||||
_skip_trap_handler_rv32_hyp:
|
||||
#endif
|
||||
csrw CSR_MTVEC, a4
|
||||
|
||||
#if __riscv_xlen == 32
|
||||
/* Override trap exit for H-extension */
|
||||
csrr a5, CSR_MISA
|
||||
srli a5, a5, ('H' - 'A')
|
||||
andi a5, a5, 0x1
|
||||
beq a5, zero, _skip_trap_exit_rv32_hyp
|
||||
lla a4, _trap_exit_rv32_hyp
|
||||
csrr a5, CSR_MSCRATCH
|
||||
REG_S a4, SBI_SCRATCH_TRAP_EXIT_OFFSET(a5)
|
||||
_skip_trap_exit_rv32_hyp:
|
||||
#endif
|
||||
|
||||
/* Initialize SBI runtime */
|
||||
csrr a0, CSR_MSCRATCH
|
||||
call sbi_init
|
||||
@@ -426,7 +503,12 @@ _start_warm:
|
||||
/* We don't expect to reach here hence just hang */
|
||||
j _start_hang
|
||||
|
||||
.data
|
||||
.align 3
|
||||
#ifdef FW_PIC
|
||||
_runtime_offset:
|
||||
RISCV_PTR 0
|
||||
#endif
|
||||
_relocate_lottery:
|
||||
RISCV_PTR 0
|
||||
_boot_status:
|
||||
@@ -434,7 +516,7 @@ _boot_status:
|
||||
_load_start:
|
||||
RISCV_PTR _fw_start
|
||||
_link_start:
|
||||
RISCV_PTR _fw_start
|
||||
RISCV_PTR FW_TEXT_START
|
||||
_link_end:
|
||||
RISCV_PTR _fw_reloc_end
|
||||
|
||||
@@ -449,7 +531,7 @@ _hartid_to_scratch:
|
||||
* t1 -> HART Stack End
|
||||
* t2 -> Temporary
|
||||
*/
|
||||
la t2, platform
|
||||
lla t2, platform
|
||||
#if __riscv_xlen == 64
|
||||
lwu t0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(t2)
|
||||
lwu t2, SBI_PLATFORM_HART_COUNT_OFFSET(t2)
|
||||
@@ -459,7 +541,7 @@ _hartid_to_scratch:
|
||||
#endif
|
||||
sub t2, t2, a1
|
||||
mul t2, t2, t0
|
||||
la t1, _fw_end
|
||||
lla t1, _fw_end
|
||||
add t1, t1, t2
|
||||
li t2, SBI_SCRATCH_SIZE
|
||||
sub a0, t1, t2
|
||||
@@ -474,51 +556,70 @@ _start_hang:
|
||||
|
||||
.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
|
||||
/* Map implicit memcpy() added by compiler to sbi_memcpy() */
|
||||
.section .text
|
||||
.align 3
|
||||
.globl _trap_handler
|
||||
_trap_handler:
|
||||
.globl memcpy
|
||||
memcpy:
|
||||
tail sbi_memcpy
|
||||
|
||||
/* Map implicit memset() added by compiler to sbi_memset() */
|
||||
.section .text
|
||||
.align 3
|
||||
.globl memset
|
||||
memset:
|
||||
tail sbi_memset
|
||||
|
||||
/* Map implicit memmove() added by compiler to sbi_memmove() */
|
||||
.section .text
|
||||
.align 3
|
||||
.globl memmove
|
||||
memmove:
|
||||
tail sbi_memmove
|
||||
|
||||
/* Map implicit memcmp() added by compiler to sbi_memcmp() */
|
||||
.section .text
|
||||
.align 3
|
||||
.globl memcmp
|
||||
memcmp:
|
||||
tail sbi_memcmp
|
||||
|
||||
.macro TRAP_SAVE_AND_SETUP_SP_T0
|
||||
/* Swap TP and MSCRATCH */
|
||||
csrrw tp, CSR_MSCRATCH, tp
|
||||
|
||||
/* Save T0 in scratch space */
|
||||
REG_S t0, SBI_SCRATCH_TMP0_OFFSET(tp)
|
||||
|
||||
/* Check which mode we came from */
|
||||
/*
|
||||
* Set T0 to appropriate exception stack
|
||||
*
|
||||
* Came_From_M_Mode = ((MSTATUS.MPP < PRV_M) ? 1 : 0) - 1;
|
||||
* Exception_Stack = TP ^ (Came_From_M_Mode & (SP ^ TP))
|
||||
*
|
||||
* Came_From_M_Mode = 0 ==> Exception_Stack = TP
|
||||
* Came_From_M_Mode = -1 ==> Exception_Stack = SP
|
||||
*/
|
||||
csrr t0, CSR_MSTATUS
|
||||
srl t0, t0, MSTATUS_MPP_SHIFT
|
||||
and t0, t0, PRV_M
|
||||
xori t0, t0, PRV_M
|
||||
beq t0, zero, _trap_handler_m_mode
|
||||
slti t0, t0, PRV_M
|
||||
add t0, t0, -1
|
||||
xor sp, sp, tp
|
||||
and t0, t0, sp
|
||||
xor sp, sp, tp
|
||||
xor t0, tp, t0
|
||||
|
||||
/* We came from S-mode or U-mode */
|
||||
_trap_handler_s_mode:
|
||||
/* Set T0 to original SP */
|
||||
add t0, sp, zero
|
||||
/* Save original SP on exception stack */
|
||||
REG_S sp, (SBI_TRAP_REGS_OFFSET(sp) - SBI_TRAP_REGS_SIZE)(t0)
|
||||
|
||||
/* Setup exception stack */
|
||||
add sp, tp, -(SBI_TRAP_REGS_SIZE)
|
||||
|
||||
/* Jump to code common for all modes */
|
||||
j _trap_handler_all_mode
|
||||
|
||||
/* We came from M-mode */
|
||||
_trap_handler_m_mode:
|
||||
/* Set T0 to original SP */
|
||||
add t0, sp, zero
|
||||
|
||||
/* Re-use current SP as exception stack */
|
||||
add sp, sp, -(SBI_TRAP_REGS_SIZE)
|
||||
|
||||
_trap_handler_all_mode:
|
||||
/* Save original SP (from T0) on stack */
|
||||
REG_S t0, SBI_TRAP_REGS_OFFSET(sp)(sp)
|
||||
/* Set SP to exception stack and make room for trap registers */
|
||||
add sp, t0, -(SBI_TRAP_REGS_SIZE)
|
||||
|
||||
/* Restore T0 from scratch space */
|
||||
REG_L t0, SBI_SCRATCH_TMP0_OFFSET(tp)
|
||||
@@ -528,23 +629,23 @@ _trap_handler_all_mode:
|
||||
|
||||
/* Swap TP and MSCRATCH */
|
||||
csrrw tp, CSR_MSCRATCH, tp
|
||||
.endm
|
||||
|
||||
.macro TRAP_SAVE_MEPC_MSTATUS have_mstatush
|
||||
/* Save MEPC and MSTATUS CSRs */
|
||||
csrr t0, CSR_MEPC
|
||||
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
|
||||
.if \have_mstatush
|
||||
csrr t0, CSR_MSTATUSH
|
||||
REG_S t0, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
|
||||
_skip_mstatush_save:
|
||||
#endif
|
||||
.else
|
||||
REG_S zero, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
|
||||
.endif
|
||||
.endm
|
||||
|
||||
.macro TRAP_SAVE_GENERAL_REGS_EXCEPT_SP_T0
|
||||
/* Save all general regisers except SP and T0 */
|
||||
REG_S zero, SBI_TRAP_REGS_OFFSET(zero)(sp)
|
||||
REG_S ra, SBI_TRAP_REGS_OFFSET(ra)(sp)
|
||||
@@ -576,65 +677,113 @@ _skip_mstatush_save:
|
||||
REG_S t4, SBI_TRAP_REGS_OFFSET(t4)(sp)
|
||||
REG_S t5, SBI_TRAP_REGS_OFFSET(t5)(sp)
|
||||
REG_S t6, SBI_TRAP_REGS_OFFSET(t6)(sp)
|
||||
.endm
|
||||
|
||||
.macro TRAP_CALL_C_ROUTINE
|
||||
/* Call C routine */
|
||||
add a0, sp, zero
|
||||
call sbi_trap_handler
|
||||
.endm
|
||||
|
||||
/* Restore all general regisers except SP and T0 */
|
||||
REG_L ra, SBI_TRAP_REGS_OFFSET(ra)(sp)
|
||||
REG_L gp, SBI_TRAP_REGS_OFFSET(gp)(sp)
|
||||
REG_L tp, SBI_TRAP_REGS_OFFSET(tp)(sp)
|
||||
REG_L t1, SBI_TRAP_REGS_OFFSET(t1)(sp)
|
||||
REG_L t2, SBI_TRAP_REGS_OFFSET(t2)(sp)
|
||||
REG_L s0, SBI_TRAP_REGS_OFFSET(s0)(sp)
|
||||
REG_L s1, SBI_TRAP_REGS_OFFSET(s1)(sp)
|
||||
REG_L a0, SBI_TRAP_REGS_OFFSET(a0)(sp)
|
||||
REG_L a1, SBI_TRAP_REGS_OFFSET(a1)(sp)
|
||||
REG_L a2, SBI_TRAP_REGS_OFFSET(a2)(sp)
|
||||
REG_L a3, SBI_TRAP_REGS_OFFSET(a3)(sp)
|
||||
REG_L a4, SBI_TRAP_REGS_OFFSET(a4)(sp)
|
||||
REG_L a5, SBI_TRAP_REGS_OFFSET(a5)(sp)
|
||||
REG_L a6, SBI_TRAP_REGS_OFFSET(a6)(sp)
|
||||
REG_L a7, SBI_TRAP_REGS_OFFSET(a7)(sp)
|
||||
REG_L s2, SBI_TRAP_REGS_OFFSET(s2)(sp)
|
||||
REG_L s3, SBI_TRAP_REGS_OFFSET(s3)(sp)
|
||||
REG_L s4, SBI_TRAP_REGS_OFFSET(s4)(sp)
|
||||
REG_L s5, SBI_TRAP_REGS_OFFSET(s5)(sp)
|
||||
REG_L s6, SBI_TRAP_REGS_OFFSET(s6)(sp)
|
||||
REG_L s7, SBI_TRAP_REGS_OFFSET(s7)(sp)
|
||||
REG_L s8, SBI_TRAP_REGS_OFFSET(s8)(sp)
|
||||
REG_L s9, SBI_TRAP_REGS_OFFSET(s9)(sp)
|
||||
REG_L s10, SBI_TRAP_REGS_OFFSET(s10)(sp)
|
||||
REG_L s11, SBI_TRAP_REGS_OFFSET(s11)(sp)
|
||||
REG_L t3, SBI_TRAP_REGS_OFFSET(t3)(sp)
|
||||
REG_L t4, SBI_TRAP_REGS_OFFSET(t4)(sp)
|
||||
REG_L t5, SBI_TRAP_REGS_OFFSET(t5)(sp)
|
||||
REG_L t6, SBI_TRAP_REGS_OFFSET(t6)(sp)
|
||||
.macro TRAP_RESTORE_GENERAL_REGS_EXCEPT_A0_T0
|
||||
/* Restore all general regisers except A0 and T0 */
|
||||
REG_L ra, SBI_TRAP_REGS_OFFSET(ra)(a0)
|
||||
REG_L sp, SBI_TRAP_REGS_OFFSET(sp)(a0)
|
||||
REG_L gp, SBI_TRAP_REGS_OFFSET(gp)(a0)
|
||||
REG_L tp, SBI_TRAP_REGS_OFFSET(tp)(a0)
|
||||
REG_L t1, SBI_TRAP_REGS_OFFSET(t1)(a0)
|
||||
REG_L t2, SBI_TRAP_REGS_OFFSET(t2)(a0)
|
||||
REG_L s0, SBI_TRAP_REGS_OFFSET(s0)(a0)
|
||||
REG_L s1, SBI_TRAP_REGS_OFFSET(s1)(a0)
|
||||
REG_L a1, SBI_TRAP_REGS_OFFSET(a1)(a0)
|
||||
REG_L a2, SBI_TRAP_REGS_OFFSET(a2)(a0)
|
||||
REG_L a3, SBI_TRAP_REGS_OFFSET(a3)(a0)
|
||||
REG_L a4, SBI_TRAP_REGS_OFFSET(a4)(a0)
|
||||
REG_L a5, SBI_TRAP_REGS_OFFSET(a5)(a0)
|
||||
REG_L a6, SBI_TRAP_REGS_OFFSET(a6)(a0)
|
||||
REG_L a7, SBI_TRAP_REGS_OFFSET(a7)(a0)
|
||||
REG_L s2, SBI_TRAP_REGS_OFFSET(s2)(a0)
|
||||
REG_L s3, SBI_TRAP_REGS_OFFSET(s3)(a0)
|
||||
REG_L s4, SBI_TRAP_REGS_OFFSET(s4)(a0)
|
||||
REG_L s5, SBI_TRAP_REGS_OFFSET(s5)(a0)
|
||||
REG_L s6, SBI_TRAP_REGS_OFFSET(s6)(a0)
|
||||
REG_L s7, SBI_TRAP_REGS_OFFSET(s7)(a0)
|
||||
REG_L s8, SBI_TRAP_REGS_OFFSET(s8)(a0)
|
||||
REG_L s9, SBI_TRAP_REGS_OFFSET(s9)(a0)
|
||||
REG_L s10, SBI_TRAP_REGS_OFFSET(s10)(a0)
|
||||
REG_L s11, SBI_TRAP_REGS_OFFSET(s11)(a0)
|
||||
REG_L t3, SBI_TRAP_REGS_OFFSET(t3)(a0)
|
||||
REG_L t4, SBI_TRAP_REGS_OFFSET(t4)(a0)
|
||||
REG_L t5, SBI_TRAP_REGS_OFFSET(t5)(a0)
|
||||
REG_L t6, SBI_TRAP_REGS_OFFSET(t6)(a0)
|
||||
.endm
|
||||
|
||||
.macro TRAP_RESTORE_MEPC_MSTATUS have_mstatush
|
||||
/* Restore MEPC and MSTATUS CSRs */
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(mepc)(sp)
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(mepc)(a0)
|
||||
csrw CSR_MEPC, t0
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatus)(a0)
|
||||
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)
|
||||
.if \have_mstatush
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatusH)(a0)
|
||||
csrw CSR_MSTATUSH, t0
|
||||
_skip_mstatush_restore:
|
||||
#endif
|
||||
.endif
|
||||
.endm
|
||||
|
||||
.macro TRAP_RESTORE_A0_T0
|
||||
/* Restore T0 */
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(t0)(sp)
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(t0)(a0)
|
||||
|
||||
/* Restore SP */
|
||||
REG_L sp, SBI_TRAP_REGS_OFFSET(sp)(sp)
|
||||
/* Restore A0 */
|
||||
REG_L a0, SBI_TRAP_REGS_OFFSET(a0)(a0)
|
||||
.endm
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _trap_handler
|
||||
.globl _trap_exit
|
||||
_trap_handler:
|
||||
TRAP_SAVE_AND_SETUP_SP_T0
|
||||
|
||||
TRAP_SAVE_MEPC_MSTATUS 0
|
||||
|
||||
TRAP_SAVE_GENERAL_REGS_EXCEPT_SP_T0
|
||||
|
||||
TRAP_CALL_C_ROUTINE
|
||||
|
||||
_trap_exit:
|
||||
TRAP_RESTORE_GENERAL_REGS_EXCEPT_A0_T0
|
||||
|
||||
TRAP_RESTORE_MEPC_MSTATUS 0
|
||||
|
||||
TRAP_RESTORE_A0_T0
|
||||
|
||||
mret
|
||||
|
||||
#if __riscv_xlen == 32
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _trap_handler_rv32_hyp
|
||||
.globl _trap_exit_rv32_hyp
|
||||
_trap_handler_rv32_hyp:
|
||||
TRAP_SAVE_AND_SETUP_SP_T0
|
||||
|
||||
TRAP_SAVE_MEPC_MSTATUS 1
|
||||
|
||||
TRAP_SAVE_GENERAL_REGS_EXCEPT_SP_T0
|
||||
|
||||
TRAP_CALL_C_ROUTINE
|
||||
|
||||
_trap_exit_rv32_hyp:
|
||||
TRAP_RESTORE_GENERAL_REGS_EXCEPT_A0_T0
|
||||
|
||||
TRAP_RESTORE_MEPC_MSTATUS 1
|
||||
|
||||
TRAP_RESTORE_A0_T0
|
||||
|
||||
mret
|
||||
#endif
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _reset_regs
|
||||
@@ -673,3 +822,14 @@ _reset_regs:
|
||||
csrw CSR_MSCRATCH, 0
|
||||
|
||||
ret
|
||||
|
||||
#ifdef FW_FDT_PATH
|
||||
.section .rodata
|
||||
.align 4
|
||||
.globl fw_fdt_bin
|
||||
fw_fdt_bin:
|
||||
.incbin FW_FDT_PATH
|
||||
#ifdef FW_FDT_PADDING
|
||||
.fill FW_FDT_PADDING, 1, 0
|
||||
#endif
|
||||
#endif
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
. = FW_TEXT_START;
|
||||
|
||||
/* Don't add any section between FW_TEXT_START and _fw_start */
|
||||
PROVIDE(_fw_start = .);
|
||||
|
||||
. = ALIGN(0x1000); /* Need this to create proper sections */
|
||||
@@ -61,6 +61,19 @@
|
||||
PROVIDE(_data_end = .);
|
||||
}
|
||||
|
||||
.dynsym : {
|
||||
PROVIDE(__dyn_sym_start = .);
|
||||
*(.dynsym)
|
||||
PROVIDE(__dyn_sym_end = .);
|
||||
}
|
||||
|
||||
.rela.dyn : {
|
||||
PROVIDE(__rel_dyn_start = .);
|
||||
*(.rela*)
|
||||
. = ALIGN(8);
|
||||
PROVIDE(__rel_dyn_end = .);
|
||||
}
|
||||
|
||||
. = ALIGN(0x1000); /* Ensure next section is page aligned */
|
||||
|
||||
.bss :
|
||||
|
@@ -36,7 +36,7 @@ fw_boot_hart:
|
||||
bgt a0, a1, _bad_dynamic_info
|
||||
|
||||
/* Read boot HART id */
|
||||
li a1, 0x2
|
||||
li a1, FW_DYNAMIC_INFO_VERSION_2
|
||||
blt a0, a1, 2f
|
||||
REG_L a0, FW_DYNAMIC_INFO_BOOT_HART_OFFSET(a2)
|
||||
ret
|
||||
@@ -54,51 +54,30 @@ fw_boot_hart:
|
||||
*/
|
||||
fw_save_info:
|
||||
/* Save next arg1 in 'a1' */
|
||||
la a4, _dynamic_next_arg1
|
||||
lla 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
|
||||
lla a4, _dynamic_next_addr
|
||||
REG_L a3, FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET(a2)
|
||||
REG_S a3, (a4)
|
||||
la a4, _dynamic_next_mode
|
||||
lla a4, _dynamic_next_mode
|
||||
REG_L a3, FW_DYNAMIC_INFO_NEXT_MODE_OFFSET(a2)
|
||||
REG_S a3, (a4)
|
||||
la a4, _dynamic_options
|
||||
lla a4, _dynamic_options
|
||||
REG_L a3, FW_DYNAMIC_INFO_OPTIONS_OFFSET(a2)
|
||||
REG_S a3, (a4)
|
||||
|
||||
/* Save version == 0x2 fields */
|
||||
li a4, 0x2
|
||||
li a4, FW_DYNAMIC_INFO_VERSION_2
|
||||
REG_L a3, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
|
||||
blt a3, a4, 2f
|
||||
la a4, _dynamic_boot_hart
|
||||
lla a4, _dynamic_boot_hart
|
||||
REG_L a3, FW_DYNAMIC_INFO_BOOT_HART_OFFSET(a2)
|
||||
REG_S a3, (a4)
|
||||
2:
|
||||
ret
|
||||
|
||||
.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
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_arg1
|
||||
@@ -109,7 +88,7 @@ fw_prev_arg1:
|
||||
* The next arg1 should be returned in 'a0'.
|
||||
*/
|
||||
fw_next_arg1:
|
||||
la a0, _dynamic_next_arg1
|
||||
lla a0, _dynamic_next_arg1
|
||||
REG_L a0, (a0)
|
||||
ret
|
||||
|
||||
@@ -121,7 +100,7 @@ fw_next_arg1:
|
||||
* The next address should be returned in 'a0'.
|
||||
*/
|
||||
fw_next_addr:
|
||||
la a0, _dynamic_next_addr
|
||||
lla a0, _dynamic_next_addr
|
||||
REG_L a0, (a0)
|
||||
ret
|
||||
|
||||
@@ -133,7 +112,7 @@ fw_next_addr:
|
||||
* The next address should be returned in 'a0'
|
||||
*/
|
||||
fw_next_mode:
|
||||
la a0, _dynamic_next_mode
|
||||
lla a0, _dynamic_next_mode
|
||||
REG_L a0, (a0)
|
||||
ret
|
||||
|
||||
@@ -146,7 +125,7 @@ fw_next_mode:
|
||||
* The next address should be returned in 'a0'.
|
||||
*/
|
||||
fw_options:
|
||||
la a0, _dynamic_options
|
||||
lla a0, _dynamic_options
|
||||
REG_L a0, (a0)
|
||||
ret
|
||||
|
||||
|
@@ -34,19 +34,6 @@ fw_boot_hart:
|
||||
fw_save_info:
|
||||
ret
|
||||
|
||||
.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
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_arg1
|
||||
@@ -72,7 +59,7 @@ fw_next_arg1:
|
||||
* The next address should be returned in 'a0'.
|
||||
*/
|
||||
fw_next_addr:
|
||||
la a0, _jump_addr
|
||||
lla a0, _jump_addr
|
||||
REG_L a0, (a0)
|
||||
ret
|
||||
|
||||
|
@@ -34,23 +34,6 @@ fw_boot_hart:
|
||||
fw_save_info:
|
||||
ret
|
||||
|
||||
.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:
|
||||
#ifdef FW_PAYLOAD_FDT_PATH
|
||||
la a0, fdt_bin
|
||||
#else
|
||||
add a0, zero, zero
|
||||
#endif
|
||||
ret
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_arg1
|
||||
@@ -76,7 +59,7 @@ fw_next_arg1:
|
||||
* The next address should be returned in 'a0'.
|
||||
*/
|
||||
fw_next_addr:
|
||||
la a0, payload_bin
|
||||
lla a0, payload_bin
|
||||
ret
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
@@ -102,14 +85,6 @@ fw_options:
|
||||
add a0, zero, zero
|
||||
ret
|
||||
|
||||
#ifdef FW_PAYLOAD_FDT_PATH
|
||||
.section .text, "ax", %progbits
|
||||
.align 4
|
||||
.globl fdt_bin
|
||||
fdt_bin:
|
||||
.incbin FW_PAYLOAD_FDT_PATH
|
||||
#endif
|
||||
|
||||
.section .payload, "ax", %progbits
|
||||
.align 4
|
||||
.globl payload_bin
|
||||
|
@@ -13,10 +13,28 @@ firmware-cflags-y +=
|
||||
firmware-asflags-y +=
|
||||
firmware-ldflags-y +=
|
||||
|
||||
ifndef FW_PIC
|
||||
FW_PIC := $(OPENSBI_LD_PIE)
|
||||
endif
|
||||
|
||||
ifeq ($(FW_PIC),y)
|
||||
firmware-genflags-y += -DFW_PIC
|
||||
firmware-asflags-y += -fpic
|
||||
firmware-cflags-y += -fPIE -pie
|
||||
firmware-ldflags-y += -Wl,--no-dynamic-linker -Wl,-pie
|
||||
endif
|
||||
|
||||
ifdef FW_TEXT_START
|
||||
firmware-genflags-y += -DFW_TEXT_START=$(FW_TEXT_START)
|
||||
endif
|
||||
|
||||
ifdef FW_FDT_PATH
|
||||
firmware-genflags-y += -DFW_FDT_PATH=\"$(FW_FDT_PATH)\"
|
||||
ifdef FW_FDT_PADDING
|
||||
firmware-genflags-y += -DFW_FDT_PADDING=$(FW_FDT_PADDING)
|
||||
endif
|
||||
endif
|
||||
|
||||
firmware-bins-$(FW_DYNAMIC) += fw_dynamic.bin
|
||||
|
||||
firmware-bins-$(FW_JUMP) += fw_jump.bin
|
||||
@@ -41,9 +59,6 @@ ifdef FW_PAYLOAD_ALIGN
|
||||
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_ALIGN=$(FW_PAYLOAD_ALIGN)
|
||||
endif
|
||||
|
||||
ifdef FW_PAYLOAD_FDT_PATH
|
||||
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_FDT_PATH=\"$(FW_PAYLOAD_FDT_PATH)\"
|
||||
endif
|
||||
ifdef FW_PAYLOAD_FDT_ADDR
|
||||
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_FDT_ADDR=$(FW_PAYLOAD_FDT_ADDR)
|
||||
endif
|
||||
|
@@ -28,20 +28,20 @@
|
||||
.globl _start
|
||||
_start:
|
||||
/* Pick one hart to run the main boot sequence */
|
||||
la a3, _hart_lottery
|
||||
lla a3, _hart_lottery
|
||||
li a2, 1
|
||||
amoadd.w a3, a2, (a3)
|
||||
bnez a3, _start_hang
|
||||
|
||||
/* Save a0 and a1 */
|
||||
la a3, _boot_a0
|
||||
lla a3, _boot_a0
|
||||
REG_S a0, 0(a3)
|
||||
la a3, _boot_a1
|
||||
lla a3, _boot_a1
|
||||
REG_S a1, 0(a3)
|
||||
|
||||
/* Zero-out BSS */
|
||||
la a4, _bss_start
|
||||
la a5, _bss_end
|
||||
lla a4, _bss_start
|
||||
lla a5, _bss_end
|
||||
_bss_zero:
|
||||
REG_S zero, (a4)
|
||||
add a4, a4, __SIZEOF_POINTER__
|
||||
@@ -53,18 +53,18 @@ _start_warm:
|
||||
csrw CSR_SIP, zero
|
||||
|
||||
/* Setup exception vectors */
|
||||
la a3, _start_hang
|
||||
lla a3, _start_hang
|
||||
csrw CSR_STVEC, a3
|
||||
|
||||
/* Setup stack */
|
||||
la a3, _payload_end
|
||||
lla a3, _payload_end
|
||||
li a4, 0x2000
|
||||
add sp, a3, a4
|
||||
|
||||
/* Jump to C main */
|
||||
la a3, _boot_a0
|
||||
lla a3, _boot_a0
|
||||
REG_L a0, 0(a3)
|
||||
la a3, _boot_a1
|
||||
lla a3, _boot_a1
|
||||
REG_L a1, 0(a3)
|
||||
call test_main
|
||||
|
||||
|
@@ -9,24 +9,25 @@
|
||||
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
|
||||
#define SBI_ECALL(__num, __a0, __a1, __a2) \
|
||||
#define SBI_ECALL(__eid, __fid, __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); \
|
||||
register unsigned long a6 asm("a6") = (unsigned long)(__fid); \
|
||||
register unsigned long a7 asm("a7") = (unsigned long)(__eid); \
|
||||
asm volatile("ecall" \
|
||||
: "+r"(a0) \
|
||||
: "r"(a1), "r"(a2), "r"(a7) \
|
||||
: "r"(a1), "r"(a2), "r"(a6), "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_0(__eid, __fid) SBI_ECALL(__eid, __fid, 0, 0, 0)
|
||||
#define SBI_ECALL_1(__eid, __fid, __a0) SBI_ECALL(__eid, __fid, __a0, 0, 0)
|
||||
#define SBI_ECALL_2(__eid, __fid, __a0, __a1) SBI_ECALL(__eid, __fid, __a0, __a1, 0)
|
||||
|
||||
#define sbi_ecall_console_putc(c) SBI_ECALL_1(SBI_EXT_0_1_CONSOLE_PUTCHAR, (c))
|
||||
#define sbi_ecall_console_putc(c) SBI_ECALL_1(SBI_EXT_0_1_CONSOLE_PUTCHAR, 0, (c))
|
||||
|
||||
static inline void sbi_ecall_console_puts(const char *str)
|
||||
{
|
||||
|
@@ -15,23 +15,24 @@
|
||||
/* clang-format off */
|
||||
|
||||
/** Offset of magic member in fw_dynamic_info */
|
||||
#define FW_DYNAMIC_INFO_MAGIC_OFFSET (0 * __SIZEOF_POINTER__)
|
||||
#define FW_DYNAMIC_INFO_MAGIC_OFFSET (0 * __SIZEOF_LONG__)
|
||||
/** Offset of version member in fw_dynamic_info */
|
||||
#define FW_DYNAMIC_INFO_VERSION_OFFSET (1 * __SIZEOF_POINTER__)
|
||||
#define FW_DYNAMIC_INFO_VERSION_OFFSET (1 * __SIZEOF_LONG__)
|
||||
/** Offset of next_addr member in fw_dynamic_info (version >= 1) */
|
||||
#define FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET (2 * __SIZEOF_POINTER__)
|
||||
#define FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET (2 * __SIZEOF_LONG__)
|
||||
/** Offset of next_mode member in fw_dynamic_info (version >= 1) */
|
||||
#define FW_DYNAMIC_INFO_NEXT_MODE_OFFSET (3 * __SIZEOF_POINTER__)
|
||||
#define FW_DYNAMIC_INFO_NEXT_MODE_OFFSET (3 * __SIZEOF_LONG__)
|
||||
/** Offset of options member in fw_dynamic_info (version >= 1) */
|
||||
#define FW_DYNAMIC_INFO_OPTIONS_OFFSET (4 * __SIZEOF_POINTER__)
|
||||
#define FW_DYNAMIC_INFO_OPTIONS_OFFSET (4 * __SIZEOF_LONG__)
|
||||
/** Offset of boot_hart member in fw_dynamic_info (version >= 2) */
|
||||
#define FW_DYNAMIC_INFO_BOOT_HART_OFFSET (5 * __SIZEOF_POINTER__)
|
||||
#define FW_DYNAMIC_INFO_BOOT_HART_OFFSET (5 * __SIZEOF_LONG__)
|
||||
|
||||
/** 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 0x2
|
||||
#define FW_DYNAMIC_INFO_VERSION_2 0x2
|
||||
#define FW_DYNAMIC_INFO_VERSION_MAX FW_DYNAMIC_INFO_VERSION_2
|
||||
|
||||
/** Possible next mode values */
|
||||
#define FW_DYNAMIC_INFO_NEXT_MODE_U 0x0
|
||||
@@ -40,7 +41,7 @@
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
|
@@ -14,7 +14,7 @@
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#ifdef __ASSEMBLY__
|
||||
#ifdef __ASSEMBLER__
|
||||
#define __ASM_STR(x) x
|
||||
#else
|
||||
#define __ASM_STR(x) #x
|
||||
@@ -38,7 +38,7 @@
|
||||
#define LGREG __REG_SEL(3, 2)
|
||||
|
||||
#if __SIZEOF_POINTER__ == 8
|
||||
#ifdef __ASSEMBLY__
|
||||
#ifdef __ASSEMBLER__
|
||||
#define RISCV_PTR .dword
|
||||
#define RISCV_SZPTR 8
|
||||
#define RISCV_LGPTR 3
|
||||
@@ -48,7 +48,7 @@
|
||||
#define RISCV_LGPTR "3"
|
||||
#endif
|
||||
#elif __SIZEOF_POINTER__ == 4
|
||||
#ifdef __ASSEMBLY__
|
||||
#ifdef __ASSEMBLER__
|
||||
#define RISCV_PTR .word
|
||||
#define RISCV_SZPTR 4
|
||||
#define RISCV_LGPTR 2
|
||||
@@ -79,7 +79,7 @@
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#define csr_swap(csr, val) \
|
||||
({ \
|
||||
@@ -157,6 +157,11 @@ void csr_write_num(int csr_num, unsigned long val);
|
||||
__asm__ __volatile__("wfi" ::: "memory"); \
|
||||
} while (0)
|
||||
|
||||
#define ebreak() \
|
||||
do { \
|
||||
__asm__ __volatile__("ebreak" ::: "memory"); \
|
||||
} while (0)
|
||||
|
||||
/* Get current HART id */
|
||||
#define current_hartid() ((unsigned int)csr_read(CSR_MHARTID))
|
||||
|
||||
@@ -180,8 +185,8 @@ 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 *size);
|
||||
unsigned long *log2len);
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
#endif /* !__ASSEMBLER__ */
|
||||
|
||||
#endif
|
||||
|
@@ -18,6 +18,9 @@
|
||||
#define RISCV_FENCE(p, s) \
|
||||
__asm__ __volatile__ ("fence " #p "," #s : : : "memory")
|
||||
|
||||
#define RISCV_FENCE_I \
|
||||
__asm__ __volatile__ ("fence.i" : : : "memory")
|
||||
|
||||
/* Read & Write Memory barrier */
|
||||
#define mb() RISCV_FENCE(iorw,iorw)
|
||||
|
||||
|
14
include/sbi/riscv_elf.h
Normal file
14
include/sbi/riscv_elf.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef __RISCV_ELF_H__
|
||||
#define __RISCV_ELF_H__
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
|
||||
#define R_RISCV_32 1
|
||||
#define R_RISCV_64 2
|
||||
#define R_RISCV_RELATIVE 3
|
||||
|
||||
#define RELOC_TYPE __REG_SEL(R_RISCV_64, R_RISCV_32)
|
||||
#define SYM_INDEX __REG_SEL(0x20, 0x8)
|
||||
#define SYM_SIZE __REG_SEL(0x18,0x10)
|
||||
|
||||
#endif
|
@@ -86,6 +86,7 @@
|
||||
#define IRQ_VS_EXT 10
|
||||
#define IRQ_M_EXT 11
|
||||
#define IRQ_S_GEXT 12
|
||||
#define IRQ_PMU_OVF 13
|
||||
|
||||
#define MIP_SSIP (_UL(1) << IRQ_S_SOFT)
|
||||
#define MIP_VSSIP (_UL(1) << IRQ_VS_SOFT)
|
||||
@@ -97,6 +98,7 @@
|
||||
#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 MIP_LCOFIP (_UL(1) << IRQ_PMU_OVF)
|
||||
|
||||
#define SIP_SSIP MIP_SSIP
|
||||
#define SIP_STIP MIP_STIP
|
||||
@@ -144,7 +146,12 @@
|
||||
#define PMP_L _UL(0x80)
|
||||
|
||||
#define PMP_SHIFT 2
|
||||
#define PMP_COUNT 16
|
||||
#define PMP_COUNT 64
|
||||
#if __riscv_xlen == 64
|
||||
#define PMP_ADDR_MASK ((_ULL(0x1) << 54) - 1)
|
||||
#else
|
||||
#define PMP_ADDR_MASK _UL(0xFFFFFFFF)
|
||||
#endif
|
||||
|
||||
#if __riscv_xlen == 64
|
||||
#define MSTATUS_SD MSTATUS64_SD
|
||||
@@ -166,18 +173,52 @@
|
||||
#define HGATP_MODE_SHIFT HGATP32_MODE_SHIFT
|
||||
#endif
|
||||
|
||||
#define CSR_USTATUS 0x0
|
||||
#define CSR_FFLAGS 0x1
|
||||
#define CSR_FRM 0x2
|
||||
#define CSR_FCSR 0x3
|
||||
#if __riscv_xlen == 64
|
||||
#define MHPMEVENT_OF (_UL(1) << 63)
|
||||
#define MHPMEVENT_MINH (_UL(1) << 62)
|
||||
#define MHPMEVENT_SINH (_UL(1) << 61)
|
||||
#define MHPMEVENT_UINH (_UL(1) << 60)
|
||||
#define MHPMEVENT_VSINH (_UL(1) << 59)
|
||||
#define MHPMEVENT_VUINH (_UL(1) << 58)
|
||||
#else
|
||||
#define MHPMEVENTH_OF (_UL(1) << 31)
|
||||
#define MHPMEVENTH_MINH (_ULL(1) << 30)
|
||||
#define MHPMEVENTH_SINH (_ULL(1) << 29)
|
||||
#define MHPMEVENTH_UINH (_ULL(1) << 28)
|
||||
#define MHPMEVENTH_VSINH (_ULL(1) << 27)
|
||||
#define MHPMEVENTH_VUINH (_ULL(1) << 26)
|
||||
|
||||
#define MHPMEVENT_MINH (MHPMEVENTH_MINH << 32)
|
||||
#define MHPMEVENT_SINH (MHPMEVENTH_SINH << 32)
|
||||
#define MHPMEVENT_UINH (MHPMEVENTH_UINH << 32)
|
||||
#define MHPMEVENT_VSINH (MHPMEVENTH_VSINH << 32)
|
||||
#define MHPMEVENT_VUINH (MHPMEVENTH_VUINH << 32)
|
||||
|
||||
#endif
|
||||
|
||||
#define MHPMEVENT_SSCOF_MASK _ULL(0xFFFF000000000000)
|
||||
|
||||
/* ===== User-level CSRs ===== */
|
||||
|
||||
/* User Trap Setup (N-extension) */
|
||||
#define CSR_USTATUS 0x000
|
||||
#define CSR_UIE 0x004
|
||||
#define CSR_UTVEC 0x005
|
||||
|
||||
/* User Trap Handling (N-extension) */
|
||||
#define CSR_USCRATCH 0x040
|
||||
#define CSR_UEPC 0x041
|
||||
#define CSR_UCAUSE 0x042
|
||||
#define CSR_UTVAL 0x043
|
||||
#define CSR_UIP 0x044
|
||||
|
||||
/* User Floating-point CSRs */
|
||||
#define CSR_FFLAGS 0x001
|
||||
#define CSR_FRM 0x002
|
||||
#define CSR_FCSR 0x003
|
||||
|
||||
/* User Counters/Timers */
|
||||
#define CSR_CYCLE 0xc00
|
||||
#define CSR_UIE 0x4
|
||||
#define CSR_UTVEC 0x5
|
||||
#define CSR_USCRATCH 0x40
|
||||
#define CSR_UEPC 0x41
|
||||
#define CSR_UCAUSE 0x42
|
||||
#define CSR_UTVAL 0x43
|
||||
#define CSR_UIP 0x44
|
||||
#define CSR_TIME 0xc01
|
||||
#define CSR_INSTRET 0xc02
|
||||
#define CSR_HPMCOUNTER3 0xc03
|
||||
@@ -209,148 +250,6 @@
|
||||
#define CSR_HPMCOUNTER29 0xc1d
|
||||
#define CSR_HPMCOUNTER30 0xc1e
|
||||
#define CSR_HPMCOUNTER31 0xc1f
|
||||
#define CSR_SSTATUS 0x100
|
||||
#define CSR_SIE 0x104
|
||||
#define CSR_STVEC 0x105
|
||||
#define CSR_SCOUNTEREN 0x106
|
||||
#define CSR_SSCRATCH 0x140
|
||||
#define CSR_SEPC 0x141
|
||||
#define CSR_SCAUSE 0x142
|
||||
#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
|
||||
#define CSR_MIDELEG 0x303
|
||||
#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
|
||||
#define CSR_PMPCFG3 0x3a3
|
||||
#define CSR_PMPADDR0 0x3b0
|
||||
#define CSR_PMPADDR1 0x3b1
|
||||
#define CSR_PMPADDR2 0x3b2
|
||||
#define CSR_PMPADDR3 0x3b3
|
||||
#define CSR_PMPADDR4 0x3b4
|
||||
#define CSR_PMPADDR5 0x3b5
|
||||
#define CSR_PMPADDR6 0x3b6
|
||||
#define CSR_PMPADDR7 0x3b7
|
||||
#define CSR_PMPADDR8 0x3b8
|
||||
#define CSR_PMPADDR9 0x3b9
|
||||
#define CSR_PMPADDR10 0x3ba
|
||||
#define CSR_PMPADDR11 0x3bb
|
||||
#define CSR_PMPADDR12 0x3bc
|
||||
#define CSR_PMPADDR13 0x3bd
|
||||
#define CSR_PMPADDR14 0x3be
|
||||
#define CSR_PMPADDR15 0x3bf
|
||||
#define CSR_TSELECT 0x7a0
|
||||
#define CSR_TDATA1 0x7a1
|
||||
#define CSR_TDATA2 0x7a2
|
||||
#define CSR_TDATA3 0x7a3
|
||||
#define CSR_DCSR 0x7b0
|
||||
#define CSR_DPC 0x7b1
|
||||
#define CSR_DSCRATCH 0x7b2
|
||||
|
||||
#define CSR_MCYCLE 0xb00
|
||||
#define CSR_MINSTRET 0xb02
|
||||
#define CSR_MHPMCOUNTER3 0xb03
|
||||
#define CSR_MHPMCOUNTER4 0xb04
|
||||
#define CSR_MHPMCOUNTER5 0xb05
|
||||
#define CSR_MHPMCOUNTER6 0xb06
|
||||
#define CSR_MHPMCOUNTER7 0xb07
|
||||
#define CSR_MHPMCOUNTER8 0xb08
|
||||
#define CSR_MHPMCOUNTER9 0xb09
|
||||
#define CSR_MHPMCOUNTER10 0xb0a
|
||||
#define CSR_MHPMCOUNTER11 0xb0b
|
||||
#define CSR_MHPMCOUNTER12 0xb0c
|
||||
#define CSR_MHPMCOUNTER13 0xb0d
|
||||
#define CSR_MHPMCOUNTER14 0xb0e
|
||||
#define CSR_MHPMCOUNTER15 0xb0f
|
||||
#define CSR_MHPMCOUNTER16 0xb10
|
||||
#define CSR_MHPMCOUNTER17 0xb11
|
||||
#define CSR_MHPMCOUNTER18 0xb12
|
||||
#define CSR_MHPMCOUNTER19 0xb13
|
||||
#define CSR_MHPMCOUNTER20 0xb14
|
||||
#define CSR_MHPMCOUNTER21 0xb15
|
||||
#define CSR_MHPMCOUNTER22 0xb16
|
||||
#define CSR_MHPMCOUNTER23 0xb17
|
||||
#define CSR_MHPMCOUNTER24 0xb18
|
||||
#define CSR_MHPMCOUNTER25 0xb19
|
||||
#define CSR_MHPMCOUNTER26 0xb1a
|
||||
#define CSR_MHPMCOUNTER27 0xb1b
|
||||
#define CSR_MHPMCOUNTER28 0xb1c
|
||||
#define CSR_MHPMCOUNTER29 0xb1d
|
||||
#define CSR_MHPMCOUNTER30 0xb1e
|
||||
#define CSR_MHPMCOUNTER31 0xb1f
|
||||
#define CSR_MHPMEVENT3 0x323
|
||||
#define CSR_MHPMEVENT4 0x324
|
||||
#define CSR_MHPMEVENT5 0x325
|
||||
#define CSR_MHPMEVENT6 0x326
|
||||
#define CSR_MHPMEVENT7 0x327
|
||||
#define CSR_MHPMEVENT8 0x328
|
||||
#define CSR_MHPMEVENT9 0x329
|
||||
#define CSR_MHPMEVENT10 0x32a
|
||||
#define CSR_MHPMEVENT11 0x32b
|
||||
#define CSR_MHPMEVENT12 0x32c
|
||||
#define CSR_MHPMEVENT13 0x32d
|
||||
#define CSR_MHPMEVENT14 0x32e
|
||||
#define CSR_MHPMEVENT15 0x32f
|
||||
#define CSR_MHPMEVENT16 0x330
|
||||
#define CSR_MHPMEVENT17 0x331
|
||||
#define CSR_MHPMEVENT18 0x332
|
||||
#define CSR_MHPMEVENT19 0x333
|
||||
#define CSR_MHPMEVENT20 0x334
|
||||
#define CSR_MHPMEVENT21 0x335
|
||||
#define CSR_MHPMEVENT22 0x336
|
||||
#define CSR_MHPMEVENT23 0x337
|
||||
#define CSR_MHPMEVENT24 0x338
|
||||
#define CSR_MHPMEVENT25 0x339
|
||||
#define CSR_MHPMEVENT26 0x33a
|
||||
#define CSR_MHPMEVENT27 0x33b
|
||||
#define CSR_MHPMEVENT28 0x33c
|
||||
#define CSR_MHPMEVENT29 0x33d
|
||||
#define CSR_MHPMEVENT30 0x33e
|
||||
#define CSR_MHPMEVENT31 0x33f
|
||||
#define CSR_MVENDORID 0xf11
|
||||
#define CSR_MARCHID 0xf12
|
||||
#define CSR_MIMPID 0xf13
|
||||
#define CSR_MHARTID 0xf14
|
||||
#define CSR_CYCLEH 0xc80
|
||||
#define CSR_TIMEH 0xc81
|
||||
#define CSR_INSTRETH 0xc82
|
||||
@@ -383,6 +282,203 @@
|
||||
#define CSR_HPMCOUNTER29H 0xc9d
|
||||
#define CSR_HPMCOUNTER30H 0xc9e
|
||||
#define CSR_HPMCOUNTER31H 0xc9f
|
||||
|
||||
/* ===== Supervisor-level CSRs ===== */
|
||||
|
||||
/* Supervisor Trap Setup */
|
||||
#define CSR_SSTATUS 0x100
|
||||
#define CSR_SEDELEG 0x102
|
||||
#define CSR_SIDELEG 0x103
|
||||
#define CSR_SIE 0x104
|
||||
#define CSR_STVEC 0x105
|
||||
#define CSR_SCOUNTEREN 0x106
|
||||
|
||||
/* Supervisor Trap Handling */
|
||||
#define CSR_SSCRATCH 0x140
|
||||
#define CSR_SEPC 0x141
|
||||
#define CSR_SCAUSE 0x142
|
||||
#define CSR_STVAL 0x143
|
||||
#define CSR_SIP 0x144
|
||||
|
||||
/* Supervisor Protection and Translation */
|
||||
#define CSR_SATP 0x180
|
||||
|
||||
/* ===== Hypervisor-level CSRs ===== */
|
||||
|
||||
/* Hypervisor Trap Setup (H-extension) */
|
||||
#define CSR_HSTATUS 0x600
|
||||
#define CSR_HEDELEG 0x602
|
||||
#define CSR_HIDELEG 0x603
|
||||
#define CSR_HIE 0x604
|
||||
#define CSR_HCOUNTEREN 0x606
|
||||
#define CSR_HGEIE 0x607
|
||||
|
||||
/* Hypervisor Trap Handling (H-extension) */
|
||||
#define CSR_HTVAL 0x643
|
||||
#define CSR_HIP 0x644
|
||||
#define CSR_HVIP 0x645
|
||||
#define CSR_HTINST 0x64a
|
||||
#define CSR_HGEIP 0xe12
|
||||
|
||||
/* Hypervisor Protection and Translation (H-extension) */
|
||||
#define CSR_HGATP 0x680
|
||||
|
||||
/* Hypervisor Counter/Timer Virtualization Registers (H-extension) */
|
||||
#define CSR_HTIMEDELTA 0x605
|
||||
#define CSR_HTIMEDELTAH 0x615
|
||||
|
||||
/* Virtual Supervisor Registers (H-extension) */
|
||||
#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
|
||||
|
||||
/* ===== Machine-level CSRs ===== */
|
||||
|
||||
/* Machine Information Registers */
|
||||
#define CSR_MVENDORID 0xf11
|
||||
#define CSR_MARCHID 0xf12
|
||||
#define CSR_MIMPID 0xf13
|
||||
#define CSR_MHARTID 0xf14
|
||||
|
||||
/* Machine Trap Setup */
|
||||
#define CSR_MSTATUS 0x300
|
||||
#define CSR_MISA 0x301
|
||||
#define CSR_MEDELEG 0x302
|
||||
#define CSR_MIDELEG 0x303
|
||||
#define CSR_MIE 0x304
|
||||
#define CSR_MTVEC 0x305
|
||||
#define CSR_MCOUNTEREN 0x306
|
||||
#define CSR_MSTATUSH 0x310
|
||||
|
||||
/* Machine Trap Handling */
|
||||
#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
|
||||
|
||||
/* Machine Memory Protection */
|
||||
#define CSR_PMPCFG0 0x3a0
|
||||
#define CSR_PMPCFG1 0x3a1
|
||||
#define CSR_PMPCFG2 0x3a2
|
||||
#define CSR_PMPCFG3 0x3a3
|
||||
#define CSR_PMPCFG4 0x3a4
|
||||
#define CSR_PMPCFG5 0x3a5
|
||||
#define CSR_PMPCFG6 0x3a6
|
||||
#define CSR_PMPCFG7 0x3a7
|
||||
#define CSR_PMPCFG8 0x3a8
|
||||
#define CSR_PMPCFG9 0x3a9
|
||||
#define CSR_PMPCFG10 0x3aa
|
||||
#define CSR_PMPCFG11 0x3ab
|
||||
#define CSR_PMPCFG12 0x3ac
|
||||
#define CSR_PMPCFG13 0x3ad
|
||||
#define CSR_PMPCFG14 0x3ae
|
||||
#define CSR_PMPCFG15 0x3af
|
||||
#define CSR_PMPADDR0 0x3b0
|
||||
#define CSR_PMPADDR1 0x3b1
|
||||
#define CSR_PMPADDR2 0x3b2
|
||||
#define CSR_PMPADDR3 0x3b3
|
||||
#define CSR_PMPADDR4 0x3b4
|
||||
#define CSR_PMPADDR5 0x3b5
|
||||
#define CSR_PMPADDR6 0x3b6
|
||||
#define CSR_PMPADDR7 0x3b7
|
||||
#define CSR_PMPADDR8 0x3b8
|
||||
#define CSR_PMPADDR9 0x3b9
|
||||
#define CSR_PMPADDR10 0x3ba
|
||||
#define CSR_PMPADDR11 0x3bb
|
||||
#define CSR_PMPADDR12 0x3bc
|
||||
#define CSR_PMPADDR13 0x3bd
|
||||
#define CSR_PMPADDR14 0x3be
|
||||
#define CSR_PMPADDR15 0x3bf
|
||||
#define CSR_PMPADDR16 0x3c0
|
||||
#define CSR_PMPADDR17 0x3c1
|
||||
#define CSR_PMPADDR18 0x3c2
|
||||
#define CSR_PMPADDR19 0x3c3
|
||||
#define CSR_PMPADDR20 0x3c4
|
||||
#define CSR_PMPADDR21 0x3c5
|
||||
#define CSR_PMPADDR22 0x3c6
|
||||
#define CSR_PMPADDR23 0x3c7
|
||||
#define CSR_PMPADDR24 0x3c8
|
||||
#define CSR_PMPADDR25 0x3c9
|
||||
#define CSR_PMPADDR26 0x3ca
|
||||
#define CSR_PMPADDR27 0x3cb
|
||||
#define CSR_PMPADDR28 0x3cc
|
||||
#define CSR_PMPADDR29 0x3cd
|
||||
#define CSR_PMPADDR30 0x3ce
|
||||
#define CSR_PMPADDR31 0x3cf
|
||||
#define CSR_PMPADDR32 0x3d0
|
||||
#define CSR_PMPADDR33 0x3d1
|
||||
#define CSR_PMPADDR34 0x3d2
|
||||
#define CSR_PMPADDR35 0x3d3
|
||||
#define CSR_PMPADDR36 0x3d4
|
||||
#define CSR_PMPADDR37 0x3d5
|
||||
#define CSR_PMPADDR38 0x3d6
|
||||
#define CSR_PMPADDR39 0x3d7
|
||||
#define CSR_PMPADDR40 0x3d8
|
||||
#define CSR_PMPADDR41 0x3d9
|
||||
#define CSR_PMPADDR42 0x3da
|
||||
#define CSR_PMPADDR43 0x3db
|
||||
#define CSR_PMPADDR44 0x3dc
|
||||
#define CSR_PMPADDR45 0x3dd
|
||||
#define CSR_PMPADDR46 0x3de
|
||||
#define CSR_PMPADDR47 0x3df
|
||||
#define CSR_PMPADDR48 0x3e0
|
||||
#define CSR_PMPADDR49 0x3e1
|
||||
#define CSR_PMPADDR50 0x3e2
|
||||
#define CSR_PMPADDR51 0x3e3
|
||||
#define CSR_PMPADDR52 0x3e4
|
||||
#define CSR_PMPADDR53 0x3e5
|
||||
#define CSR_PMPADDR54 0x3e6
|
||||
#define CSR_PMPADDR55 0x3e7
|
||||
#define CSR_PMPADDR56 0x3e8
|
||||
#define CSR_PMPADDR57 0x3e9
|
||||
#define CSR_PMPADDR58 0x3ea
|
||||
#define CSR_PMPADDR59 0x3eb
|
||||
#define CSR_PMPADDR60 0x3ec
|
||||
#define CSR_PMPADDR61 0x3ed
|
||||
#define CSR_PMPADDR62 0x3ee
|
||||
#define CSR_PMPADDR63 0x3ef
|
||||
|
||||
/* Machine Counters/Timers */
|
||||
#define CSR_MCYCLE 0xb00
|
||||
#define CSR_MINSTRET 0xb02
|
||||
#define CSR_MHPMCOUNTER3 0xb03
|
||||
#define CSR_MHPMCOUNTER4 0xb04
|
||||
#define CSR_MHPMCOUNTER5 0xb05
|
||||
#define CSR_MHPMCOUNTER6 0xb06
|
||||
#define CSR_MHPMCOUNTER7 0xb07
|
||||
#define CSR_MHPMCOUNTER8 0xb08
|
||||
#define CSR_MHPMCOUNTER9 0xb09
|
||||
#define CSR_MHPMCOUNTER10 0xb0a
|
||||
#define CSR_MHPMCOUNTER11 0xb0b
|
||||
#define CSR_MHPMCOUNTER12 0xb0c
|
||||
#define CSR_MHPMCOUNTER13 0xb0d
|
||||
#define CSR_MHPMCOUNTER14 0xb0e
|
||||
#define CSR_MHPMCOUNTER15 0xb0f
|
||||
#define CSR_MHPMCOUNTER16 0xb10
|
||||
#define CSR_MHPMCOUNTER17 0xb11
|
||||
#define CSR_MHPMCOUNTER18 0xb12
|
||||
#define CSR_MHPMCOUNTER19 0xb13
|
||||
#define CSR_MHPMCOUNTER20 0xb14
|
||||
#define CSR_MHPMCOUNTER21 0xb15
|
||||
#define CSR_MHPMCOUNTER22 0xb16
|
||||
#define CSR_MHPMCOUNTER23 0xb17
|
||||
#define CSR_MHPMCOUNTER24 0xb18
|
||||
#define CSR_MHPMCOUNTER25 0xb19
|
||||
#define CSR_MHPMCOUNTER26 0xb1a
|
||||
#define CSR_MHPMCOUNTER27 0xb1b
|
||||
#define CSR_MHPMCOUNTER28 0xb1c
|
||||
#define CSR_MHPMCOUNTER29 0xb1d
|
||||
#define CSR_MHPMCOUNTER30 0xb1e
|
||||
#define CSR_MHPMCOUNTER31 0xb1f
|
||||
#define CSR_MCYCLEH 0xb80
|
||||
#define CSR_MINSTRETH 0xb82
|
||||
#define CSR_MHPMCOUNTER3H 0xb83
|
||||
@@ -415,6 +511,86 @@
|
||||
#define CSR_MHPMCOUNTER30H 0xb9e
|
||||
#define CSR_MHPMCOUNTER31H 0xb9f
|
||||
|
||||
/* Machine Counter Setup */
|
||||
#define CSR_MCOUNTINHIBIT 0x320
|
||||
#define CSR_MHPMEVENT3 0x323
|
||||
#define CSR_MHPMEVENT4 0x324
|
||||
#define CSR_MHPMEVENT5 0x325
|
||||
#define CSR_MHPMEVENT6 0x326
|
||||
#define CSR_MHPMEVENT7 0x327
|
||||
#define CSR_MHPMEVENT8 0x328
|
||||
#define CSR_MHPMEVENT9 0x329
|
||||
#define CSR_MHPMEVENT10 0x32a
|
||||
#define CSR_MHPMEVENT11 0x32b
|
||||
#define CSR_MHPMEVENT12 0x32c
|
||||
#define CSR_MHPMEVENT13 0x32d
|
||||
#define CSR_MHPMEVENT14 0x32e
|
||||
#define CSR_MHPMEVENT15 0x32f
|
||||
#define CSR_MHPMEVENT16 0x330
|
||||
#define CSR_MHPMEVENT17 0x331
|
||||
#define CSR_MHPMEVENT18 0x332
|
||||
#define CSR_MHPMEVENT19 0x333
|
||||
#define CSR_MHPMEVENT20 0x334
|
||||
#define CSR_MHPMEVENT21 0x335
|
||||
#define CSR_MHPMEVENT22 0x336
|
||||
#define CSR_MHPMEVENT23 0x337
|
||||
#define CSR_MHPMEVENT24 0x338
|
||||
#define CSR_MHPMEVENT25 0x339
|
||||
#define CSR_MHPMEVENT26 0x33a
|
||||
#define CSR_MHPMEVENT27 0x33b
|
||||
#define CSR_MHPMEVENT28 0x33c
|
||||
#define CSR_MHPMEVENT29 0x33d
|
||||
#define CSR_MHPMEVENT30 0x33e
|
||||
#define CSR_MHPMEVENT31 0x33f
|
||||
|
||||
/* For RV32 */
|
||||
#define CSR_MHPMEVENT3H 0x723
|
||||
#define CSR_MHPMEVENT4H 0x724
|
||||
#define CSR_MHPMEVENT5H 0x725
|
||||
#define CSR_MHPMEVENT6H 0x726
|
||||
#define CSR_MHPMEVENT7H 0x727
|
||||
#define CSR_MHPMEVENT8H 0x728
|
||||
#define CSR_MHPMEVENT9H 0x729
|
||||
#define CSR_MHPMEVENT10H 0x72a
|
||||
#define CSR_MHPMEVENT11H 0x72b
|
||||
#define CSR_MHPMEVENT12H 0x72c
|
||||
#define CSR_MHPMEVENT13H 0x72d
|
||||
#define CSR_MHPMEVENT14H 0x72e
|
||||
#define CSR_MHPMEVENT15H 0x72f
|
||||
#define CSR_MHPMEVENT16H 0x730
|
||||
#define CSR_MHPMEVENT17H 0x731
|
||||
#define CSR_MHPMEVENT18H 0x732
|
||||
#define CSR_MHPMEVENT19H 0x733
|
||||
#define CSR_MHPMEVENT20H 0x734
|
||||
#define CSR_MHPMEVENT21H 0x735
|
||||
#define CSR_MHPMEVENT22H 0x736
|
||||
#define CSR_MHPMEVENT23H 0x737
|
||||
#define CSR_MHPMEVENT24H 0x738
|
||||
#define CSR_MHPMEVENT25H 0x739
|
||||
#define CSR_MHPMEVENT26H 0x73a
|
||||
#define CSR_MHPMEVENT27H 0x73b
|
||||
#define CSR_MHPMEVENT28H 0x73c
|
||||
#define CSR_MHPMEVENT29H 0x73d
|
||||
#define CSR_MHPMEVENT30H 0x73e
|
||||
#define CSR_MHPMEVENT31H 0x73f
|
||||
|
||||
/* Counter Overflow CSR */
|
||||
#define CSR_SCOUNTOVF 0xda0
|
||||
|
||||
/* Debug/Trace Registers */
|
||||
#define CSR_TSELECT 0x7a0
|
||||
#define CSR_TDATA1 0x7a1
|
||||
#define CSR_TDATA2 0x7a2
|
||||
#define CSR_TDATA3 0x7a3
|
||||
|
||||
/* Debug Mode Registers */
|
||||
#define CSR_DCSR 0x7b0
|
||||
#define CSR_DPC 0x7b1
|
||||
#define CSR_DSCRATCH0 0x7b2
|
||||
#define CSR_DSCRATCH1 0x7b3
|
||||
|
||||
/* ===== Trap/Exception Causes ===== */
|
||||
|
||||
#define CAUSE_MISALIGNED_FETCH 0x0
|
||||
#define CAUSE_FETCH_ACCESS 0x1
|
||||
#define CAUSE_ILLEGAL_INSTRUCTION 0x2
|
||||
@@ -424,8 +600,8 @@
|
||||
#define CAUSE_MISALIGNED_STORE 0x6
|
||||
#define CAUSE_STORE_ACCESS 0x7
|
||||
#define CAUSE_USER_ECALL 0x8
|
||||
#define CAUSE_HYPERVISOR_ECALL 0x9
|
||||
#define CAUSE_SUPERVISOR_ECALL 0xa
|
||||
#define CAUSE_SUPERVISOR_ECALL 0x9
|
||||
#define CAUSE_VIRTUAL_SUPERVISOR_ECALL 0xa
|
||||
#define CAUSE_MACHINE_ECALL 0xb
|
||||
#define CAUSE_FETCH_PAGE_FAULT 0xc
|
||||
#define CAUSE_LOAD_PAGE_FAULT 0xd
|
||||
@@ -435,6 +611,8 @@
|
||||
#define CAUSE_VIRTUAL_INST_FAULT 0x16
|
||||
#define CAUSE_STORE_GUEST_PAGE_FAULT 0x17
|
||||
|
||||
/* ===== Instruction Encodings ===== */
|
||||
|
||||
#define INSN_MATCH_LB 0x3
|
||||
#define INSN_MASK_LB 0x707f
|
||||
#define INSN_MATCH_LH 0x1003
|
||||
|
@@ -42,15 +42,28 @@
|
||||
: "t0"); \
|
||||
})
|
||||
#define init_fp_reg(i) SET_F32_REG((i) << 3, 3, 0, 0)
|
||||
|
||||
#if __riscv_xlen == 64
|
||||
#define GET_F64_REG(insn, pos, regs) \
|
||||
({ \
|
||||
register ulong value asm("a0") = \
|
||||
SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
|
||||
register ulong value asm("a0") = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
|
||||
ulong tmp; \
|
||||
asm("1: auipc %0, %%pcrel_hi(get_f64_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" \
|
||||
: "=&r"(tmp), "+&r"(value)::"t0"); \
|
||||
sizeof(ulong) == 4 ? *(int64_t *)value : (int64_t)value; \
|
||||
value; \
|
||||
})
|
||||
#else
|
||||
#define GET_F64_REG(insn, pos, regs) \
|
||||
({ \
|
||||
u64 value; \
|
||||
ulong offset = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
|
||||
register ulong ptr asm("a0") = (ulong)&value; \
|
||||
asm ("1: auipc t1, %%pcrel_hi(get_f64_reg); add t1, t1, %2; jalr t0, t1, %%pcrel_lo(1b)" \
|
||||
: "=m"(value) : "r"(ptr), "r"(offset) : "t0", "t1"); \
|
||||
value; \
|
||||
})
|
||||
#endif
|
||||
|
||||
#define SET_F64_REG(insn, pos, regs, val) \
|
||||
({ \
|
||||
uint64_t __val = (val); \
|
||||
|
@@ -2,30 +2,41 @@
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
* Copyright (c) 2021 Christoph Müllner <cmuellner@linux.com>
|
||||
*/
|
||||
|
||||
#ifndef __RISCV_LOCKS_H__
|
||||
#define __RISCV_LOCKS_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
#define TICKET_SHIFT 16
|
||||
|
||||
typedef struct {
|
||||
volatile long lock;
|
||||
} spinlock_t;
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
u16 next;
|
||||
u16 owner;
|
||||
#else
|
||||
u16 owner;
|
||||
u16 next;
|
||||
#endif
|
||||
} __aligned(4) spinlock_t;
|
||||
|
||||
#define __RISCV_SPIN_UNLOCKED 0
|
||||
#define __SPIN_LOCK_UNLOCKED \
|
||||
(spinlock_t) { 0, 0 }
|
||||
|
||||
#define SPIN_LOCK_INIT(_lptr) (_lptr)->lock = __RISCV_SPIN_UNLOCKED
|
||||
#define SPIN_LOCK_INIT(x) \
|
||||
x = __SPIN_LOCK_UNLOCKED
|
||||
|
||||
#define SPIN_LOCK_INITIALIZER \
|
||||
{ \
|
||||
.lock = __RISCV_SPIN_UNLOCKED, \
|
||||
}
|
||||
#define SPIN_LOCK_INITIALIZER \
|
||||
__SPIN_LOCK_UNLOCKED
|
||||
|
||||
int spin_lock_check(spinlock_t *lock);
|
||||
#define DEFINE_SPIN_LOCK(x) \
|
||||
spinlock_t SPIN_LOCK_INIT(x)
|
||||
|
||||
int spin_trylock(spinlock_t *lock);
|
||||
bool spin_lock_check(spinlock_t *lock);
|
||||
|
||||
bool spin_trylock(spinlock_t *lock);
|
||||
|
||||
void spin_lock(spinlock_t *lock);
|
||||
|
||||
|
@@ -66,10 +66,8 @@ static inline int ffs(int x)
|
||||
x >>= 2;
|
||||
r += 2;
|
||||
}
|
||||
if (!(x & 1)) {
|
||||
x >>= 1;
|
||||
if (!(x & 1))
|
||||
r += 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -148,10 +146,8 @@ static inline int fls(int x)
|
||||
x <<= 2;
|
||||
r -= 2;
|
||||
}
|
||||
if (!(x & 0x80000000u)) {
|
||||
x <<= 1;
|
||||
if (!(x & 0x80000000u))
|
||||
r -= 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@@ -12,6 +12,17 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
struct sbi_console_device {
|
||||
/** Name of the console device */
|
||||
char name[32];
|
||||
|
||||
/** Write a character to the console output */
|
||||
void (*console_putc)(char ch);
|
||||
|
||||
/** Read a character from the console input */
|
||||
int (*console_getc)(void);
|
||||
};
|
||||
|
||||
#define __printf(a, b) __attribute__((format(printf, a, b)))
|
||||
|
||||
bool sbi_isprintable(char ch);
|
||||
@@ -32,8 +43,19 @@ int __printf(1, 2) sbi_printf(const char *format, ...);
|
||||
|
||||
int __printf(1, 2) sbi_dprintf(const char *format, ...);
|
||||
|
||||
void __printf(1, 2) __attribute__((noreturn)) sbi_panic(const char *format, ...);
|
||||
|
||||
const struct sbi_console_device *sbi_console_get_device(void);
|
||||
|
||||
void sbi_console_set_device(const struct sbi_console_device *dev);
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
int sbi_console_init(struct sbi_scratch *scratch);
|
||||
|
||||
#define SBI_ASSERT(cond, args) do { \
|
||||
if (unlikely(!(cond))) \
|
||||
sbi_panic args; \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
@@ -22,7 +22,7 @@
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#ifdef __ASSEMBLY__
|
||||
#ifdef __ASSEMBLER__
|
||||
#define _AC(X,Y) X
|
||||
#define _AT(T,X) X
|
||||
#else
|
||||
|
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
|
||||
#define csr_read_allowed(csr_num, trap) \
|
||||
({ \
|
||||
@@ -19,6 +20,7 @@
|
||||
register ulong ttmp asm("a4"); \
|
||||
register ulong mtvec = sbi_hart_expected_trap_addr(); \
|
||||
register ulong ret = 0; \
|
||||
((struct sbi_trap_info *)(trap))->cause = 0; \
|
||||
asm volatile( \
|
||||
"add %[ttmp], %[tinfo], zero\n" \
|
||||
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
|
||||
@@ -36,6 +38,7 @@
|
||||
register ulong tinfo asm("a3") = (ulong)trap; \
|
||||
register ulong ttmp asm("a4"); \
|
||||
register ulong mtvec = sbi_hart_expected_trap_addr(); \
|
||||
((struct sbi_trap_info *)(trap))->cause = 0; \
|
||||
asm volatile( \
|
||||
"add %[ttmp], %[tinfo], zero\n" \
|
||||
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
|
||||
|
187
include/sbi/sbi_domain.h
Normal file
187
include/sbi/sbi_domain.h
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __SBI_DOMAIN_H__
|
||||
#define __SBI_DOMAIN_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
#include <sbi/sbi_hartmask.h>
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
/** Domain access types */
|
||||
enum sbi_domain_access {
|
||||
SBI_DOMAIN_READ = (1UL << 0),
|
||||
SBI_DOMAIN_WRITE = (1UL << 1),
|
||||
SBI_DOMAIN_EXECUTE = (1UL << 2),
|
||||
SBI_DOMAIN_MMIO = (1UL << 3)
|
||||
};
|
||||
|
||||
/** Representation of OpenSBI domain memory region */
|
||||
struct sbi_domain_memregion {
|
||||
/**
|
||||
* Size of memory region as power of 2
|
||||
* It has to be minimum 3 and maximum __riscv_xlen
|
||||
*/
|
||||
unsigned long order;
|
||||
/**
|
||||
* Base address of memory region
|
||||
* It must be 2^order aligned address
|
||||
*/
|
||||
unsigned long base;
|
||||
/** Flags representing memory region attributes */
|
||||
#define SBI_DOMAIN_MEMREGION_READABLE (1UL << 0)
|
||||
#define SBI_DOMAIN_MEMREGION_WRITEABLE (1UL << 1)
|
||||
#define SBI_DOMAIN_MEMREGION_EXECUTABLE (1UL << 2)
|
||||
#define SBI_DOMAIN_MEMREGION_MMODE (1UL << 3)
|
||||
#define SBI_DOMAIN_MEMREGION_ACCESS_MASK (0xfUL)
|
||||
|
||||
#define SBI_DOMAIN_MEMREGION_MMIO (1UL << 31)
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
/** Maximum number of domains */
|
||||
#define SBI_DOMAIN_MAX_INDEX 32
|
||||
|
||||
/** Representation of OpenSBI domain */
|
||||
struct sbi_domain {
|
||||
/**
|
||||
* Logical index of this domain
|
||||
* Note: This set by sbi_domain_finalize() in the coldboot path
|
||||
*/
|
||||
u32 index;
|
||||
/**
|
||||
* HARTs assigned to this domain
|
||||
* Note: This set by sbi_domain_init() and sbi_domain_finalize()
|
||||
* in the coldboot path
|
||||
*/
|
||||
struct sbi_hartmask assigned_harts;
|
||||
/** Name of this domain */
|
||||
char name[64];
|
||||
/** Possible HARTs in this domain */
|
||||
const struct sbi_hartmask *possible_harts;
|
||||
/** Array of memory regions terminated by a region with order zero */
|
||||
struct sbi_domain_memregion *regions;
|
||||
/** HART id of the HART booting this domain */
|
||||
u32 boot_hartid;
|
||||
/** Arg1 (or 'a1' register) of next booting stage for this domain */
|
||||
unsigned long next_arg1;
|
||||
/** Address of next booting stage for this domain */
|
||||
unsigned long next_addr;
|
||||
/** Privilege mode of next booting stage for this domain */
|
||||
unsigned long next_mode;
|
||||
/** Is domain allowed to reset the system */
|
||||
bool system_reset_allowed;
|
||||
};
|
||||
|
||||
/** The root domain instance */
|
||||
extern struct sbi_domain root;
|
||||
|
||||
/** HART id to domain table */
|
||||
extern struct sbi_domain *hartid_to_domain_table[];
|
||||
|
||||
/** Get pointer to sbi_domain from HART id */
|
||||
#define sbi_hartid_to_domain(__hartid) \
|
||||
hartid_to_domain_table[__hartid]
|
||||
|
||||
/** Get pointer to sbi_domain for current HART */
|
||||
#define sbi_domain_thishart_ptr() \
|
||||
sbi_hartid_to_domain(current_hartid())
|
||||
|
||||
/** Index to domain table */
|
||||
extern struct sbi_domain *domidx_to_domain_table[];
|
||||
|
||||
/** Get pointer to sbi_domain from index */
|
||||
#define sbi_index_to_domain(__index) \
|
||||
domidx_to_domain_table[__index]
|
||||
|
||||
/** Iterate over each domain */
|
||||
#define sbi_domain_for_each(__i, __d) \
|
||||
for ((__i) = 0; ((__d) = sbi_index_to_domain(__i)); (__i)++)
|
||||
|
||||
/** Iterate over each memory region of a domain */
|
||||
#define sbi_domain_for_each_memregion(__d, __r) \
|
||||
for ((__r) = (__d)->regions; (__r)->order; (__r)++)
|
||||
|
||||
/**
|
||||
* Check whether given HART is assigned to specified domain
|
||||
* @param dom pointer to domain
|
||||
* @param hartid the HART ID
|
||||
* @return TRUE if HART is assigned to domain otherwise FALSE
|
||||
*/
|
||||
bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid);
|
||||
|
||||
/**
|
||||
* Get ulong assigned HART mask for given domain and HART base ID
|
||||
* @param dom pointer to domain
|
||||
* @param hbase the HART base ID
|
||||
* @return ulong possible HART mask
|
||||
* Note: the return ulong mask will be set to zero on failure.
|
||||
*/
|
||||
ulong sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom,
|
||||
ulong hbase);
|
||||
|
||||
/**
|
||||
* Initialize a domain memory region based on it's physical
|
||||
* address and size.
|
||||
*
|
||||
* @param addr start physical address of memory region
|
||||
* @param size physical size of memory region
|
||||
* @param flags memory region flags
|
||||
* @param reg pointer to memory region being initialized
|
||||
*/
|
||||
void sbi_domain_memregion_init(unsigned long addr,
|
||||
unsigned long size,
|
||||
unsigned long flags,
|
||||
struct sbi_domain_memregion *reg);
|
||||
|
||||
/**
|
||||
* Check whether we can access specified address for given mode and
|
||||
* memory region flags under a domain
|
||||
* @param dom pointer to domain
|
||||
* @param addr the address to be checked
|
||||
* @param mode the privilege mode of access
|
||||
* @param access_flags bitmask of domain access types (enum sbi_domain_access)
|
||||
* @return TRUE if access allowed otherwise FALSE
|
||||
*/
|
||||
bool sbi_domain_check_addr(const struct sbi_domain *dom,
|
||||
unsigned long addr, unsigned long mode,
|
||||
unsigned long access_flags);
|
||||
|
||||
/** Dump domain details on the console */
|
||||
void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix);
|
||||
|
||||
/** Dump all domain details on the console */
|
||||
void sbi_domain_dump_all(const char *suffix);
|
||||
|
||||
/**
|
||||
* Register a new domain
|
||||
* @param dom pointer to domain
|
||||
* @param assign_mask pointer to HART mask of HARTs assigned to the domain
|
||||
*
|
||||
* @return 0 on success and negative error code on failure
|
||||
*/
|
||||
int sbi_domain_register(struct sbi_domain *dom,
|
||||
const struct sbi_hartmask *assign_mask);
|
||||
|
||||
/**
|
||||
* Add a memory region to the root domain
|
||||
* @param reg pointer to the memory region to be added
|
||||
*
|
||||
* @return 0 on success and negative error code on failure
|
||||
*/
|
||||
int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg);
|
||||
|
||||
/** Finalize domain tables and startup non-root domains */
|
||||
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid);
|
||||
|
||||
/** Initialize domains */
|
||||
int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid);
|
||||
|
||||
#endif
|
@@ -14,7 +14,7 @@
|
||||
#include <sbi/sbi_list.h>
|
||||
|
||||
#define SBI_ECALL_VERSION_MAJOR 0
|
||||
#define SBI_ECALL_VERSION_MINOR 2
|
||||
#define SBI_ECALL_VERSION_MINOR 3
|
||||
#define SBI_OPENSBI_IMPID 1
|
||||
|
||||
struct sbi_trap_regs;
|
||||
@@ -26,7 +26,8 @@ struct sbi_ecall_extension {
|
||||
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,
|
||||
const struct sbi_trap_regs *regs,
|
||||
unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap);
|
||||
};
|
||||
|
||||
@@ -37,6 +38,8 @@ 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;
|
||||
extern struct sbi_ecall_extension ecall_srst;
|
||||
extern struct sbi_ecall_extension ecall_pmu;
|
||||
|
||||
u16 sbi_ecall_version_major(void);
|
||||
|
||||
|
@@ -27,6 +27,8 @@
|
||||
#define SBI_EXT_IPI 0x735049
|
||||
#define SBI_EXT_RFENCE 0x52464E43
|
||||
#define SBI_EXT_HSM 0x48534D
|
||||
#define SBI_EXT_SRST 0x53525354
|
||||
#define SBI_EXT_PMU 0x504D55
|
||||
|
||||
/* SBI function IDs for BASE extension*/
|
||||
#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
|
||||
@@ -47,21 +49,182 @@
|
||||
#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
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID 0x3
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA 0x4
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID 0x5
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA 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_EXT_HSM_HART_SUSPEND 0x3
|
||||
|
||||
#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_HSM_STATE_STARTED 0x0
|
||||
#define SBI_HSM_STATE_STOPPED 0x1
|
||||
#define SBI_HSM_STATE_START_PENDING 0x2
|
||||
#define SBI_HSM_STATE_STOP_PENDING 0x3
|
||||
#define SBI_HSM_STATE_SUSPENDED 0x4
|
||||
#define SBI_HSM_STATE_SUSPEND_PENDING 0x5
|
||||
#define SBI_HSM_STATE_RESUME_PENDING 0x6
|
||||
|
||||
#define SBI_HSM_SUSP_BASE_MASK 0x7fffffff
|
||||
#define SBI_HSM_SUSP_NON_RET_BIT 0x80000000
|
||||
#define SBI_HSM_SUSP_PLAT_BASE 0x10000000
|
||||
|
||||
#define SBI_HSM_SUSPEND_RET_DEFAULT 0x00000000
|
||||
#define SBI_HSM_SUSPEND_RET_PLATFORM SBI_HSM_SUSP_PLAT_BASE
|
||||
#define SBI_HSM_SUSPEND_RET_LAST SBI_HSM_SUSP_BASE_MASK
|
||||
#define SBI_HSM_SUSPEND_NON_RET_DEFAULT SBI_HSM_SUSP_NON_RET_BIT
|
||||
#define SBI_HSM_SUSPEND_NON_RET_PLATFORM (SBI_HSM_SUSP_NON_RET_BIT | \
|
||||
SBI_HSM_SUSP_PLAT_BASE)
|
||||
#define SBI_HSM_SUSPEND_NON_RET_LAST (SBI_HSM_SUSP_NON_RET_BIT | \
|
||||
SBI_HSM_SUSP_BASE_MASK)
|
||||
|
||||
/* SBI function IDs for SRST extension */
|
||||
#define SBI_EXT_SRST_RESET 0x0
|
||||
|
||||
#define SBI_SRST_RESET_TYPE_SHUTDOWN 0x0
|
||||
#define SBI_SRST_RESET_TYPE_COLD_REBOOT 0x1
|
||||
#define SBI_SRST_RESET_TYPE_WARM_REBOOT 0x2
|
||||
#define SBI_SRST_RESET_TYPE_LAST SBI_SRST_RESET_TYPE_WARM_REBOOT
|
||||
|
||||
#define SBI_SRST_RESET_REASON_NONE 0x0
|
||||
#define SBI_SRST_RESET_REASON_SYSFAIL 0x1
|
||||
|
||||
/* SBI function IDs for PMU extension */
|
||||
#define SBI_EXT_PMU_NUM_COUNTERS 0x0
|
||||
#define SBI_EXT_PMU_COUNTER_GET_INFO 0x1
|
||||
#define SBI_EXT_PMU_COUNTER_CFG_MATCH 0x2
|
||||
#define SBI_EXT_PMU_COUNTER_START 0x3
|
||||
#define SBI_EXT_PMU_COUNTER_STOP 0x4
|
||||
#define SBI_EXT_PMU_COUNTER_FW_READ 0x5
|
||||
|
||||
/** General pmu event codes specified in SBI PMU extension */
|
||||
enum sbi_pmu_hw_generic_events_t {
|
||||
SBI_PMU_HW_NO_EVENT = 0,
|
||||
SBI_PMU_HW_CPU_CYCLES = 1,
|
||||
SBI_PMU_HW_INSTRUCTIONS = 2,
|
||||
SBI_PMU_HW_CACHE_REFERENCES = 3,
|
||||
SBI_PMU_HW_CACHE_MISSES = 4,
|
||||
SBI_PMU_HW_BRANCH_INSTRUCTIONS = 5,
|
||||
SBI_PMU_HW_BRANCH_MISSES = 6,
|
||||
SBI_PMU_HW_BUS_CYCLES = 7,
|
||||
SBI_PMU_HW_STALLED_CYCLES_FRONTEND = 8,
|
||||
SBI_PMU_HW_STALLED_CYCLES_BACKEND = 9,
|
||||
SBI_PMU_HW_REF_CPU_CYCLES = 10,
|
||||
|
||||
SBI_PMU_HW_GENERAL_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* Generalized hardware cache events:
|
||||
*
|
||||
* { L1-D, L1-I, LLC, ITLB, DTLB, BPU, NODE } x
|
||||
* { read, write, prefetch } x
|
||||
* { accesses, misses }
|
||||
*/
|
||||
enum sbi_pmu_hw_cache_id {
|
||||
SBI_PMU_HW_CACHE_L1D = 0,
|
||||
SBI_PMU_HW_CACHE_L1I = 1,
|
||||
SBI_PMU_HW_CACHE_LL = 2,
|
||||
SBI_PMU_HW_CACHE_DTLB = 3,
|
||||
SBI_PMU_HW_CACHE_ITLB = 4,
|
||||
SBI_PMU_HW_CACHE_BPU = 5,
|
||||
SBI_PMU_HW_CACHE_NODE = 6,
|
||||
|
||||
SBI_PMU_HW_CACHE_MAX,
|
||||
};
|
||||
|
||||
enum sbi_pmu_hw_cache_op_id {
|
||||
SBI_PMU_HW_CACHE_OP_READ = 0,
|
||||
SBI_PMU_HW_CACHE_OP_WRITE = 1,
|
||||
SBI_PMU_HW_CACHE_OP_PREFETCH = 2,
|
||||
|
||||
SBI_PMU_HW_CACHE_OP_MAX,
|
||||
};
|
||||
|
||||
enum sbi_pmu_hw_cache_op_result_id {
|
||||
SBI_PMU_HW_CACHE_RESULT_ACCESS = 0,
|
||||
SBI_PMU_HW_CACHE_RESULT_MISS = 1,
|
||||
|
||||
SBI_PMU_HW_CACHE_RESULT_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* Special "firmware" events provided by the OpenSBI, even if the hardware
|
||||
* does not support performance events. These events are encoded as a raw
|
||||
* event type in Linux kernel perf framework.
|
||||
*/
|
||||
enum sbi_pmu_fw_event_code_id {
|
||||
SBI_PMU_FW_MISALIGNED_LOAD = 0,
|
||||
SBI_PMU_FW_MISALIGNED_STORE = 1,
|
||||
SBI_PMU_FW_ACCESS_LOAD = 2,
|
||||
SBI_PMU_FW_ACCESS_STORE = 3,
|
||||
SBI_PMU_FW_ILLEGAL_INSN = 4,
|
||||
SBI_PMU_FW_SET_TIMER = 5,
|
||||
SBI_PMU_FW_IPI_SENT = 6,
|
||||
SBI_PMU_FW_IPI_RECVD = 7,
|
||||
SBI_PMU_FW_FENCE_I_SENT = 8,
|
||||
SBI_PMU_FW_FENCE_I_RECVD = 9,
|
||||
SBI_PMU_FW_SFENCE_VMA_SENT = 10,
|
||||
SBI_PMU_FW_SFENCE_VMA_RCVD = 11,
|
||||
SBI_PMU_FW_SFENCE_VMA_ASID_SENT = 12,
|
||||
SBI_PMU_FW_SFENCE_VMA_ASID_RCVD = 13,
|
||||
|
||||
SBI_PMU_FW_HFENCE_GVMA_SENT = 14,
|
||||
SBI_PMU_FW_HFENCE_GVMA_RCVD = 15,
|
||||
SBI_PMU_FW_HFENCE_GVMA_VMID_SENT = 16,
|
||||
SBI_PMU_FW_HFENCE_GVMA_VMID_RCVD = 17,
|
||||
|
||||
SBI_PMU_FW_HFENCE_VVMA_SENT = 18,
|
||||
SBI_PMU_FW_HFENCE_VVMA_RCVD = 19,
|
||||
SBI_PMU_FW_HFENCE_VVMA_ASID_SENT = 20,
|
||||
SBI_PMU_FW_HFENCE_VVMA_ASID_RCVD = 21,
|
||||
SBI_PMU_FW_MAX,
|
||||
};
|
||||
|
||||
/** SBI PMU event idx type */
|
||||
enum sbi_pmu_event_type_id {
|
||||
SBI_PMU_EVENT_TYPE_HW = 0x0,
|
||||
SBI_PMU_EVENT_TYPE_HW_CACHE = 0x1,
|
||||
SBI_PMU_EVENT_TYPE_HW_RAW = 0x2,
|
||||
SBI_PMU_EVENT_TYPE_FW = 0xf,
|
||||
SBI_PMU_EVENT_TYPE_MAX,
|
||||
};
|
||||
|
||||
/** SBI PMU counter type */
|
||||
enum sbi_pmu_ctr_type {
|
||||
SBI_PMU_CTR_TYPE_HW = 0,
|
||||
SBI_PMU_CTR_TYPE_FW,
|
||||
};
|
||||
|
||||
/* Helper macros to decode event idx */
|
||||
#define SBI_PMU_EVENT_IDX_OFFSET 20
|
||||
#define SBI_PMU_EVENT_IDX_MASK 0xFFFFF
|
||||
#define SBI_PMU_EVENT_IDX_CODE_MASK 0xFFFF
|
||||
#define SBI_PMU_EVENT_IDX_TYPE_MASK 0xF0000
|
||||
#define SBI_PMU_EVENT_RAW_IDX 0x20000
|
||||
|
||||
#define SBI_PMU_EVENT_IDX_INVALID 0xFFFFFFFF
|
||||
|
||||
/* Flags defined for config matching function */
|
||||
#define SBI_PMU_CFG_FLAG_SKIP_MATCH (1 << 0)
|
||||
#define SBI_PMU_CFG_FLAG_CLEAR_VALUE (1 << 1)
|
||||
#define SBI_PMU_CFG_FLAG_AUTO_START (1 << 2)
|
||||
#define SBI_PMU_CFG_FLAG_SET_VUINH (1 << 3)
|
||||
#define SBI_PMU_CFG_FLAG_SET_VSINH (1 << 4)
|
||||
#define SBI_PMU_CFG_FLAG_SET_UINH (1 << 5)
|
||||
#define SBI_PMU_CFG_FLAG_SET_SINH (1 << 6)
|
||||
#define SBI_PMU_CFG_FLAG_SET_MINH (1 << 7)
|
||||
|
||||
/* Flags defined for counter start function */
|
||||
#define SBI_PMU_START_FLAG_SET_INIT_VALUE (1 << 0)
|
||||
|
||||
/* Flags defined for counter stop function */
|
||||
#define SBI_PMU_STOP_FLAG_RESET (1 << 0)
|
||||
|
||||
/* SBI base specification related macros */
|
||||
#define SBI_SPEC_VERSION_MAJOR_OFFSET 24
|
||||
#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f
|
||||
#define SBI_SPEC_VERSION_MINOR_MASK 0xffffff
|
||||
@@ -78,8 +241,10 @@
|
||||
#define SBI_ERR_DENIED -4
|
||||
#define SBI_ERR_INVALID_ADDRESS -5
|
||||
#define SBI_ERR_ALREADY_AVAILABLE -6
|
||||
#define SBI_ERR_ALREADY_STARTED -7
|
||||
#define SBI_ERR_ALREADY_STOPPED -8
|
||||
|
||||
#define SBI_LAST_ERR SBI_ERR_ALREADY_AVAILABLE
|
||||
#define SBI_LAST_ERR SBI_ERR_ALREADY_STOPPED
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
|
@@ -21,6 +21,8 @@
|
||||
#define SBI_EDENIED SBI_ERR_DENIED
|
||||
#define SBI_EINVALID_ADDR SBI_ERR_INVALID_ADDRESS
|
||||
#define SBI_EALREADY SBI_ERR_ALREADY_AVAILABLE
|
||||
#define SBI_EALREADY_STARTED SBI_ERR_ALREADY_STARTED
|
||||
#define SBI_EALREADY_STOPPED SBI_ERR_ALREADY_STOPPED
|
||||
|
||||
#define SBI_ENODEV -1000
|
||||
#define SBI_ENOSYS -1001
|
||||
|
@@ -33,8 +33,8 @@ int sbi_fifo_dequeue(struct sbi_fifo *fifo, void *data);
|
||||
int sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data);
|
||||
void sbi_fifo_init(struct sbi_fifo *fifo, void *queue_mem, u16 entries,
|
||||
u16 entry_size);
|
||||
bool sbi_fifo_is_empty(struct sbi_fifo *fifo);
|
||||
bool sbi_fifo_is_full(struct sbi_fifo *fifo);
|
||||
int sbi_fifo_is_empty(struct sbi_fifo *fifo);
|
||||
int sbi_fifo_is_full(struct sbi_fifo *fifo);
|
||||
int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
|
||||
int (*fptr)(void *in, void *data));
|
||||
u16 sbi_fifo_avail(struct sbi_fifo *fifo);
|
||||
|
@@ -14,14 +14,16 @@
|
||||
|
||||
/** 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),
|
||||
SBI_HART_HAS_SCOUNTEREN = (1 << 0),
|
||||
/** Hart has M-mode counter enable */
|
||||
SBI_HART_HAS_MCOUNTEREN = (1 << 2),
|
||||
SBI_HART_HAS_MCOUNTEREN = (1 << 1),
|
||||
/** Hart has counter inhibit CSR */
|
||||
SBI_HART_HAS_MCOUNTINHIBIT = (1 << 2),
|
||||
/** Hart has sscofpmf extension */
|
||||
SBI_HART_HAS_SSCOFPMF = (1 << 3),
|
||||
/** HART has timer csr implementation in hardware */
|
||||
SBI_HART_HAS_TIME = (1 << 3),
|
||||
SBI_HART_HAS_TIME = (1 << 4),
|
||||
|
||||
/** Last index of Hart features*/
|
||||
SBI_HART_HAS_LAST_FEATURE = SBI_HART_HAS_TIME,
|
||||
@@ -29,7 +31,8 @@ enum sbi_hart_features {
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot);
|
||||
int sbi_hart_reinit(struct sbi_scratch *scratch);
|
||||
int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||
|
||||
extern void (*sbi_hart_expected_trap)(void);
|
||||
static inline ulong sbi_hart_expected_trap_addr(void)
|
||||
@@ -37,14 +40,14 @@ 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_mhpm_count(struct sbi_scratch *scratch);
|
||||
void sbi_hart_delegation_dump(struct sbi_scratch *scratch,
|
||||
const char *prefix, const char *suffix);
|
||||
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);
|
||||
unsigned long sbi_hart_pmp_granularity(struct sbi_scratch *scratch);
|
||||
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch);
|
||||
unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch);
|
||||
int sbi_hart_pmp_configure(struct sbi_scratch *scratch);
|
||||
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);
|
||||
|
@@ -67,7 +67,7 @@ static inline void sbi_hartmask_clear_hart(u32 h, struct sbi_hartmask *m)
|
||||
* @param h HART id to test
|
||||
* @param m the hartmask pointer
|
||||
*/
|
||||
static inline int sbi_hartmask_test_hart(u32 h, struct sbi_hartmask *m)
|
||||
static inline int sbi_hartmask_test_hart(u32 h, const struct sbi_hartmask *m)
|
||||
{
|
||||
if (h < SBI_HARTMASK_MAX_BITS)
|
||||
return __test_bit(h, m->bits);
|
||||
|
@@ -12,13 +12,14 @@
|
||||
#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);
|
||||
void __sbi_hfence_gvma_vmid_gpa(unsigned long gpa_divby_4,
|
||||
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);
|
||||
void __sbi_hfence_gvma_gpa(unsigned long gpa_divby_4);
|
||||
|
||||
/** Invalidate all possible Stage2 TLBs */
|
||||
void __sbi_hfence_gvma_all(void);
|
||||
|
@@ -12,25 +12,54 @@
|
||||
|
||||
#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
|
||||
/** Hart state managment device */
|
||||
struct sbi_hsm_device {
|
||||
/** Name of the hart state managment device */
|
||||
char name[32];
|
||||
|
||||
/** Start (or power-up) the given hart */
|
||||
int (*hart_start)(u32 hartid, ulong saddr);
|
||||
|
||||
/**
|
||||
* Stop (or power-down) the current hart from running. This call
|
||||
* doesn't expect to return if success.
|
||||
*/
|
||||
int (*hart_stop)(void);
|
||||
|
||||
/**
|
||||
* Put the current hart in platform specific suspend (or low-power)
|
||||
* state.
|
||||
*
|
||||
* For successful retentive suspend, the call will return 0 when
|
||||
* the hart resumes normal execution.
|
||||
*
|
||||
* For successful non-retentive suspend, the hart will resume from
|
||||
* specified resume address
|
||||
*/
|
||||
int (*hart_suspend)(u32 suspend_type, ulong raddr);
|
||||
};
|
||||
|
||||
struct sbi_domain;
|
||||
struct sbi_scratch;
|
||||
|
||||
const struct sbi_hsm_device *sbi_hsm_get_device(void);
|
||||
|
||||
void sbi_hsm_set_device(const struct sbi_hsm_device *dev);
|
||||
|
||||
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_start(struct sbi_scratch *scratch,
|
||||
const struct sbi_domain *dom,
|
||||
u32 hartid, ulong saddr, ulong smode, 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_hart_resume_start(struct sbi_scratch *scratch);
|
||||
void sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch);
|
||||
int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type,
|
||||
ulong raddr, ulong rmode, ulong priv);
|
||||
int sbi_hsm_hart_get_state(const struct sbi_domain *dom, u32 hartid);
|
||||
int sbi_hsm_hart_interruptible_mask(const struct sbi_domain *dom,
|
||||
ulong hbase, ulong *out_hmask);
|
||||
void sbi_hsm_prepare_next_jump(struct sbi_scratch *scratch, u32 hartid);
|
||||
|
||||
#endif
|
||||
|
@@ -18,6 +18,18 @@
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
/** IPI hardware device */
|
||||
struct sbi_ipi_device {
|
||||
/** Name of the IPI device */
|
||||
char name[32];
|
||||
|
||||
/** Send IPI to a target HART */
|
||||
void (*ipi_send)(u32 target_hart);
|
||||
|
||||
/** Clear IPI for a target HART */
|
||||
void (*ipi_clear)(u32 target_hart);
|
||||
};
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
/** IPI event operations or callbacks */
|
||||
@@ -63,6 +75,12 @@ int sbi_ipi_send_halt(ulong hmask, ulong hbase);
|
||||
|
||||
void sbi_ipi_process(void);
|
||||
|
||||
void sbi_ipi_raw_send(u32 target_hart);
|
||||
|
||||
const struct sbi_ipi_device *sbi_ipi_get_device(void);
|
||||
|
||||
void sbi_ipi_set_device(const struct sbi_ipi_device *dev);
|
||||
|
||||
int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||
|
||||
void sbi_ipi_exit(struct sbi_scratch *scratch);
|
||||
|
@@ -43,6 +43,17 @@ static inline void __sbi_list_add(struct sbi_dlist *new,
|
||||
next->prev = new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the list is empty or not.
|
||||
* @param head List head
|
||||
*
|
||||
* Retruns TRUE if list is empty, FALSE otherwise.
|
||||
*/
|
||||
static inline bool sbi_list_empty(struct sbi_dlist *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the new node after the given head.
|
||||
* @param new New node that needs to be added to list.
|
||||
|
@@ -38,32 +38,29 @@
|
||||
|
||||
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT (1UL << 12)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
#include <sbi/sbi_version.h>
|
||||
|
||||
struct sbi_domain_memregion;
|
||||
struct sbi_trap_info;
|
||||
struct sbi_trap_regs;
|
||||
|
||||
/** Possible feature flags of a platform */
|
||||
enum sbi_platform_features {
|
||||
/** Platform has timer value */
|
||||
SBI_PLATFORM_HAS_TIMER_VALUE = (1 << 0),
|
||||
/** Platform has HART hotplug support */
|
||||
SBI_PLATFORM_HAS_HART_HOTPLUG = (1 << 1),
|
||||
/** Platform has fault delegation support */
|
||||
SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 2),
|
||||
/** Platform has custom secondary hart booting support */
|
||||
SBI_PLATFORM_HAS_HART_SECONDARY_BOOT = (1 << 3),
|
||||
SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 1),
|
||||
|
||||
/** Last index of Platform features*/
|
||||
SBI_PLATFORM_HAS_LAST_FEATURE = SBI_PLATFORM_HAS_HART_SECONDARY_BOOT,
|
||||
SBI_PLATFORM_HAS_LAST_FEATURE = SBI_PLATFORM_HAS_MFAULTS_DELEGATION,
|
||||
};
|
||||
|
||||
/** Default feature set for a platform */
|
||||
#define SBI_PLATFORM_DEFAULT_FEATURES \
|
||||
(SBI_PLATFORM_HAS_TIMER_VALUE | SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
|
||||
(SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
|
||||
|
||||
/** Platform functions */
|
||||
struct sbi_platform_operations {
|
||||
@@ -89,19 +86,15 @@ struct sbi_platform_operations {
|
||||
*/
|
||||
int (*misa_get_xlen)(void);
|
||||
|
||||
/** Get number of PMP regions for given HART */
|
||||
u32 (*pmp_region_count)(u32 hartid);
|
||||
/**
|
||||
* Get PMP regions details (namely: protection, base address,
|
||||
* and size) for given HART
|
||||
*/
|
||||
int (*pmp_region_info)(u32 hartid, u32 index, ulong *prot, ulong *addr,
|
||||
ulong *log2size);
|
||||
/** Initialize (or populate) domains for the platform */
|
||||
int (*domains_init)(void);
|
||||
|
||||
/** Initialize hw performance counters */
|
||||
int (*pmu_init)(void);
|
||||
|
||||
/** Get platform specific mhpmevent value */
|
||||
uint64_t (*pmu_xlate_to_mhpmevent)(uint32_t event_idx, uint64_t data);
|
||||
|
||||
/** Write a character to the platform console output */
|
||||
void (*console_putc)(char ch);
|
||||
/** Read a character from the platform console input */
|
||||
int (*console_getc)(void);
|
||||
/** Initialize the platform console */
|
||||
int (*console_init)(void);
|
||||
|
||||
@@ -110,10 +103,6 @@ struct sbi_platform_operations {
|
||||
/** Exit the platform interrupt controller for current HART */
|
||||
void (*irqchip_exit)(void);
|
||||
|
||||
/** Send IPI to a target HART */
|
||||
void (*ipi_send)(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 */
|
||||
@@ -122,39 +111,19 @@ struct sbi_platform_operations {
|
||||
/** Get tlb flush limit value **/
|
||||
u64 (*get_tlbr_flush_limit)(void);
|
||||
|
||||
/** Get platform timer value */
|
||||
u64 (*timer_value)(void);
|
||||
/** Start platform timer event for current HART */
|
||||
void (*timer_event_start)(u64 next_event);
|
||||
/** Stop platform timer event for current HART */
|
||||
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);
|
||||
|
||||
/** 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,
|
||||
const struct sbi_trap_regs *regs,
|
||||
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
|
||||
@@ -201,7 +170,7 @@ struct sbi_platform {
|
||||
* 2. HART id < SBI_HARTMASK_MAX_BITS
|
||||
*/
|
||||
const u32 *hart_index2id;
|
||||
} __packed;
|
||||
};
|
||||
|
||||
/** Get pointer to sbi_platform for sbi_scratch pointer */
|
||||
#define sbi_platform_ptr(__s) \
|
||||
@@ -213,18 +182,9 @@ struct sbi_platform {
|
||||
#define sbi_platform_ops(__p) \
|
||||
((const struct sbi_platform_operations *)(__p)->platform_ops_addr)
|
||||
|
||||
/** Check whether the platform supports timer value */
|
||||
#define sbi_platform_has_timer_value(__p) \
|
||||
((__p)->features & SBI_PLATFORM_HAS_TIMER_VALUE)
|
||||
/** 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 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
|
||||
@@ -339,39 +299,6 @@ static inline bool sbi_platform_hart_invalid(const struct sbi_platform *plat,
|
||||
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
|
||||
*
|
||||
@@ -457,71 +384,50 @@ static inline int sbi_platform_misa_xlen(const struct sbi_platform *plat)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of PMP regions of a HART
|
||||
* Initialize (or populate) domains for the platform
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param hartid HART ID
|
||||
*
|
||||
* @return number of PMP regions
|
||||
*/
|
||||
static inline u32 sbi_platform_pmp_region_count(const struct sbi_platform *plat,
|
||||
u32 hartid)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->pmp_region_count)
|
||||
return sbi_platform_ops(plat)->pmp_region_count(hartid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get PMP regions details (namely: protection, base address,
|
||||
* and size) of a HART
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param hartid HART ID
|
||||
* @param index index of PMP region for which we want details
|
||||
* @param prot output pointer for PMP region protection
|
||||
* @param addr output pointer for PMP region base address
|
||||
* @param log2size output pointer for log-of-2 PMP region size
|
||||
*
|
||||
* @return 0 on success and negative error code on failure
|
||||
*/
|
||||
static inline int sbi_platform_pmp_region_info(const struct sbi_platform *plat,
|
||||
u32 hartid, u32 index,
|
||||
ulong *prot, ulong *addr,
|
||||
ulong *log2size)
|
||||
static inline int sbi_platform_domains_init(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->pmp_region_info)
|
||||
return sbi_platform_ops(plat)->pmp_region_info(hartid, index,
|
||||
prot, addr,
|
||||
log2size);
|
||||
if (plat && sbi_platform_ops(plat)->domains_init)
|
||||
return sbi_platform_ops(plat)->domains_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a character to the platform console output
|
||||
* Setup hw PMU events for the platform
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param ch character to write
|
||||
*
|
||||
* @return 0 on success and negative error code on failure
|
||||
*/
|
||||
static inline void sbi_platform_console_putc(const struct sbi_platform *plat,
|
||||
char ch)
|
||||
static inline int sbi_platform_pmu_init(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->console_putc)
|
||||
sbi_platform_ops(plat)->console_putc(ch);
|
||||
if (plat && sbi_platform_ops(plat)->pmu_init)
|
||||
return sbi_platform_ops(plat)->pmu_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a character from the platform console input
|
||||
* Get the value to be written in mhpmeventx for event_idx
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param event_idx ID of the PMU event
|
||||
* @param data Additional configuration data passed from supervisor software
|
||||
*
|
||||
* @return character read from console input
|
||||
* @return expected value by the platform or 0 if platform doesn't know about
|
||||
* the event
|
||||
*/
|
||||
static inline int sbi_platform_console_getc(const struct sbi_platform *plat)
|
||||
static inline uint64_t sbi_platform_pmu_xlate_to_mhpmevent(const struct sbi_platform *plat,
|
||||
uint32_t event_idx, uint64_t data)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->console_getc)
|
||||
return sbi_platform_ops(plat)->console_getc();
|
||||
return -1;
|
||||
if (plat && sbi_platform_ops(plat)->pmu_xlate_to_mhpmevent)
|
||||
return sbi_platform_ops(plat)->pmu_xlate_to_mhpmevent(event_idx,
|
||||
data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -565,32 +471,6 @@ static inline void sbi_platform_irqchip_exit(const struct sbi_platform *plat)
|
||||
sbi_platform_ops(plat)->irqchip_exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send IPI to a target HART
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param target_hart HART ID of IPI target
|
||||
*/
|
||||
static inline void sbi_platform_ipi_send(const struct sbi_platform *plat,
|
||||
u32 target_hart)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->ipi_send)
|
||||
sbi_platform_ops(plat)->ipi_send(target_hart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear IPI for a target HART
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param target_hart HART ID of IPI target
|
||||
*/
|
||||
static inline void sbi_platform_ipi_clear(const struct sbi_platform *plat,
|
||||
u32 target_hart)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->ipi_clear)
|
||||
sbi_platform_ops(plat)->ipi_clear(target_hart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the platform IPI support for current HART
|
||||
*
|
||||
@@ -618,45 +498,6 @@ static inline void sbi_platform_ipi_exit(const struct sbi_platform *plat)
|
||||
sbi_platform_ops(plat)->ipi_exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get platform timer value
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*
|
||||
* @return 64-bit timer value
|
||||
*/
|
||||
static inline u64 sbi_platform_timer_value(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->timer_value)
|
||||
return sbi_platform_ops(plat)->timer_value();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start platform timer event for current HART
|
||||
*
|
||||
* @param plat pointer to struct struct sbi_platform
|
||||
* @param next_event timer value when timer event will happen
|
||||
*/
|
||||
static inline void
|
||||
sbi_platform_timer_event_start(const struct sbi_platform *plat, u64 next_event)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->timer_event_start)
|
||||
sbi_platform_ops(plat)->timer_event_start(next_event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop platform timer event for current HART
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*/
|
||||
static inline void
|
||||
sbi_platform_timer_event_stop(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->timer_event_stop)
|
||||
sbi_platform_ops(plat)->timer_event_stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the platform timer for current HART
|
||||
*
|
||||
@@ -684,22 +525,6 @@ static inline void sbi_platform_timer_exit(const struct sbi_platform *plat)
|
||||
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_reset(const struct sbi_platform *plat,
|
||||
u32 reset_type)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->system_reset)
|
||||
return sbi_platform_ops(plat)->system_reset(reset_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a vendor extension is implemented or not.
|
||||
*
|
||||
@@ -723,7 +548,7 @@ static inline int sbi_platform_vendor_ext_check(const struct sbi_platform *plat,
|
||||
* @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 regs pointer to trap registers 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
|
||||
*
|
||||
@@ -732,13 +557,13 @@ static inline int sbi_platform_vendor_ext_check(const struct sbi_platform *plat,
|
||||
static inline int sbi_platform_vendor_ext_provider(
|
||||
const struct sbi_platform *plat,
|
||||
long extid, long funcid,
|
||||
unsigned long *args,
|
||||
const struct sbi_trap_regs *regs,
|
||||
unsigned long *out_value,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->vendor_ext_provider) {
|
||||
return sbi_platform_ops(plat)->vendor_ext_provider(extid,
|
||||
funcid, args,
|
||||
funcid, regs,
|
||||
out_value,
|
||||
out_trap);
|
||||
}
|
||||
|
74
include/sbi/sbi_pmu.h
Normal file
74
include/sbi/sbi_pmu.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Atish Patra <atish.patra@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __SBI_PMU_H__
|
||||
#define __SBI_PMU_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
#include <sbi/sbi_hartmask.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
|
||||
/* Event related macros */
|
||||
/* Maximum number of hardware events that can mapped by OpenSBI */
|
||||
#define SBI_PMU_HW_EVENT_MAX 64
|
||||
|
||||
/* Maximum number of firmware events that can mapped by OpenSBI */
|
||||
#define SBI_PMU_FW_EVENT_MAX 32
|
||||
|
||||
/* Counter related macros */
|
||||
#define SBI_PMU_FW_CTR_MAX 16
|
||||
#define SBI_PMU_HW_CTR_MAX 32
|
||||
#define SBI_PMU_CTR_MAX (SBI_PMU_HW_CTR_MAX + SBI_PMU_FW_CTR_MAX)
|
||||
#define SBI_PMU_FIXED_CTR_MASK 0x07
|
||||
|
||||
/** Initialize PMU */
|
||||
int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||
|
||||
/** Reset PMU during hart exit */
|
||||
void sbi_pmu_exit(struct sbi_scratch *scratch);
|
||||
|
||||
/**
|
||||
* Add the hardware event to counter mapping information. This should be called
|
||||
* from the platform code to update the mapping table.
|
||||
* @param eidx_start Start of the event idx range for supported counters
|
||||
* @param eidx_end End of the event idx range for supported counters
|
||||
* @param cmap A bitmap representing counters supporting the event range
|
||||
* @return 0 on success, error otherwise.
|
||||
*/
|
||||
int sbi_pmu_add_hw_event_counter_map(u32 eidx_start, u32 eidx_end, u32 cmap);
|
||||
|
||||
/**
|
||||
* Add the raw hardware event selector and supported counter information. This
|
||||
* should be called from the platform code to update the mapping table.
|
||||
* @param info a pointer to the hardware event info
|
||||
* @return 0 on success, error otherwise.
|
||||
*/
|
||||
|
||||
int sbi_pmu_add_raw_event_counter_map(uint64_t select, uint64_t select_mask, u32 cmap);
|
||||
|
||||
int sbi_pmu_ctr_read(uint32_t cidx, unsigned long *cval);
|
||||
|
||||
int sbi_pmu_ctr_stop(unsigned long cidx_base, unsigned long cidx_mask,
|
||||
unsigned long flag);
|
||||
|
||||
int sbi_pmu_ctr_start(unsigned long cidx_base, unsigned long cidx_mask,
|
||||
unsigned long flags, uint64_t ival);
|
||||
|
||||
int sbi_pmu_ctr_get_info(uint32_t cidx, unsigned long *ctr_info);
|
||||
|
||||
unsigned long sbi_pmu_num_ctr(void);
|
||||
|
||||
int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask,
|
||||
unsigned long flags, unsigned long event_idx,
|
||||
uint64_t event_data);
|
||||
|
||||
int sbi_pmu_ctr_incr_fw(enum sbi_pmu_fw_event_code_id fw_id);
|
||||
|
||||
#endif
|
@@ -30,18 +30,20 @@
|
||||
#define SBI_SCRATCH_PLATFORM_ADDR_OFFSET (6 * __SIZEOF_POINTER__)
|
||||
/** Offset of hartid_to_scratch member in sbi_scratch */
|
||||
#define SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET (7 * __SIZEOF_POINTER__)
|
||||
/** Offset of trap_exit member in sbi_scratch */
|
||||
#define SBI_SCRATCH_TRAP_EXIT_OFFSET (8 * __SIZEOF_POINTER__)
|
||||
/** Offset of tmp0 member in sbi_scratch */
|
||||
#define SBI_SCRATCH_TMP0_OFFSET (8 * __SIZEOF_POINTER__)
|
||||
#define SBI_SCRATCH_TMP0_OFFSET (9 * __SIZEOF_POINTER__)
|
||||
/** Offset of options member in sbi_scratch */
|
||||
#define SBI_SCRATCH_OPTIONS_OFFSET (9 * __SIZEOF_POINTER__)
|
||||
#define SBI_SCRATCH_OPTIONS_OFFSET (10 * __SIZEOF_POINTER__)
|
||||
/** Offset of extra space in sbi_scratch */
|
||||
#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (10 * __SIZEOF_POINTER__)
|
||||
#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (11 * __SIZEOF_POINTER__)
|
||||
/** Maximum size of sbi_scratch (4KB) */
|
||||
#define SBI_SCRATCH_SIZE (0x1000)
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
@@ -63,11 +65,13 @@ struct sbi_scratch {
|
||||
unsigned long platform_addr;
|
||||
/** Address of HART ID to sbi_scratch conversion function */
|
||||
unsigned long hartid_to_scratch;
|
||||
/** Address of trap exit function */
|
||||
unsigned long trap_exit;
|
||||
/** Temporary storage */
|
||||
unsigned long tmp0;
|
||||
/** Options for OpenSBI library */
|
||||
unsigned long options;
|
||||
} __packed;
|
||||
};
|
||||
|
||||
/** Possible options for OpenSBI library */
|
||||
enum sbi_scratch_options {
|
||||
@@ -85,7 +89,7 @@ enum sbi_scratch_options {
|
||||
#define sbi_scratch_thishart_arg1_ptr() \
|
||||
((void *)(sbi_scratch_thishart_ptr()->next_arg1))
|
||||
|
||||
/** Initialize scatch table and allocator */
|
||||
/** Initialize scratch table and allocator */
|
||||
int sbi_scratch_init(struct sbi_scratch *scratch);
|
||||
|
||||
/**
|
||||
@@ -94,7 +98,7 @@ int sbi_scratch_init(struct sbi_scratch *scratch);
|
||||
* @return zero on failure and non-zero (>= SBI_SCRATCH_EXTRA_SPACE_OFFSET)
|
||||
* on success
|
||||
*/
|
||||
unsigned long sbi_scratch_alloc_offset(unsigned long size, const char *owner);
|
||||
unsigned long sbi_scratch_alloc_offset(unsigned long size);
|
||||
|
||||
/** Free-up extra space in sbi_scratch */
|
||||
void sbi_scratch_free_offset(unsigned long offset);
|
||||
|
@@ -12,8 +12,15 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
/*
|
||||
Provides sbi_strcmp for the completeness of supporting string functions.
|
||||
it is not recommended to use sbi_strcmp() but use sbi_strncmp instead.
|
||||
*/
|
||||
|
||||
int sbi_strcmp(const char *a, const char *b);
|
||||
|
||||
int sbi_strncmp(const char *a, const char *b, size_t count);
|
||||
|
||||
size_t sbi_strlen(const char *str);
|
||||
|
||||
size_t sbi_strnlen(const char *str, size_t count);
|
||||
|
@@ -11,7 +11,36 @@
|
||||
#define __SBI_SYSTEM_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
#include <sbi/sbi_list.h>
|
||||
|
||||
void __noreturn sbi_system_reset(u32 platform_reset_type);
|
||||
/** System reset hardware device */
|
||||
struct sbi_system_reset_device {
|
||||
/** Name of the system reset device */
|
||||
char name[32];
|
||||
|
||||
/* Check whether reset type and reason supported by the device */
|
||||
int (*system_reset_check)(u32 reset_type, u32 reset_reason);
|
||||
|
||||
/** Reset the system */
|
||||
void (*system_reset)(u32 reset_type, u32 reset_reason);
|
||||
|
||||
/** List */
|
||||
struct sbi_dlist node;
|
||||
};
|
||||
|
||||
static inline struct sbi_system_reset_device *to_system_reset_device(
|
||||
struct sbi_dlist *node)
|
||||
{
|
||||
return container_of(node, struct sbi_system_reset_device, node);
|
||||
}
|
||||
|
||||
const struct sbi_system_reset_device *sbi_system_reset_get_device(
|
||||
u32 reset_type, u32 reset_reason);
|
||||
|
||||
void sbi_system_reset_add_device(struct sbi_system_reset_device *dev);
|
||||
|
||||
bool sbi_system_reset_supported(u32 reset_type, u32 reset_reason);
|
||||
|
||||
void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason);
|
||||
|
||||
#endif
|
||||
|
@@ -12,8 +12,42 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
/** Timer hardware device */
|
||||
struct sbi_timer_device {
|
||||
/** Name of the timer operations */
|
||||
char name[32];
|
||||
|
||||
/** Frequency of timer in HZ */
|
||||
unsigned long timer_freq;
|
||||
|
||||
/** Get free-running timer value */
|
||||
u64 (*timer_value)(void);
|
||||
|
||||
/** Start timer event for current HART */
|
||||
void (*timer_event_start)(u64 next_event);
|
||||
|
||||
/** Stop timer event for current HART */
|
||||
void (*timer_event_stop)(void);
|
||||
};
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
/** Generic delay loop of desired granularity */
|
||||
void sbi_timer_delay_loop(ulong units, u64 unit_freq,
|
||||
void (*delay_fn)(void *), void *opaque);
|
||||
|
||||
/** Provide delay in terms of milliseconds */
|
||||
static inline void sbi_timer_mdelay(ulong msecs)
|
||||
{
|
||||
sbi_timer_delay_loop(msecs, 1000, NULL, NULL);
|
||||
}
|
||||
|
||||
/** Provide delay in terms of microseconds */
|
||||
static inline void sbi_timer_udelay(ulong usecs)
|
||||
{
|
||||
sbi_timer_delay_loop(usecs, 1000000, NULL, NULL);
|
||||
}
|
||||
|
||||
/** Get timer value for current HART */
|
||||
u64 sbi_timer_value(void);
|
||||
|
||||
@@ -35,6 +69,12 @@ void sbi_timer_event_start(u64 next_event);
|
||||
/** Process timer event for current HART */
|
||||
void sbi_timer_process(void);
|
||||
|
||||
/** Get current timer device */
|
||||
const struct sbi_timer_device *sbi_timer_get_device(void);
|
||||
|
||||
/** Register timer device */
|
||||
void sbi_timer_set_device(const struct sbi_timer_device *dev);
|
||||
|
||||
/* Initialize timer */
|
||||
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||
|
||||
|
@@ -22,16 +22,6 @@
|
||||
|
||||
#define SBI_TLB_FIFO_NUM_ENTRIES 8
|
||||
|
||||
enum sbi_tlb_info_types {
|
||||
SBI_TLB_FLUSH_VMA,
|
||||
SBI_TLB_FLUSH_VMA_ASID,
|
||||
SBI_TLB_FLUSH_GVMA,
|
||||
SBI_TLB_FLUSH_GVMA_VMID,
|
||||
SBI_TLB_FLUSH_VVMA,
|
||||
SBI_TLB_FLUSH_VVMA_ASID,
|
||||
SBI_ITLB_FLUSH
|
||||
};
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
struct sbi_tlb_info {
|
||||
@@ -39,17 +29,25 @@ struct sbi_tlb_info {
|
||||
unsigned long size;
|
||||
unsigned long asid;
|
||||
unsigned long vmid;
|
||||
unsigned long type;
|
||||
void (*local_fn)(struct sbi_tlb_info *tinfo);
|
||||
struct sbi_hartmask smask;
|
||||
};
|
||||
|
||||
#define SBI_TLB_INFO_INIT(__p, __start, __size, __asid, __vmid, __type, __src) \
|
||||
void sbi_tlb_local_hfence_vvma(struct sbi_tlb_info *tinfo);
|
||||
void sbi_tlb_local_hfence_gvma(struct sbi_tlb_info *tinfo);
|
||||
void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo);
|
||||
void sbi_tlb_local_hfence_vvma_asid(struct sbi_tlb_info *tinfo);
|
||||
void sbi_tlb_local_hfence_gvma_vmid(struct sbi_tlb_info *tinfo);
|
||||
void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo);
|
||||
void sbi_tlb_local_fence_i(struct sbi_tlb_info *tinfo);
|
||||
|
||||
#define SBI_TLB_INFO_INIT(__p, __start, __size, __asid, __vmid, __lfn, __src) \
|
||||
do { \
|
||||
(__p)->start = (__start); \
|
||||
(__p)->size = (__size); \
|
||||
(__p)->asid = (__asid); \
|
||||
(__p)->vmid = (__vmid); \
|
||||
(__p)->type = (__type); \
|
||||
(__p)->local_fn = (__lfn); \
|
||||
SBI_HARTMASK_INIT_EXCEPT(&(__p)->smask, (__src)); \
|
||||
} while (0)
|
||||
|
||||
|
@@ -110,7 +110,7 @@
|
||||
/** Size (in bytes) of sbi_trap_info */
|
||||
#define SBI_TRAP_INFO_SIZE SBI_TRAP_INFO_OFFSET(last)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
@@ -186,7 +186,7 @@ struct sbi_trap_regs {
|
||||
unsigned long mstatus;
|
||||
/** mstatusH register state (only for 32-bit) */
|
||||
unsigned long mstatusH;
|
||||
} __packed;
|
||||
};
|
||||
|
||||
/** Representation of trap details */
|
||||
struct sbi_trap_info {
|
||||
@@ -205,7 +205,9 @@ struct sbi_trap_info {
|
||||
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_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs);
|
||||
|
||||
void __noreturn sbi_trap_exit(const struct sbi_trap_regs *regs);
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -63,12 +63,19 @@ typedef unsigned long physical_size_t;
|
||||
|
||||
#define __packed __attribute__((packed))
|
||||
#define __noreturn __attribute__((noreturn))
|
||||
#define __aligned(x) __attribute__((aligned(x)))
|
||||
|
||||
#define likely(x) __builtin_expect((x), 1)
|
||||
#define unlikely(x) __builtin_expect((x), 0)
|
||||
|
||||
#ifndef __has_builtin
|
||||
#define __has_builtin(...) 0
|
||||
#endif
|
||||
|
||||
#undef offsetof
|
||||
#ifdef __compiler_offsetof
|
||||
#if __has_builtin(__builtin_offsetof)
|
||||
#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE,MEMBER)
|
||||
#elif defined(__compiler_offsetof)
|
||||
#define offsetof(TYPE, MEMBER) __compiler_offsetof(TYPE,MEMBER)
|
||||
#else
|
||||
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||
|
@@ -10,8 +10,8 @@
|
||||
#ifndef __SBI_VERSION_H__
|
||||
#define __SBI_VERSION_H__
|
||||
|
||||
#define OPENSBI_VERSION_MAJOR 0
|
||||
#define OPENSBI_VERSION_MINOR 8
|
||||
#define OPENSBI_VERSION_MAJOR 1
|
||||
#define OPENSBI_VERSION_MINOR 0
|
||||
|
||||
/**
|
||||
* OpenSBI 32-bit version with:
|
||||
|
73
include/sbi_utils/fdt/fdt_domain.h
Normal file
73
include/sbi_utils/fdt/fdt_domain.h
Normal file
@@ -0,0 +1,73 @@
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
/*
|
||||
* fdt_domain.c - Flat Device Tree Domain helper routines
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __FDT_DOMAIN_H__
|
||||
#define __FDT_DOMAIN_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
struct sbi_domain;
|
||||
|
||||
/**
|
||||
* Iterate over each domains in device tree
|
||||
*
|
||||
* @param fdt device tree blob
|
||||
* @param opaque private pointer for each iteration
|
||||
* @param fn callback function for each iteration
|
||||
*
|
||||
* @return 0 on success and negative error code on failure
|
||||
*/
|
||||
int fdt_iterate_each_domain(void *fdt, void *opaque,
|
||||
int (*fn)(void *fdt, int domain_offset,
|
||||
void *opaque));
|
||||
|
||||
/**
|
||||
* Iterate over each memregion of a domain in device tree
|
||||
*
|
||||
* @param fdt device tree blob
|
||||
* @param domain_offset domain DT node offset
|
||||
* @param opaque private pointer for each iteration
|
||||
* @param fn callback function for each iteration
|
||||
*
|
||||
* @return 0 on success and negative error code on failure
|
||||
*/
|
||||
int fdt_iterate_each_memregion(void *fdt, int domain_offset, void *opaque,
|
||||
int (*fn)(void *fdt, int domain_offset,
|
||||
int region_offset, u32 region_access,
|
||||
void *opaque));
|
||||
|
||||
/**
|
||||
* Fix up the domain configuration in the device tree
|
||||
*
|
||||
* This routine:
|
||||
* 1. Disables MMIO devices not accessible to the coldboot HART domain
|
||||
* 2. Removes "opensbi-domain" DT property from CPU DT nodes
|
||||
* 3. Removes domain configuration DT node under /chosen DT node
|
||||
*
|
||||
* It is recommended that platform support call this function in
|
||||
* their final_init() platform operation.
|
||||
*
|
||||
* @param fdt device tree blob
|
||||
*/
|
||||
void fdt_domain_fixup(void *fdt);
|
||||
|
||||
/**
|
||||
* Populate domains from device tree
|
||||
*
|
||||
* It is recommended that platform support call this function in
|
||||
* their domains_init() platform operation.
|
||||
*
|
||||
* @param fdt device tree blob
|
||||
*
|
||||
* @return 0 on success and negative error code on failure
|
||||
*/
|
||||
int fdt_domains_populate(void *fdt);
|
||||
|
||||
#endif /* __FDT_DOMAIN_H__ */
|
@@ -30,9 +30,8 @@ void fdt_cpu_fixup(void *fdt);
|
||||
* 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);
|
||||
void fdt_plic_fixup(void *fdt);
|
||||
|
||||
/**
|
||||
* Fix up the reserved memory node in the device tree
|
||||
|
@@ -11,12 +11,20 @@
|
||||
#define __FDT_HELPER_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
|
||||
struct fdt_match {
|
||||
const char *compatible;
|
||||
void *data;
|
||||
};
|
||||
|
||||
#define FDT_MAX_PHANDLE_ARGS 16
|
||||
struct fdt_phandle_args {
|
||||
int node_offset;
|
||||
int args_count;
|
||||
u32 args[FDT_MAX_PHANDLE_ARGS];
|
||||
};
|
||||
|
||||
struct platform_uart_data {
|
||||
unsigned long addr;
|
||||
unsigned long freq;
|
||||
@@ -32,13 +40,22 @@ 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_phandle_with_args(void *fdt, int nodeoff,
|
||||
const char *prop, const char *cells_prop,
|
||||
int index, struct fdt_phandle_args *out_args);
|
||||
|
||||
int fdt_get_node_addr_size(void *fdt, int node, int index,
|
||||
uint64_t *addr, uint64_t *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_timebase_frequency(void *fdt, unsigned long *freq);
|
||||
|
||||
int fdt_parse_gaisler_uart_node(void *fdt, int nodeoffset,
|
||||
struct platform_uart_data *uart);
|
||||
|
||||
int fdt_parse_shakti_uart_node(void *fdt, int nodeoffset,
|
||||
struct platform_uart_data *uart);
|
||||
|
||||
@@ -57,12 +74,17 @@ 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_aclint_node(void *fdt, int nodeoffset, bool for_timer,
|
||||
unsigned long *out_addr1, unsigned long *out_size1,
|
||||
unsigned long *out_addr2, unsigned long *out_size2,
|
||||
u32 *out_first_hartid, u32 *out_hart_count);
|
||||
|
||||
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,
|
||||
int fdt_parse_compat_addr(void *fdt, uint64_t *addr,
|
||||
const char *compatible);
|
||||
|
||||
static inline void *fdt_get_address(void)
|
||||
{
|
||||
return sbi_scratch_thishart_arg1_ptr();
|
||||
}
|
||||
|
||||
#endif /* __FDT_HELPER_H__ */
|
||||
|
46
include/sbi_utils/fdt/fdt_pmu.h
Normal file
46
include/sbi_utils/fdt/fdt_pmu.h
Normal file
@@ -0,0 +1,46 @@
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
/*
|
||||
* fdt_pmu.c - Flat Device Tree PMU helper routines
|
||||
*
|
||||
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Atish Patra <atish.patra@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __FDT_PMU_H__
|
||||
#define __FDT_PMU_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
/**
|
||||
* Fix up the PMU node in the device tree
|
||||
*
|
||||
* This routine:
|
||||
* 1. Disables opensbi specific properties from the DT
|
||||
*
|
||||
* It is recommended that platform support call this function in
|
||||
* their final_init() platform operation.
|
||||
*
|
||||
* @param fdt device tree blob
|
||||
*/
|
||||
void fdt_pmu_fixup(void *fdt);
|
||||
|
||||
/**
|
||||
* Setup PMU data from device tree
|
||||
*
|
||||
* @param fdt device tree blob
|
||||
*
|
||||
* @return 0 on success and negative error code on failure
|
||||
*/
|
||||
int fdt_pmu_setup(void *fdt);
|
||||
|
||||
/**
|
||||
* Get the mhpmevent select value read from DT for a given event
|
||||
* @param event_idx Event ID of the given event
|
||||
*
|
||||
* @return The select value read from DT or 0 if given index was not found
|
||||
*/
|
||||
uint64_t fdt_pmu_get_select_value(uint32_t event_idx);
|
||||
|
||||
#endif
|
34
include/sbi_utils/gpio/fdt_gpio.h
Normal file
34
include/sbi_utils/gpio/fdt_gpio.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __FDT_GPIO_H__
|
||||
#define __FDT_GPIO_H__
|
||||
|
||||
#include <sbi_utils/gpio/gpio.h>
|
||||
|
||||
/** FDT based GPIO driver */
|
||||
struct fdt_gpio {
|
||||
const struct fdt_match *match_table;
|
||||
int (*xlate)(struct gpio_chip *chip,
|
||||
const struct fdt_phandle_args *pargs,
|
||||
struct gpio_pin *out_pin);
|
||||
int (*init)(void *fdt, int nodeoff, u32 phandle,
|
||||
const struct fdt_match *match);
|
||||
};
|
||||
|
||||
/** Get a GPIO pin using "gpios" DT property of client DT node */
|
||||
int fdt_gpio_pin_get(void *fdt, int nodeoff, int index,
|
||||
struct gpio_pin *out_pin);
|
||||
|
||||
/** Simple xlate function to convert two GPIO FDT cells into GPIO pin */
|
||||
int fdt_gpio_simple_xlate(struct gpio_chip *chip,
|
||||
const struct fdt_phandle_args *pargs,
|
||||
struct gpio_pin *out_pin);
|
||||
|
||||
#endif
|
107
include/sbi_utils/gpio/gpio.h
Normal file
107
include/sbi_utils/gpio/gpio.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __GPIO_H__
|
||||
#define __GPIO_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
#include <sbi/sbi_list.h>
|
||||
|
||||
#define GPIO_LINE_DIRECTION_IN 1
|
||||
#define GPIO_LINE_DIRECTION_OUT 0
|
||||
|
||||
/** Representation of a GPIO pin */
|
||||
struct gpio_pin {
|
||||
/** Pointer to the GPIO chip */
|
||||
struct gpio_chip *chip;
|
||||
/** Identification of GPIO pin within GPIO chip */
|
||||
unsigned int offset;
|
||||
/**
|
||||
* Additional configuration flags of the GPIO pin desired
|
||||
* by GPIO clients.
|
||||
*
|
||||
* NOTE: GPIO chip can have custom configuration flags.
|
||||
*/
|
||||
unsigned int flags;
|
||||
#define GPIO_FLAG_ACTIVE_LOW 0x1
|
||||
#define GPIO_FLAG_SINGLE_ENDED 0x2
|
||||
#define GPIO_FLAG_OPEN_DRAIN 0x4
|
||||
#define GPIO_FLAG_TRANSITORY 0x8
|
||||
#define GPIO_FLAG_PULL_UP 0x10
|
||||
#define GPIO_FLAG_PULL_DOWN 0x20
|
||||
};
|
||||
|
||||
/** Representation of a GPIO chip */
|
||||
struct gpio_chip {
|
||||
/** Pointer to GPIO driver owning this GPIO chip */
|
||||
void *driver;
|
||||
/** Uniquie ID of the GPIO chip assigned by the driver */
|
||||
unsigned int id;
|
||||
/** Number of GPIOs supported by the GPIO chip */
|
||||
unsigned int ngpio;
|
||||
/**
|
||||
* Get current direction of GPIO pin
|
||||
*
|
||||
* @return 0=output, 1=input, or negative error
|
||||
*/
|
||||
int (*get_direction)(struct gpio_pin *gp);
|
||||
/**
|
||||
* Set input direction of GPIO pin
|
||||
*
|
||||
* @return 0 on success and negative error code on failure
|
||||
*/
|
||||
int (*direction_input)(struct gpio_pin *gp);
|
||||
/**
|
||||
* Set output direction of GPIO pin with given output value
|
||||
*
|
||||
* @return 0 on success and negative error code on failure
|
||||
*/
|
||||
int (*direction_output)(struct gpio_pin *gp, int value);
|
||||
/**
|
||||
* Get current value of GPIO pin
|
||||
*
|
||||
* @return 0=low, 1=high, or negative error
|
||||
*/
|
||||
int (*get)(struct gpio_pin *gp);
|
||||
/** Set output value for GPIO pin */
|
||||
void (*set)(struct gpio_pin *gp, int value);
|
||||
/** List */
|
||||
struct sbi_dlist node;
|
||||
};
|
||||
|
||||
static inline struct gpio_chip *to_gpio_chip(struct sbi_dlist *node)
|
||||
{
|
||||
return container_of(node, struct gpio_chip, node);
|
||||
}
|
||||
|
||||
/** Find a registered GPIO chip */
|
||||
struct gpio_chip *gpio_chip_find(unsigned int id);
|
||||
|
||||
/** Register GPIO chip */
|
||||
int gpio_chip_add(struct gpio_chip *gc);
|
||||
|
||||
/** Un-register GPIO chip */
|
||||
void gpio_chip_remove(struct gpio_chip *gc);
|
||||
|
||||
/** Get current direction of GPIO pin */
|
||||
int gpio_get_direction(struct gpio_pin *gp);
|
||||
|
||||
/** Set input direction of GPIO pin */
|
||||
int gpio_direction_input(struct gpio_pin *gp);
|
||||
|
||||
/** Set output direction of GPIO pin */
|
||||
int gpio_direction_output(struct gpio_pin *gp, int value);
|
||||
|
||||
/** Get current value of GPIO pin */
|
||||
int gpio_get(struct gpio_pin *gp);
|
||||
|
||||
/** Set output value of GPIO pin */
|
||||
int gpio_set(struct gpio_pin *gp, int value);
|
||||
|
||||
#endif
|
26
include/sbi_utils/i2c/fdt_i2c.h
Normal file
26
include/sbi_utils/i2c/fdt_i2c.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2021 YADRO
|
||||
*
|
||||
* Authors:
|
||||
* Nikita Shubin <n.shubin@yadro.com>
|
||||
*/
|
||||
|
||||
#ifndef __FDT_I2C_H__
|
||||
#define __FDT_I2C_H__
|
||||
|
||||
#include <sbi_utils/i2c/i2c.h>
|
||||
|
||||
/** FDT based I2C adapter driver */
|
||||
struct fdt_i2c_adapter {
|
||||
const struct fdt_match *match_table;
|
||||
int (*init)(void *fdt, int nodeoff,
|
||||
const struct fdt_match *match);
|
||||
};
|
||||
|
||||
/** Get I2C adapter identified by nodeoff */
|
||||
int fdt_i2c_adapter_get(void *fdt, int nodeoff,
|
||||
struct i2c_adapter **out_adapter);
|
||||
|
||||
#endif
|
85
include/sbi_utils/i2c/i2c.h
Normal file
85
include/sbi_utils/i2c/i2c.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2021 YADRO
|
||||
*
|
||||
* Authors:
|
||||
* Nikita Shubin <n.shubin@yadro.com>
|
||||
*/
|
||||
|
||||
#ifndef __I2C_H__
|
||||
#define __I2C_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
#include <sbi/sbi_list.h>
|
||||
|
||||
/** Representation of a I2C adapter */
|
||||
struct i2c_adapter {
|
||||
/** Pointer to I2C driver owning this I2C adapter */
|
||||
void *driver;
|
||||
|
||||
/** Unique ID of the I2C adapter assigned by the driver */
|
||||
int id;
|
||||
|
||||
/**
|
||||
* Send buffer to given address, register
|
||||
*
|
||||
* @return 0 on success and negative error code on failure
|
||||
*/
|
||||
int (*write)(struct i2c_adapter *ia, uint8_t addr, uint8_t reg,
|
||||
uint8_t *buffer, int len);
|
||||
|
||||
/**
|
||||
* Read buffer from given address, register
|
||||
*
|
||||
* @return 0 on success and negative error code on failure
|
||||
*/
|
||||
int (*read)(struct i2c_adapter *ia, uint8_t addr, uint8_t reg,
|
||||
uint8_t *buffer, int len);
|
||||
|
||||
/** List */
|
||||
struct sbi_dlist node;
|
||||
};
|
||||
|
||||
static inline struct i2c_adapter *to_i2c_adapter(struct sbi_dlist *node)
|
||||
{
|
||||
return container_of(node, struct i2c_adapter, node);
|
||||
}
|
||||
|
||||
/** Find a registered I2C adapter */
|
||||
struct i2c_adapter *i2c_adapter_find(int id);
|
||||
|
||||
/** Register I2C adapter */
|
||||
int i2c_adapter_add(struct i2c_adapter *ia);
|
||||
|
||||
/** Un-register I2C adapter */
|
||||
void i2c_adapter_remove(struct i2c_adapter *ia);
|
||||
|
||||
/** Send to device on I2C adapter bus */
|
||||
int i2c_adapter_write(struct i2c_adapter *ia, uint8_t addr, uint8_t reg,
|
||||
uint8_t *buffer, int len);
|
||||
|
||||
/** Read from device on I2C adapter bus */
|
||||
int i2c_adapter_read(struct i2c_adapter *ia, uint8_t addr, uint8_t reg,
|
||||
uint8_t *buffer, int len);
|
||||
|
||||
static inline int i2c_adapter_reg_write(struct i2c_adapter *ia, uint8_t addr,
|
||||
uint8_t reg, uint8_t val)
|
||||
{
|
||||
return i2c_adapter_write(ia, addr, reg, &val, 1);
|
||||
}
|
||||
|
||||
static inline int i2c_adapter_reg_read(struct i2c_adapter *ia, uint8_t addr,
|
||||
uint8_t reg, uint8_t *val)
|
||||
{
|
||||
uint8_t buf;
|
||||
int ret = i2c_adapter_read(ia, addr, reg, &buf, 1);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = buf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
33
include/sbi_utils/ipi/aclint_mswi.h
Normal file
33
include/sbi_utils/ipi/aclint_mswi.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __IPI_ACLINT_MSWI_H__
|
||||
#define __IPI_ACLINT_MSWI_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
#define ACLINT_MSWI_ALIGN 0x1000
|
||||
#define ACLINT_MSWI_SIZE 0x4000
|
||||
#define ACLINT_MSWI_MAX_HARTS 4095
|
||||
|
||||
#define CLINT_MSWI_OFFSET 0x0000
|
||||
|
||||
struct aclint_mswi_data {
|
||||
/* Public details */
|
||||
unsigned long addr;
|
||||
unsigned long size;
|
||||
u32 first_hartid;
|
||||
u32 hart_count;
|
||||
};
|
||||
|
||||
int aclint_mswi_warm_init(void);
|
||||
|
||||
int aclint_mswi_cold_init(struct aclint_mswi_data *mswi);
|
||||
|
||||
#endif
|
@@ -17,14 +17,8 @@ struct fdt_ipi {
|
||||
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);
|
||||
|
@@ -15,11 +15,18 @@
|
||||
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);
|
||||
/**
|
||||
* fdt_reset_driver_init() - initialize reset driver based on the device-tree
|
||||
*/
|
||||
int fdt_reset_driver_init(void *fdt, struct fdt_reset *drv);
|
||||
|
||||
int fdt_reset_init(void);
|
||||
/**
|
||||
* fdt_reset_init() - initialize reset drivers based on the device-tree
|
||||
*
|
||||
* This function shall be invoked in final init.
|
||||
*/
|
||||
void fdt_reset_init(void);
|
||||
|
||||
#endif
|
||||
|
@@ -15,14 +15,8 @@
|
||||
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
|
||||
|
17
include/sbi_utils/serial/gaisler-uart.h
Normal file
17
include/sbi_utils/serial/gaisler-uart.h
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2021 Cobham Gaisler AB.
|
||||
*
|
||||
* Authors:
|
||||
* Daniel Cederman <cederman@gaisler.com>
|
||||
*/
|
||||
|
||||
#ifndef __SERIAL_GAISLER_APBUART_H__
|
||||
#define __SERIAL_GAISLER_APBUART_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
int gaisler_uart_init(unsigned long base, u32 in_freq, u32 baudrate);
|
||||
|
||||
#endif
|
17
include/sbi_utils/serial/litex-uart.h
Normal file
17
include/sbi_utils/serial/litex-uart.h
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2021 Gabriel Somlo
|
||||
*
|
||||
* Authors:
|
||||
* Gabriel Somlo <gsomlo@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __SERIAL_LITEX_UART_H__
|
||||
#define __SERIAL_LITEX_UART_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
int litex_uart_init(unsigned long base);
|
||||
|
||||
#endif
|
@@ -9,10 +9,6 @@
|
||||
|
||||
#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,10 +12,6 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
void sifive_uart_putc(char ch);
|
||||
|
||||
int sifive_uart_getc(void);
|
||||
|
||||
int sifive_uart_init(unsigned long base, u32 in_freq, u32 baudrate);
|
||||
|
||||
#endif
|
||||
|
@@ -12,10 +12,6 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
void uart8250_putc(char ch);
|
||||
|
||||
int uart8250_getc(void);
|
||||
|
||||
int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
|
||||
u32 reg_width);
|
||||
|
||||
|
@@ -1,51 +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 __SYS_CLINT_H__
|
||||
#define __SYS_CLINT_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
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_send(u32 target_hart);
|
||||
|
||||
void clint_ipi_clear(u32 target_hart);
|
||||
|
||||
int clint_warm_ipi_init(void);
|
||||
|
||||
int clint_cold_ipi_init(struct clint_data *clint);
|
||||
|
||||
u64 clint_timer_value(void);
|
||||
|
||||
void clint_timer_event_stop(void);
|
||||
|
||||
void clint_timer_event_start(u64 next_event);
|
||||
|
||||
int clint_warm_timer_init(void);
|
||||
|
||||
int clint_cold_timer_init(struct clint_data *clint,
|
||||
struct clint_data *reference);
|
||||
|
||||
#endif
|
@@ -10,10 +10,8 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
void htif_putc(char ch);
|
||||
int htif_serial_init(void);
|
||||
|
||||
int htif_getc(void);
|
||||
|
||||
int htif_system_reset(u32 type);
|
||||
int htif_system_reset_init(void);
|
||||
|
||||
#endif
|
||||
|
@@ -12,8 +12,6 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
int sifive_test_system_reset(u32 type);
|
||||
|
||||
int sifive_test_init(unsigned long base);
|
||||
|
||||
#endif
|
||||
|
53
include/sbi_utils/timer/aclint_mtimer.h
Normal file
53
include/sbi_utils/timer/aclint_mtimer.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __TIMER_ACLINT_MTIMER_H__
|
||||
#define __TIMER_ACLINT_MTIMER_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
#define ACLINT_MTIMER_ALIGN 0x8
|
||||
#define ACLINT_MTIMER_MAX_HARTS 4095
|
||||
|
||||
#define ACLINT_DEFAULT_MTIME_OFFSET 0x7ff8
|
||||
#define ACLINT_DEFAULT_MTIME_SIZE 0x8
|
||||
#define ACLINT_DEFAULT_MTIMECMP_OFFSET 0x0000
|
||||
#define ACLINT_DEFAULT_MTIMECMP_SIZE 0x7ff8
|
||||
|
||||
#define CLINT_MTIMER_OFFSET 0x4000
|
||||
|
||||
struct aclint_mtimer_data {
|
||||
/* Public details */
|
||||
unsigned long mtime_freq;
|
||||
unsigned long mtime_addr;
|
||||
unsigned long mtime_size;
|
||||
unsigned long mtimecmp_addr;
|
||||
unsigned long mtimecmp_size;
|
||||
u32 first_hartid;
|
||||
u32 hart_count;
|
||||
bool has_64bit_mmio;
|
||||
bool has_shared_mtime;
|
||||
/* Private details (initialized and used by ACLINT MTIMER library) */
|
||||
struct aclint_mtimer_data *time_delta_reference;
|
||||
unsigned long time_delta_computed;
|
||||
u64 (*time_rd)(volatile u64 *addr);
|
||||
void (*time_wr)(bool timecmp, u64 value, volatile u64 *addr);
|
||||
};
|
||||
|
||||
void aclint_mtimer_sync(struct aclint_mtimer_data *mt);
|
||||
|
||||
void aclint_mtimer_set_reference(struct aclint_mtimer_data *mt,
|
||||
struct aclint_mtimer_data *ref);
|
||||
|
||||
int aclint_mtimer_warm_init(void);
|
||||
|
||||
int aclint_mtimer_cold_init(struct aclint_mtimer_data *mt,
|
||||
struct aclint_mtimer_data *reference);
|
||||
|
||||
#endif
|
@@ -17,17 +17,8 @@ struct fdt_timer {
|
||||
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);
|
||||
|
@@ -15,10 +15,12 @@ libsbi-objs-y += riscv_locks.o
|
||||
libsbi-objs-y += sbi_bitmap.o
|
||||
libsbi-objs-y += sbi_bitops.o
|
||||
libsbi-objs-y += sbi_console.o
|
||||
libsbi-objs-y += sbi_domain.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_pmu.o
|
||||
libsbi-objs-y += sbi_ecall_replace.o
|
||||
libsbi-objs-y += sbi_ecall_vendor.o
|
||||
libsbi-objs-y += sbi_emulate_csr.o
|
||||
@@ -32,6 +34,7 @@ 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_pmu.o
|
||||
libsbi-objs-y += sbi_scratch.o
|
||||
libsbi-objs-y += sbi_string.o
|
||||
libsbi-objs-y += sbi_system.o
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
|
||||
/* determine CPU extension, return non-zero support */
|
||||
int misa_extension_imp(char ext)
|
||||
@@ -75,6 +76,8 @@ void misa_string(int xlen, char *out, unsigned int out_sz)
|
||||
out[pos++] = '8';
|
||||
break;
|
||||
default:
|
||||
sbi_panic("%s: Unknown misa.MXL encoding %d",
|
||||
__func__, xlen);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -90,148 +93,147 @@ void misa_string(int xlen, char *out, unsigned int out_sz)
|
||||
|
||||
unsigned long csr_read_num(int csr_num)
|
||||
{
|
||||
#define switchcase_csr_read(__csr_num, __val) \
|
||||
case __csr_num: \
|
||||
__val = csr_read(__csr_num); \
|
||||
break;
|
||||
#define switchcase_csr_read_2(__csr_num, __val) \
|
||||
switchcase_csr_read(__csr_num + 0, __val) \
|
||||
switchcase_csr_read(__csr_num + 1, __val)
|
||||
#define switchcase_csr_read_4(__csr_num, __val) \
|
||||
switchcase_csr_read_2(__csr_num + 0, __val) \
|
||||
switchcase_csr_read_2(__csr_num + 2, __val)
|
||||
#define switchcase_csr_read_8(__csr_num, __val) \
|
||||
switchcase_csr_read_4(__csr_num + 0, __val) \
|
||||
switchcase_csr_read_4(__csr_num + 4, __val)
|
||||
#define switchcase_csr_read_16(__csr_num, __val) \
|
||||
switchcase_csr_read_8(__csr_num + 0, __val) \
|
||||
switchcase_csr_read_8(__csr_num + 8, __val)
|
||||
#define switchcase_csr_read_32(__csr_num, __val) \
|
||||
switchcase_csr_read_16(__csr_num + 0, __val) \
|
||||
switchcase_csr_read_16(__csr_num + 16, __val)
|
||||
#define switchcase_csr_read_64(__csr_num, __val) \
|
||||
switchcase_csr_read_32(__csr_num + 0, __val) \
|
||||
switchcase_csr_read_32(__csr_num + 32, __val)
|
||||
|
||||
unsigned long ret = 0;
|
||||
|
||||
switch (csr_num) {
|
||||
case CSR_PMPCFG0:
|
||||
ret = csr_read(CSR_PMPCFG0);
|
||||
break;
|
||||
case CSR_PMPCFG1:
|
||||
ret = csr_read(CSR_PMPCFG1);
|
||||
break;
|
||||
case CSR_PMPCFG2:
|
||||
ret = csr_read(CSR_PMPCFG2);
|
||||
break;
|
||||
case CSR_PMPCFG3:
|
||||
ret = csr_read(CSR_PMPCFG3);
|
||||
break;
|
||||
case CSR_PMPADDR0:
|
||||
ret = csr_read(CSR_PMPADDR0);
|
||||
break;
|
||||
case CSR_PMPADDR1:
|
||||
ret = csr_read(CSR_PMPADDR1);
|
||||
break;
|
||||
case CSR_PMPADDR2:
|
||||
ret = csr_read(CSR_PMPADDR2);
|
||||
break;
|
||||
case CSR_PMPADDR3:
|
||||
ret = csr_read(CSR_PMPADDR3);
|
||||
break;
|
||||
case CSR_PMPADDR4:
|
||||
ret = csr_read(CSR_PMPADDR4);
|
||||
break;
|
||||
case CSR_PMPADDR5:
|
||||
ret = csr_read(CSR_PMPADDR5);
|
||||
break;
|
||||
case CSR_PMPADDR6:
|
||||
ret = csr_read(CSR_PMPADDR6);
|
||||
break;
|
||||
case CSR_PMPADDR7:
|
||||
ret = csr_read(CSR_PMPADDR7);
|
||||
break;
|
||||
case CSR_PMPADDR8:
|
||||
ret = csr_read(CSR_PMPADDR8);
|
||||
break;
|
||||
case CSR_PMPADDR9:
|
||||
ret = csr_read(CSR_PMPADDR9);
|
||||
break;
|
||||
case CSR_PMPADDR10:
|
||||
ret = csr_read(CSR_PMPADDR10);
|
||||
break;
|
||||
case CSR_PMPADDR11:
|
||||
ret = csr_read(CSR_PMPADDR11);
|
||||
break;
|
||||
case CSR_PMPADDR12:
|
||||
ret = csr_read(CSR_PMPADDR12);
|
||||
break;
|
||||
case CSR_PMPADDR13:
|
||||
ret = csr_read(CSR_PMPADDR13);
|
||||
break;
|
||||
case CSR_PMPADDR14:
|
||||
ret = csr_read(CSR_PMPADDR14);
|
||||
break;
|
||||
case CSR_PMPADDR15:
|
||||
ret = csr_read(CSR_PMPADDR15);
|
||||
break;
|
||||
switchcase_csr_read_16(CSR_PMPCFG0, ret)
|
||||
switchcase_csr_read_64(CSR_PMPADDR0, ret)
|
||||
switchcase_csr_read(CSR_MCYCLE, ret)
|
||||
switchcase_csr_read(CSR_MINSTRET, ret)
|
||||
switchcase_csr_read(CSR_MHPMCOUNTER3, ret)
|
||||
switchcase_csr_read_4(CSR_MHPMCOUNTER4, ret)
|
||||
switchcase_csr_read_8(CSR_MHPMCOUNTER8, ret)
|
||||
switchcase_csr_read_16(CSR_MHPMCOUNTER16, ret)
|
||||
switchcase_csr_read(CSR_MCOUNTINHIBIT, ret)
|
||||
switchcase_csr_read(CSR_MHPMEVENT3, ret)
|
||||
switchcase_csr_read_4(CSR_MHPMEVENT4, ret)
|
||||
switchcase_csr_read_8(CSR_MHPMEVENT8, ret)
|
||||
switchcase_csr_read_16(CSR_MHPMEVENT16, ret)
|
||||
#if __riscv_xlen == 32
|
||||
switchcase_csr_read(CSR_MCYCLEH, ret)
|
||||
switchcase_csr_read(CSR_MINSTRETH, ret)
|
||||
switchcase_csr_read(CSR_MHPMCOUNTER3H, ret)
|
||||
switchcase_csr_read_4(CSR_MHPMCOUNTER4H, ret)
|
||||
switchcase_csr_read_8(CSR_MHPMCOUNTER8H, ret)
|
||||
switchcase_csr_read_16(CSR_MHPMCOUNTER16H, ret)
|
||||
switchcase_csr_read(CSR_MHPMEVENT3H, ret)
|
||||
switchcase_csr_read_4(CSR_MHPMEVENT4H, ret)
|
||||
switchcase_csr_read_8(CSR_MHPMEVENT8H, ret)
|
||||
switchcase_csr_read_16(CSR_MHPMEVENT16H, ret)
|
||||
#endif
|
||||
|
||||
default:
|
||||
sbi_panic("%s: Unknown CSR %#x", __func__, csr_num);
|
||||
break;
|
||||
};
|
||||
|
||||
return ret;
|
||||
|
||||
#undef switchcase_csr_read_64
|
||||
#undef switchcase_csr_read_32
|
||||
#undef switchcase_csr_read_16
|
||||
#undef switchcase_csr_read_8
|
||||
#undef switchcase_csr_read_4
|
||||
#undef switchcase_csr_read_2
|
||||
#undef switchcase_csr_read
|
||||
}
|
||||
|
||||
void csr_write_num(int csr_num, unsigned long val)
|
||||
{
|
||||
#define switchcase_csr_write(__csr_num, __val) \
|
||||
case __csr_num: \
|
||||
csr_write(__csr_num, __val); \
|
||||
break;
|
||||
#define switchcase_csr_write_2(__csr_num, __val) \
|
||||
switchcase_csr_write(__csr_num + 0, __val) \
|
||||
switchcase_csr_write(__csr_num + 1, __val)
|
||||
#define switchcase_csr_write_4(__csr_num, __val) \
|
||||
switchcase_csr_write_2(__csr_num + 0, __val) \
|
||||
switchcase_csr_write_2(__csr_num + 2, __val)
|
||||
#define switchcase_csr_write_8(__csr_num, __val) \
|
||||
switchcase_csr_write_4(__csr_num + 0, __val) \
|
||||
switchcase_csr_write_4(__csr_num + 4, __val)
|
||||
#define switchcase_csr_write_16(__csr_num, __val) \
|
||||
switchcase_csr_write_8(__csr_num + 0, __val) \
|
||||
switchcase_csr_write_8(__csr_num + 8, __val)
|
||||
#define switchcase_csr_write_32(__csr_num, __val) \
|
||||
switchcase_csr_write_16(__csr_num + 0, __val) \
|
||||
switchcase_csr_write_16(__csr_num + 16, __val)
|
||||
#define switchcase_csr_write_64(__csr_num, __val) \
|
||||
switchcase_csr_write_32(__csr_num + 0, __val) \
|
||||
switchcase_csr_write_32(__csr_num + 32, __val)
|
||||
|
||||
switch (csr_num) {
|
||||
case CSR_PMPCFG0:
|
||||
csr_write(CSR_PMPCFG0, val);
|
||||
break;
|
||||
case CSR_PMPCFG1:
|
||||
csr_write(CSR_PMPCFG1, val);
|
||||
break;
|
||||
case CSR_PMPCFG2:
|
||||
csr_write(CSR_PMPCFG2, val);
|
||||
break;
|
||||
case CSR_PMPCFG3:
|
||||
csr_write(CSR_PMPCFG3, val);
|
||||
break;
|
||||
case CSR_PMPADDR0:
|
||||
csr_write(CSR_PMPADDR0, val);
|
||||
break;
|
||||
case CSR_PMPADDR1:
|
||||
csr_write(CSR_PMPADDR1, val);
|
||||
break;
|
||||
case CSR_PMPADDR2:
|
||||
csr_write(CSR_PMPADDR2, val);
|
||||
break;
|
||||
case CSR_PMPADDR3:
|
||||
csr_write(CSR_PMPADDR3, val);
|
||||
break;
|
||||
case CSR_PMPADDR4:
|
||||
csr_write(CSR_PMPADDR4, val);
|
||||
break;
|
||||
case CSR_PMPADDR5:
|
||||
csr_write(CSR_PMPADDR5, val);
|
||||
break;
|
||||
case CSR_PMPADDR6:
|
||||
csr_write(CSR_PMPADDR6, val);
|
||||
break;
|
||||
case CSR_PMPADDR7:
|
||||
csr_write(CSR_PMPADDR7, val);
|
||||
break;
|
||||
case CSR_PMPADDR8:
|
||||
csr_write(CSR_PMPADDR8, val);
|
||||
break;
|
||||
case CSR_PMPADDR9:
|
||||
csr_write(CSR_PMPADDR9, val);
|
||||
break;
|
||||
case CSR_PMPADDR10:
|
||||
csr_write(CSR_PMPADDR10, val);
|
||||
break;
|
||||
case CSR_PMPADDR11:
|
||||
csr_write(CSR_PMPADDR11, val);
|
||||
break;
|
||||
case CSR_PMPADDR12:
|
||||
csr_write(CSR_PMPADDR12, val);
|
||||
break;
|
||||
case CSR_PMPADDR13:
|
||||
csr_write(CSR_PMPADDR13, val);
|
||||
break;
|
||||
case CSR_PMPADDR14:
|
||||
csr_write(CSR_PMPADDR14, val);
|
||||
break;
|
||||
case CSR_PMPADDR15:
|
||||
csr_write(CSR_PMPADDR15, val);
|
||||
break;
|
||||
switchcase_csr_write_16(CSR_PMPCFG0, val)
|
||||
switchcase_csr_write_64(CSR_PMPADDR0, val)
|
||||
switchcase_csr_write(CSR_MCYCLE, val)
|
||||
switchcase_csr_write(CSR_MINSTRET, val)
|
||||
switchcase_csr_write(CSR_MHPMCOUNTER3, val)
|
||||
switchcase_csr_write_4(CSR_MHPMCOUNTER4, val)
|
||||
switchcase_csr_write_8(CSR_MHPMCOUNTER8, val)
|
||||
switchcase_csr_write_16(CSR_MHPMCOUNTER16, val)
|
||||
#if __riscv_xlen == 32
|
||||
switchcase_csr_write(CSR_MCYCLEH, val)
|
||||
switchcase_csr_write(CSR_MINSTRETH, val)
|
||||
switchcase_csr_write(CSR_MHPMCOUNTER3H, val)
|
||||
switchcase_csr_write_4(CSR_MHPMCOUNTER4H, val)
|
||||
switchcase_csr_write_8(CSR_MHPMCOUNTER8H, val)
|
||||
switchcase_csr_write_16(CSR_MHPMCOUNTER16H, val)
|
||||
switchcase_csr_write(CSR_MHPMEVENT3H, val)
|
||||
switchcase_csr_write_4(CSR_MHPMEVENT4H, val)
|
||||
switchcase_csr_write_8(CSR_MHPMEVENT8H, val)
|
||||
switchcase_csr_write_16(CSR_MHPMEVENT16H, val)
|
||||
#endif
|
||||
switchcase_csr_write(CSR_MCOUNTINHIBIT, val)
|
||||
switchcase_csr_write(CSR_MHPMEVENT3, val)
|
||||
switchcase_csr_write_4(CSR_MHPMEVENT4, val)
|
||||
switchcase_csr_write_8(CSR_MHPMEVENT8, val)
|
||||
switchcase_csr_write_16(CSR_MHPMEVENT16, val)
|
||||
|
||||
default:
|
||||
sbi_panic("%s: Unknown CSR %#x", __func__, csr_num);
|
||||
break;
|
||||
};
|
||||
|
||||
#undef switchcase_csr_write_64
|
||||
#undef switchcase_csr_write_32
|
||||
#undef switchcase_csr_write_16
|
||||
#undef switchcase_csr_write_8
|
||||
#undef switchcase_csr_write_4
|
||||
#undef switchcase_csr_write_2
|
||||
#undef switchcase_csr_write
|
||||
}
|
||||
|
||||
static unsigned long ctz(unsigned long x)
|
||||
{
|
||||
unsigned long ret = 0;
|
||||
|
||||
if (x == 0)
|
||||
return 8 * sizeof(x);
|
||||
|
||||
while (!(x & 1UL)) {
|
||||
ret++;
|
||||
x = x >> 1;
|
||||
@@ -259,14 +261,12 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
|
||||
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
|
||||
pmpcfg_shift = (n & 7) << 3;
|
||||
#else
|
||||
pmpcfg_csr = -1;
|
||||
pmpcfg_shift = -1;
|
||||
return SBI_ENOTSUPP;
|
||||
#endif
|
||||
pmpaddr_csr = CSR_PMPADDR0 + n;
|
||||
if (pmpcfg_csr < 0 || pmpcfg_shift < 0)
|
||||
return SBI_ENOTSUPP;
|
||||
|
||||
/* encode PMP config */
|
||||
prot &= ~PMP_A;
|
||||
prot |= (log2len == PMP_SHIFT) ? PMP_A_NA4 : PMP_A_NAPOT;
|
||||
cfgmask = ~(0xffUL << pmpcfg_shift);
|
||||
pmpcfg = (csr_read_num(pmpcfg_csr) & cfgmask);
|
||||
@@ -293,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 *size)
|
||||
unsigned long *log2len)
|
||||
{
|
||||
int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr;
|
||||
unsigned long cfgmask, pmpcfg, prot;
|
||||
unsigned long t1, addr, log2len;
|
||||
unsigned long t1, addr, len;
|
||||
|
||||
/* check parameters */
|
||||
if (n >= PMP_COUNT || !prot_out || !addr_out || !size)
|
||||
if (n >= PMP_COUNT || !prot_out || !addr_out || !log2len)
|
||||
return SBI_EINVAL;
|
||||
*prot_out = *addr_out = *size = 0;
|
||||
*prot_out = *addr_out = *log2len = 0;
|
||||
|
||||
/* calculate PMP register and offset */
|
||||
#if __riscv_xlen == 32
|
||||
@@ -312,12 +312,9 @@ int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
|
||||
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
|
||||
pmpcfg_shift = (n & 7) << 3;
|
||||
#else
|
||||
pmpcfg_csr = -1;
|
||||
pmpcfg_shift = -1;
|
||||
return SBI_ENOTSUPP;
|
||||
#endif
|
||||
pmpaddr_csr = CSR_PMPADDR0 + n;
|
||||
if (pmpcfg_csr < 0 || pmpcfg_shift < 0)
|
||||
return SBI_ENOTSUPP;
|
||||
|
||||
/* decode PMP config */
|
||||
cfgmask = (0xffUL << pmpcfg_shift);
|
||||
@@ -329,23 +326,21 @@ int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
|
||||
addr = csr_read_num(pmpaddr_csr);
|
||||
if (addr == -1UL) {
|
||||
addr = 0;
|
||||
log2len = __riscv_xlen;
|
||||
len = __riscv_xlen;
|
||||
} else {
|
||||
t1 = ctz(~addr);
|
||||
addr = (addr & ~((1UL << t1) - 1)) << PMP_SHIFT;
|
||||
log2len = (t1 + PMP_SHIFT + 1);
|
||||
len = (t1 + PMP_SHIFT + 1);
|
||||
}
|
||||
} else {
|
||||
addr = csr_read_num(pmpaddr_csr) << PMP_SHIFT;
|
||||
log2len = PMP_SHIFT;
|
||||
len = PMP_SHIFT;
|
||||
}
|
||||
|
||||
/* return details */
|
||||
*prot_out = prot;
|
||||
*addr_out = addr;
|
||||
|
||||
if (log2len < __riscv_xlen)
|
||||
*size = (1UL << log2len);
|
||||
*log2len = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -28,25 +28,23 @@ void atomic_write(atomic_t *atom, long value)
|
||||
long atomic_add_return(atomic_t *atom, long value)
|
||||
{
|
||||
long ret;
|
||||
|
||||
#if __SIZEOF_LONG__ == 4
|
||||
__asm__ __volatile__(" amoadd.w.aqrl %1, %2, %0"
|
||||
: "+A"(atom->counter), "=r"(ret)
|
||||
: "r"(value)
|
||||
: "memory");
|
||||
|
||||
#elif __SIZEOF_LONG__ == 8
|
||||
__asm__ __volatile__(" amoadd.d.aqrl %1, %2, %0"
|
||||
: "+A"(atom->counter), "=r"(ret)
|
||||
: "r"(value)
|
||||
: "memory");
|
||||
#endif
|
||||
return ret + value;
|
||||
}
|
||||
|
||||
long atomic_sub_return(atomic_t *atom, long value)
|
||||
{
|
||||
long ret;
|
||||
|
||||
__asm__ __volatile__(" amoadd.w.aqrl %1, %2, %0"
|
||||
: "+A"(atom->counter), "=r"(ret)
|
||||
: "r"(-value)
|
||||
: "memory");
|
||||
|
||||
return ret - value;
|
||||
return atomic_add_return(atom, -value);
|
||||
}
|
||||
|
||||
#define __axchg(ptr, new, size) \
|
||||
|
@@ -2,44 +2,76 @@
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
* Copyright (c) 2021 Christoph Müllner <cmuellner@linux.com>
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_barrier.h>
|
||||
#include <sbi/riscv_locks.h>
|
||||
|
||||
int spin_lock_check(spinlock_t *lock)
|
||||
static inline bool spin_lock_unlocked(spinlock_t lock)
|
||||
{
|
||||
return (lock->lock == __RISCV_SPIN_UNLOCKED) ? 0 : 1;
|
||||
return lock.owner == lock.next;
|
||||
}
|
||||
|
||||
int spin_trylock(spinlock_t *lock)
|
||||
bool spin_lock_check(spinlock_t *lock)
|
||||
{
|
||||
int tmp = 1, busy;
|
||||
RISCV_FENCE(r, rw);
|
||||
return !spin_lock_unlocked(*lock);
|
||||
}
|
||||
|
||||
bool spin_trylock(spinlock_t *lock)
|
||||
{
|
||||
unsigned long inc = 1u << TICKET_SHIFT;
|
||||
unsigned long mask = 0xffffu << TICKET_SHIFT;
|
||||
u32 l0, tmp1, tmp2;
|
||||
|
||||
__asm__ __volatile__(
|
||||
" amoswap.w %0, %2, %1\n" RISCV_ACQUIRE_BARRIER
|
||||
: "=r"(busy), "+A"(lock->lock)
|
||||
: "r"(tmp)
|
||||
/* Get the current lock counters. */
|
||||
"1: lr.w.aq %0, %3\n"
|
||||
" slli %2, %0, %6\n"
|
||||
" and %2, %2, %5\n"
|
||||
" and %1, %0, %5\n"
|
||||
/* Is the lock free right now? */
|
||||
" bne %1, %2, 2f\n"
|
||||
" add %0, %0, %4\n"
|
||||
/* Acquire the lock. */
|
||||
" sc.w.rl %0, %0, %3\n"
|
||||
" bnez %0, 1b\n"
|
||||
"2:"
|
||||
: "=&r"(l0), "=&r"(tmp1), "=&r"(tmp2), "+A"(*lock)
|
||||
: "r"(inc), "r"(mask), "I"(TICKET_SHIFT)
|
||||
: "memory");
|
||||
|
||||
return !busy;
|
||||
return l0 == 0;
|
||||
}
|
||||
|
||||
void spin_lock(spinlock_t *lock)
|
||||
{
|
||||
while (1) {
|
||||
if (spin_lock_check(lock))
|
||||
continue;
|
||||
unsigned long inc = 1u << TICKET_SHIFT;
|
||||
unsigned long mask = 0xffffu;
|
||||
u32 l0, tmp1, tmp2;
|
||||
|
||||
if (spin_trylock(lock))
|
||||
break;
|
||||
}
|
||||
__asm__ __volatile__(
|
||||
/* Atomically increment the next ticket. */
|
||||
" amoadd.w.aqrl %0, %4, %3\n"
|
||||
|
||||
/* Did we get the lock? */
|
||||
" srli %1, %0, %6\n"
|
||||
" and %1, %1, %5\n"
|
||||
"1: and %2, %0, %5\n"
|
||||
" beq %1, %2, 2f\n"
|
||||
|
||||
/* If not, then spin on the lock. */
|
||||
" lw %0, %3\n"
|
||||
RISCV_ACQUIRE_BARRIER
|
||||
" j 1b\n"
|
||||
"2:"
|
||||
: "=&r"(l0), "=&r"(tmp1), "=&r"(tmp2), "+A"(*lock)
|
||||
: "r"(inc), "r"(mask), "I"(TICKET_SHIFT)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
void spin_unlock(spinlock_t *lock)
|
||||
{
|
||||
__smp_store_release(&lock->lock, __RISCV_SPIN_UNLOCKED);
|
||||
__smp_store_release(&lock->owner, lock->owner + 1);
|
||||
}
|
||||
|
@@ -9,10 +9,11 @@
|
||||
|
||||
#include <sbi/riscv_locks.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
|
||||
static const struct sbi_platform *console_plat = NULL;
|
||||
static const struct sbi_console_device *console_dev = NULL;
|
||||
static spinlock_t console_out_lock = SPIN_LOCK_INITIALIZER;
|
||||
|
||||
bool sbi_isprintable(char c)
|
||||
@@ -26,14 +27,18 @@ bool sbi_isprintable(char c)
|
||||
|
||||
int sbi_getc(void)
|
||||
{
|
||||
return sbi_platform_console_getc(console_plat);
|
||||
if (console_dev && console_dev->console_getc)
|
||||
return console_dev->console_getc();
|
||||
return -1;
|
||||
}
|
||||
|
||||
void sbi_putc(char ch)
|
||||
{
|
||||
if (ch == '\n')
|
||||
sbi_platform_console_putc(console_plat, '\r');
|
||||
sbi_platform_console_putc(console_plat, ch);
|
||||
if (console_dev && console_dev->console_putc) {
|
||||
if (ch == '\n')
|
||||
console_dev->console_putc('\r');
|
||||
console_dev->console_putc(ch);
|
||||
}
|
||||
}
|
||||
|
||||
void sbi_puts(const char *str)
|
||||
@@ -383,16 +388,43 @@ int sbi_dprintf(const char *format, ...)
|
||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||
|
||||
va_start(args, format);
|
||||
if (scratch->options & SBI_SCRATCH_DEBUG_PRINTS)
|
||||
if (scratch->options & SBI_SCRATCH_DEBUG_PRINTS) {
|
||||
spin_lock(&console_out_lock);
|
||||
retval = print(NULL, NULL, format, args);
|
||||
spin_unlock(&console_out_lock);
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void sbi_panic(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
spin_lock(&console_out_lock);
|
||||
va_start(args, format);
|
||||
print(NULL, NULL, format, args);
|
||||
va_end(args);
|
||||
spin_unlock(&console_out_lock);
|
||||
|
||||
sbi_hart_hang();
|
||||
}
|
||||
|
||||
const struct sbi_console_device *sbi_console_get_device(void)
|
||||
{
|
||||
return console_dev;
|
||||
}
|
||||
|
||||
void sbi_console_set_device(const struct sbi_console_device *dev)
|
||||
{
|
||||
if (!dev || console_dev)
|
||||
return;
|
||||
|
||||
console_dev = dev;
|
||||
}
|
||||
|
||||
int sbi_console_init(struct sbi_scratch *scratch)
|
||||
{
|
||||
console_plat = sbi_platform_ptr(scratch);
|
||||
|
||||
return sbi_platform_console_init(console_plat);
|
||||
return sbi_platform_console_init(sbi_platform_ptr(scratch));
|
||||
}
|
||||
|
618
lib/sbi/sbi_domain.c
Normal file
618
lib/sbi/sbi_domain.c
Normal file
@@ -0,0 +1,618 @@
|
||||
/*
|
||||
* 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_console.h>
|
||||
#include <sbi/sbi_domain.h>
|
||||
#include <sbi/sbi_hartmask.h>
|
||||
#include <sbi/sbi_hsm.h>
|
||||
#include <sbi/sbi_math.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/sbi_string.h>
|
||||
|
||||
struct sbi_domain *hartid_to_domain_table[SBI_HARTMASK_MAX_BITS] = { 0 };
|
||||
struct sbi_domain *domidx_to_domain_table[SBI_DOMAIN_MAX_INDEX] = { 0 };
|
||||
static u32 domain_count = 0;
|
||||
static bool domain_finalized = false;
|
||||
|
||||
static struct sbi_hartmask root_hmask = { 0 };
|
||||
|
||||
#define ROOT_REGION_MAX 16
|
||||
static u32 root_memregs_count = 0;
|
||||
static struct sbi_domain_memregion root_fw_region;
|
||||
static struct sbi_domain_memregion root_memregs[ROOT_REGION_MAX + 1] = { 0 };
|
||||
|
||||
struct sbi_domain root = {
|
||||
.name = "root",
|
||||
.possible_harts = &root_hmask,
|
||||
.regions = root_memregs,
|
||||
.system_reset_allowed = TRUE,
|
||||
};
|
||||
|
||||
bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid)
|
||||
{
|
||||
if (dom)
|
||||
return sbi_hartmask_test_hart(hartid, &dom->assigned_harts);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ulong sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom,
|
||||
ulong hbase)
|
||||
{
|
||||
ulong ret, bword, boff;
|
||||
|
||||
if (!dom)
|
||||
return 0;
|
||||
|
||||
bword = BIT_WORD(hbase);
|
||||
boff = BIT_WORD_OFFSET(hbase);
|
||||
|
||||
ret = sbi_hartmask_bits(&dom->assigned_harts)[bword++] >> boff;
|
||||
if (boff && bword < BIT_WORD(SBI_HARTMASK_MAX_BITS)) {
|
||||
ret |= (sbi_hartmask_bits(&dom->assigned_harts)[bword] &
|
||||
(BIT(boff) - 1UL)) << (BITS_PER_LONG - boff);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void domain_memregion_initfw(struct sbi_domain_memregion *reg)
|
||||
{
|
||||
if (!reg)
|
||||
return;
|
||||
|
||||
sbi_memcpy(reg, &root_fw_region, sizeof(*reg));
|
||||
}
|
||||
|
||||
void sbi_domain_memregion_init(unsigned long addr,
|
||||
unsigned long size,
|
||||
unsigned long flags,
|
||||
struct sbi_domain_memregion *reg)
|
||||
{
|
||||
unsigned long base = 0, order;
|
||||
|
||||
for (order = log2roundup(size) ; order <= __riscv_xlen; order++) {
|
||||
if (order < __riscv_xlen) {
|
||||
base = addr & ~((1UL << order) - 1UL);
|
||||
if ((base <= addr) &&
|
||||
(addr < (base + (1UL << order))) &&
|
||||
(base <= (addr + size - 1UL)) &&
|
||||
((addr + size - 1UL) < (base + (1UL << order))))
|
||||
break;
|
||||
} else {
|
||||
base = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (reg) {
|
||||
reg->base = base;
|
||||
reg->order = order;
|
||||
reg->flags = flags;
|
||||
}
|
||||
}
|
||||
|
||||
bool sbi_domain_check_addr(const struct sbi_domain *dom,
|
||||
unsigned long addr, unsigned long mode,
|
||||
unsigned long access_flags)
|
||||
{
|
||||
bool mmio = FALSE;
|
||||
struct sbi_domain_memregion *reg;
|
||||
unsigned long rstart, rend, rflags, rwx = 0;
|
||||
|
||||
if (!dom)
|
||||
return FALSE;
|
||||
|
||||
if (access_flags & SBI_DOMAIN_READ)
|
||||
rwx |= SBI_DOMAIN_MEMREGION_READABLE;
|
||||
if (access_flags & SBI_DOMAIN_WRITE)
|
||||
rwx |= SBI_DOMAIN_MEMREGION_WRITEABLE;
|
||||
if (access_flags & SBI_DOMAIN_EXECUTE)
|
||||
rwx |= SBI_DOMAIN_MEMREGION_EXECUTABLE;
|
||||
if (access_flags & SBI_DOMAIN_MMIO)
|
||||
mmio = TRUE;
|
||||
|
||||
sbi_domain_for_each_memregion(dom, reg) {
|
||||
rflags = reg->flags;
|
||||
if (mode == PRV_M && !(rflags & SBI_DOMAIN_MEMREGION_MMODE))
|
||||
continue;
|
||||
|
||||
rstart = reg->base;
|
||||
rend = (reg->order < __riscv_xlen) ?
|
||||
rstart + ((1UL << reg->order) - 1) : -1UL;
|
||||
if (rstart <= addr && addr <= rend) {
|
||||
if ((mmio && !(rflags & SBI_DOMAIN_MEMREGION_MMIO)) ||
|
||||
(!mmio && (rflags & SBI_DOMAIN_MEMREGION_MMIO)))
|
||||
return FALSE;
|
||||
return ((rflags & rwx) == rwx) ? TRUE : FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return (mode == PRV_M) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/* Check if region complies with constraints */
|
||||
static bool is_region_valid(const struct sbi_domain_memregion *reg)
|
||||
{
|
||||
if (reg->order < 3 || __riscv_xlen < reg->order)
|
||||
return FALSE;
|
||||
|
||||
if (reg->base & (BIT(reg->order) - 1))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/** Check if regionA is sub-region of regionB */
|
||||
static bool is_region_subset(const struct sbi_domain_memregion *regA,
|
||||
const struct sbi_domain_memregion *regB)
|
||||
{
|
||||
ulong regA_start = regA->base;
|
||||
ulong regA_end = regA->base + (BIT(regA->order) - 1);
|
||||
ulong regB_start = regB->base;
|
||||
ulong regB_end = regB->base + (BIT(regA->order) - 1);
|
||||
|
||||
if ((regB_start <= regA_start) &&
|
||||
(regA_start < regB_end) &&
|
||||
(regB_start < regA_end) &&
|
||||
(regA_end <= regB_end))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/** Check if regionA conflicts regionB */
|
||||
static bool is_region_conflict(const struct sbi_domain_memregion *regA,
|
||||
const struct sbi_domain_memregion *regB)
|
||||
{
|
||||
if ((is_region_subset(regA, regB) || is_region_subset(regB, regA)) &&
|
||||
regA->flags == regB->flags)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/** Check if regionA should be placed before regionB */
|
||||
static bool is_region_before(const struct sbi_domain_memregion *regA,
|
||||
const struct sbi_domain_memregion *regB)
|
||||
{
|
||||
if (regA->order < regB->order)
|
||||
return TRUE;
|
||||
|
||||
if ((regA->order == regB->order) &&
|
||||
(regA->base < regB->base))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int sanitize_domain(const struct sbi_platform *plat,
|
||||
struct sbi_domain *dom)
|
||||
{
|
||||
u32 i, j, count;
|
||||
bool have_fw_reg;
|
||||
struct sbi_domain_memregion treg, *reg, *reg1;
|
||||
|
||||
/* Check possible HARTs */
|
||||
if (!dom->possible_harts) {
|
||||
sbi_printf("%s: %s possible HART mask is NULL\n",
|
||||
__func__, dom->name);
|
||||
return SBI_EINVAL;
|
||||
}
|
||||
sbi_hartmask_for_each_hart(i, dom->possible_harts) {
|
||||
if (sbi_platform_hart_invalid(plat, i)) {
|
||||
sbi_printf("%s: %s possible HART mask has invalid "
|
||||
"hart %d\n", __func__, dom->name, i);
|
||||
return SBI_EINVAL;
|
||||
}
|
||||
};
|
||||
|
||||
/* Check memory regions */
|
||||
if (!dom->regions) {
|
||||
sbi_printf("%s: %s regions is NULL\n",
|
||||
__func__, dom->name);
|
||||
return SBI_EINVAL;
|
||||
}
|
||||
sbi_domain_for_each_memregion(dom, reg) {
|
||||
if (!is_region_valid(reg)) {
|
||||
sbi_printf("%s: %s has invalid region base=0x%lx "
|
||||
"order=%lu flags=0x%lx\n", __func__,
|
||||
dom->name, reg->base, reg->order,
|
||||
reg->flags);
|
||||
return SBI_EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Count memory regions and check presence of firmware region */
|
||||
count = 0;
|
||||
have_fw_reg = FALSE;
|
||||
sbi_domain_for_each_memregion(dom, reg) {
|
||||
if (reg->order == root_fw_region.order &&
|
||||
reg->base == root_fw_region.base &&
|
||||
reg->flags == root_fw_region.flags)
|
||||
have_fw_reg = TRUE;
|
||||
count++;
|
||||
}
|
||||
if (!have_fw_reg) {
|
||||
sbi_printf("%s: %s does not have firmware region\n",
|
||||
__func__, dom->name);
|
||||
return SBI_EINVAL;
|
||||
}
|
||||
|
||||
/* Sort the memory regions */
|
||||
for (i = 0; i < (count - 1); i++) {
|
||||
reg = &dom->regions[i];
|
||||
for (j = i + 1; j < count; j++) {
|
||||
reg1 = &dom->regions[j];
|
||||
|
||||
if (is_region_conflict(reg1, reg)) {
|
||||
sbi_printf("%s: %s conflict between regions "
|
||||
"(base=0x%lx order=%lu flags=0x%lx) and "
|
||||
"(base=0x%lx order=%lu flags=0x%lx)\n",
|
||||
__func__, dom->name,
|
||||
reg->base, reg->order, reg->flags,
|
||||
reg1->base, reg1->order, reg1->flags);
|
||||
return SBI_EINVAL;
|
||||
}
|
||||
|
||||
if (!is_region_before(reg1, reg))
|
||||
continue;
|
||||
|
||||
sbi_memcpy(&treg, reg1, sizeof(treg));
|
||||
sbi_memcpy(reg1, reg, sizeof(treg));
|
||||
sbi_memcpy(reg, &treg, sizeof(treg));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't need to check boot HART id of domain because if boot
|
||||
* HART id is not possible/assigned to this domain then it won't
|
||||
* be started at boot-time by sbi_domain_finalize().
|
||||
*/
|
||||
|
||||
/*
|
||||
* Check next mode
|
||||
*
|
||||
* We only allow next mode to be S-mode or U-mode.so that we can
|
||||
* protect M-mode context and enforce checks on memory accesses.
|
||||
*/
|
||||
if (dom->next_mode != PRV_S &&
|
||||
dom->next_mode != PRV_U) {
|
||||
sbi_printf("%s: %s invalid next booting stage mode 0x%lx\n",
|
||||
__func__, dom->name, dom->next_mode);
|
||||
return SBI_EINVAL;
|
||||
}
|
||||
|
||||
/* Check next address and next mode*/
|
||||
if (!sbi_domain_check_addr(dom, dom->next_addr, dom->next_mode,
|
||||
SBI_DOMAIN_EXECUTE)) {
|
||||
sbi_printf("%s: %s next booting stage address 0x%lx can't "
|
||||
"execute\n", __func__, dom->name, dom->next_addr);
|
||||
return SBI_EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
|
||||
{
|
||||
u32 i, k;
|
||||
unsigned long rstart, rend;
|
||||
struct sbi_domain_memregion *reg;
|
||||
|
||||
sbi_printf("Domain%d Name %s: %s\n",
|
||||
dom->index, suffix, dom->name);
|
||||
|
||||
sbi_printf("Domain%d Boot HART %s: %d\n",
|
||||
dom->index, suffix, dom->boot_hartid);
|
||||
|
||||
k = 0;
|
||||
sbi_printf("Domain%d HARTs %s: ", dom->index, suffix);
|
||||
sbi_hartmask_for_each_hart(i, dom->possible_harts)
|
||||
sbi_printf("%s%d%s", (k++) ? "," : "",
|
||||
i, sbi_domain_is_assigned_hart(dom, i) ? "*" : "");
|
||||
sbi_printf("\n");
|
||||
|
||||
i = 0;
|
||||
sbi_domain_for_each_memregion(dom, reg) {
|
||||
rstart = reg->base;
|
||||
rend = (reg->order < __riscv_xlen) ?
|
||||
rstart + ((1UL << reg->order) - 1) : -1UL;
|
||||
|
||||
sbi_printf("Domain%d Region%02d %s: 0x%" PRILX "-0x%" PRILX " ",
|
||||
dom->index, i, suffix, rstart, rend);
|
||||
|
||||
k = 0;
|
||||
if (reg->flags & SBI_DOMAIN_MEMREGION_MMODE)
|
||||
sbi_printf("%cM", (k++) ? ',' : '(');
|
||||
if (reg->flags & SBI_DOMAIN_MEMREGION_MMIO)
|
||||
sbi_printf("%cI", (k++) ? ',' : '(');
|
||||
if (reg->flags & SBI_DOMAIN_MEMREGION_READABLE)
|
||||
sbi_printf("%cR", (k++) ? ',' : '(');
|
||||
if (reg->flags & SBI_DOMAIN_MEMREGION_WRITEABLE)
|
||||
sbi_printf("%cW", (k++) ? ',' : '(');
|
||||
if (reg->flags & SBI_DOMAIN_MEMREGION_EXECUTABLE)
|
||||
sbi_printf("%cX", (k++) ? ',' : '(');
|
||||
sbi_printf("%s\n", (k++) ? ")" : "()");
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
sbi_printf("Domain%d Next Address%s: 0x%" PRILX "\n",
|
||||
dom->index, suffix, dom->next_addr);
|
||||
|
||||
sbi_printf("Domain%d Next Arg1 %s: 0x%" PRILX "\n",
|
||||
dom->index, suffix, dom->next_arg1);
|
||||
|
||||
sbi_printf("Domain%d Next Mode %s: ", dom->index, suffix);
|
||||
switch (dom->next_mode) {
|
||||
case PRV_M:
|
||||
sbi_printf("M-mode\n");
|
||||
break;
|
||||
case PRV_S:
|
||||
sbi_printf("S-mode\n");
|
||||
break;
|
||||
case PRV_U:
|
||||
sbi_printf("U-mode\n");
|
||||
break;
|
||||
default:
|
||||
sbi_printf("Unknown\n");
|
||||
break;
|
||||
};
|
||||
|
||||
sbi_printf("Domain%d SysReset %s: %s\n",
|
||||
dom->index, suffix, (dom->system_reset_allowed) ? "yes" : "no");
|
||||
}
|
||||
|
||||
void sbi_domain_dump_all(const char *suffix)
|
||||
{
|
||||
u32 i;
|
||||
const struct sbi_domain *dom;
|
||||
|
||||
sbi_domain_for_each(i, dom) {
|
||||
sbi_domain_dump(dom, suffix);
|
||||
sbi_printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
int sbi_domain_register(struct sbi_domain *dom,
|
||||
const struct sbi_hartmask *assign_mask)
|
||||
{
|
||||
u32 i;
|
||||
int rc;
|
||||
struct sbi_domain *tdom;
|
||||
u32 cold_hartid = current_hartid();
|
||||
const struct sbi_platform *plat = sbi_platform_thishart_ptr();
|
||||
|
||||
/* Sanity checks */
|
||||
if (!dom || !assign_mask || domain_finalized)
|
||||
return SBI_EINVAL;
|
||||
|
||||
/* Check if domain already discovered */
|
||||
sbi_domain_for_each(i, tdom) {
|
||||
if (tdom == dom)
|
||||
return SBI_EALREADY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure that we have room for Domain Index to
|
||||
* HART ID mapping
|
||||
*/
|
||||
if (SBI_DOMAIN_MAX_INDEX <= domain_count) {
|
||||
sbi_printf("%s: No room for %s\n",
|
||||
__func__, dom->name);
|
||||
return SBI_ENOSPC;
|
||||
}
|
||||
|
||||
/* Sanitize discovered domain */
|
||||
rc = sanitize_domain(plat, dom);
|
||||
if (rc) {
|
||||
sbi_printf("%s: sanity checks failed for"
|
||||
" %s (error %d)\n", __func__,
|
||||
dom->name, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Assign index to domain */
|
||||
dom->index = domain_count++;
|
||||
domidx_to_domain_table[dom->index] = dom;
|
||||
|
||||
/* Clear assigned HARTs of domain */
|
||||
sbi_hartmask_clear_all(&dom->assigned_harts);
|
||||
|
||||
/* Assign domain to HART if HART is a possible HART */
|
||||
sbi_hartmask_for_each_hart(i, assign_mask) {
|
||||
if (!sbi_hartmask_test_hart(i, dom->possible_harts))
|
||||
continue;
|
||||
|
||||
tdom = hartid_to_domain_table[i];
|
||||
if (tdom)
|
||||
sbi_hartmask_clear_hart(i,
|
||||
&tdom->assigned_harts);
|
||||
hartid_to_domain_table[i] = dom;
|
||||
sbi_hartmask_set_hart(i, &dom->assigned_harts);
|
||||
|
||||
/*
|
||||
* If cold boot HART is assigned to this domain then
|
||||
* override boot HART of this domain.
|
||||
*/
|
||||
if (i == cold_hartid &&
|
||||
dom->boot_hartid != cold_hartid) {
|
||||
sbi_printf("Domain%d Boot HARTID forced to"
|
||||
" %d\n", dom->index, cold_hartid);
|
||||
dom->boot_hartid = cold_hartid;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg)
|
||||
{
|
||||
int rc;
|
||||
bool reg_merged;
|
||||
struct sbi_domain_memregion *nreg, *nreg1, *nreg2;
|
||||
const struct sbi_platform *plat = sbi_platform_thishart_ptr();
|
||||
|
||||
/* Sanity checks */
|
||||
if (!reg || domain_finalized ||
|
||||
(root.regions != root_memregs) ||
|
||||
(ROOT_REGION_MAX <= root_memregs_count))
|
||||
return SBI_EINVAL;
|
||||
|
||||
/* Check for conflicts */
|
||||
sbi_domain_for_each_memregion(&root, nreg) {
|
||||
if (is_region_conflict(reg, nreg))
|
||||
return SBI_EINVAL;
|
||||
}
|
||||
|
||||
/* Append the memregion to root memregions */
|
||||
nreg = &root_memregs[root_memregs_count];
|
||||
sbi_memcpy(nreg, reg, sizeof(*reg));
|
||||
root_memregs_count++;
|
||||
root_memregs[root_memregs_count].order = 0;
|
||||
|
||||
/* Sort and optimize root regions */
|
||||
do {
|
||||
/* Sanitize the root domain so that memregions are sorted */
|
||||
rc = sanitize_domain(plat, &root);
|
||||
if (rc) {
|
||||
sbi_printf("%s: sanity checks failed for"
|
||||
" %s (error %d)\n", __func__,
|
||||
root.name, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Merge consecutive memregions with same order and flags */
|
||||
reg_merged = false;
|
||||
sbi_domain_for_each_memregion(&root, nreg) {
|
||||
nreg1 = nreg + 1;
|
||||
if (!nreg1->order)
|
||||
continue;
|
||||
|
||||
if (!(nreg->base & (BIT(nreg->order + 1) - 1)) &&
|
||||
(nreg->base + BIT(nreg->order)) == nreg1->base &&
|
||||
nreg->order == nreg1->order &&
|
||||
nreg->flags == nreg1->flags) {
|
||||
nreg->order++;
|
||||
while (nreg1->order) {
|
||||
nreg2 = nreg1 + 1;
|
||||
sbi_memcpy(nreg1, nreg2, sizeof(*nreg1));
|
||||
nreg1++;
|
||||
}
|
||||
reg_merged = true;
|
||||
root_memregs_count--;
|
||||
}
|
||||
}
|
||||
} while (reg_merged);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
|
||||
{
|
||||
int rc;
|
||||
u32 i, dhart;
|
||||
struct sbi_domain *dom;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
/* Initialize and populate domains for the platform */
|
||||
rc = sbi_platform_domains_init(plat);
|
||||
if (rc) {
|
||||
sbi_printf("%s: platform domains_init() failed (error %d)\n",
|
||||
__func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Startup boot HART of domains */
|
||||
sbi_domain_for_each(i, dom) {
|
||||
/* Domain boot HART */
|
||||
dhart = dom->boot_hartid;
|
||||
|
||||
/* Ignore of boot HART is off limits */
|
||||
if (SBI_HARTMASK_MAX_BITS <= dhart)
|
||||
continue;
|
||||
|
||||
/* Ignore if boot HART not possible for this domain */
|
||||
if (!sbi_hartmask_test_hart(dhart, dom->possible_harts))
|
||||
continue;
|
||||
|
||||
/* Ignore if boot HART assigned different domain */
|
||||
if (sbi_hartid_to_domain(dhart) != dom ||
|
||||
!sbi_hartmask_test_hart(dhart, &dom->assigned_harts))
|
||||
continue;
|
||||
|
||||
/* Startup boot HART of domain */
|
||||
if (dhart == cold_hartid) {
|
||||
scratch->next_addr = dom->next_addr;
|
||||
scratch->next_mode = dom->next_mode;
|
||||
scratch->next_arg1 = dom->next_arg1;
|
||||
} else {
|
||||
rc = sbi_hsm_hart_start(scratch, NULL, dhart,
|
||||
dom->next_addr,
|
||||
dom->next_mode,
|
||||
dom->next_arg1);
|
||||
if (rc) {
|
||||
sbi_printf("%s: failed to start boot HART %d"
|
||||
" for %s (error %d)\n", __func__,
|
||||
dhart, dom->name, rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the finalized flag so that the root domain
|
||||
* regions can't be changed.
|
||||
*/
|
||||
domain_finalized = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
|
||||
{
|
||||
u32 i;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
/* Root domain firmware memory region */
|
||||
sbi_domain_memregion_init(scratch->fw_start, scratch->fw_size, 0,
|
||||
&root_fw_region);
|
||||
domain_memregion_initfw(&root_memregs[root_memregs_count++]);
|
||||
|
||||
/* Root domain allow everything memory region */
|
||||
sbi_domain_memregion_init(0, ~0UL,
|
||||
(SBI_DOMAIN_MEMREGION_READABLE |
|
||||
SBI_DOMAIN_MEMREGION_WRITEABLE |
|
||||
SBI_DOMAIN_MEMREGION_EXECUTABLE),
|
||||
&root_memregs[root_memregs_count++]);
|
||||
|
||||
/* Root domain memory region end */
|
||||
root_memregs[root_memregs_count].order = 0;
|
||||
|
||||
/* Root domain boot HART id is same as coldboot HART id */
|
||||
root.boot_hartid = cold_hartid;
|
||||
|
||||
/* Root domain next booting stage details */
|
||||
root.next_arg1 = scratch->next_arg1;
|
||||
root.next_addr = scratch->next_addr;
|
||||
root.next_mode = scratch->next_mode;
|
||||
|
||||
/* Root domain possible and assigned HARTs */
|
||||
for (i = 0; i < SBI_HARTMASK_MAX_BITS; i++) {
|
||||
if (sbi_platform_hart_invalid(plat, i))
|
||||
continue;
|
||||
sbi_hartmask_set_hart(i, &root_hmask);
|
||||
}
|
||||
|
||||
return sbi_domain_register(&root, &root_hmask);
|
||||
}
|
@@ -101,19 +101,11 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs)
|
||||
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);
|
||||
regs, &out_val, &trap);
|
||||
if (extension_id >= SBI_EXT_0_1_SET_TIMER &&
|
||||
extension_id <= SBI_EXT_0_1_SHUTDOWN)
|
||||
is_0_1_spec = 1;
|
||||
@@ -167,6 +159,12 @@ int sbi_ecall_init(void)
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = sbi_ecall_register_extension(&ecall_hsm);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = sbi_ecall_register_extension(&ecall_srst);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = sbi_ecall_register_extension(&ecall_pmu);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = sbi_ecall_register_extension(&ecall_legacy);
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
#include <sbi/sbi_version.h>
|
||||
#include <sbi/riscv_asm.h>
|
||||
|
||||
@@ -32,7 +33,8 @@ static int sbi_ecall_base_probe(unsigned long extid, unsigned long *out_val)
|
||||
}
|
||||
|
||||
static int sbi_ecall_base_handler(unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
const struct sbi_trap_regs *regs,
|
||||
unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -61,7 +63,7 @@ static int sbi_ecall_base_handler(unsigned long extid, unsigned long funcid,
|
||||
*out_val = csr_read(CSR_MIMPID);
|
||||
break;
|
||||
case SBI_EXT_BASE_PROBE_EXT:
|
||||
ret = sbi_ecall_base_probe(args[0], out_val);
|
||||
ret = sbi_ecall_base_probe(regs->a0, out_val);
|
||||
break;
|
||||
default:
|
||||
ret = SBI_ENOTSUPP;
|
||||
|
@@ -7,31 +7,41 @@
|
||||
* Atish Patra <atish.patra@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/sbi_domain.h>
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_trap.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,
|
||||
const struct sbi_trap_regs *regs,
|
||||
unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
int ret = 0, hstate;
|
||||
int ret = 0;
|
||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||
ulong smode = (csr_read(CSR_MSTATUS) & MSTATUS_MPP) >>
|
||||
MSTATUS_MPP_SHIFT;
|
||||
|
||||
switch (funcid) {
|
||||
case SBI_EXT_HSM_HART_START:
|
||||
ret = sbi_hsm_hart_start(scratch, args[0], args[1], args[2]);
|
||||
ret = sbi_hsm_hart_start(scratch, sbi_domain_thishart_ptr(),
|
||||
regs->a0, regs->a1, smode, regs->a2);
|
||||
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);
|
||||
ret = sbi_hsm_hart_get_state(sbi_domain_thishart_ptr(),
|
||||
regs->a0);
|
||||
break;
|
||||
case SBI_EXT_HSM_HART_SUSPEND:
|
||||
ret = sbi_hsm_hart_suspend(scratch, regs->a0, regs->a1,
|
||||
smode, regs->a2);
|
||||
break;
|
||||
default:
|
||||
ret = SBI_ENOTSUPP;
|
||||
|
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_domain.h>
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
@@ -33,7 +34,8 @@ static int sbi_load_hart_mask_unpriv(ulong *pmask, ulong *hmask,
|
||||
if (uptrap->cause)
|
||||
return SBI_ETRAP;
|
||||
} else {
|
||||
sbi_hsm_hart_started_mask(0, &mask);
|
||||
sbi_hsm_hart_interruptible_mask(sbi_domain_thishart_ptr(),
|
||||
0, &mask);
|
||||
}
|
||||
*hmask = mask;
|
||||
|
||||
@@ -41,7 +43,8 @@ static int sbi_load_hart_mask_unpriv(ulong *pmask, ulong *hmask,
|
||||
}
|
||||
|
||||
static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
const struct sbi_trap_regs *regs,
|
||||
unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -52,13 +55,13 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
|
||||
switch (extid) {
|
||||
case SBI_EXT_0_1_SET_TIMER:
|
||||
#if __riscv_xlen == 32
|
||||
sbi_timer_event_start((((u64)args[1] << 32) | (u64)args[0]));
|
||||
sbi_timer_event_start((((u64)regs->a1 << 32) | (u64)regs->a0));
|
||||
#else
|
||||
sbi_timer_event_start((u64)args[0]);
|
||||
sbi_timer_event_start((u64)regs->a0);
|
||||
#endif
|
||||
break;
|
||||
case SBI_EXT_0_1_CONSOLE_PUTCHAR:
|
||||
sbi_putc(args[0]);
|
||||
sbi_putc(regs->a0);
|
||||
break;
|
||||
case SBI_EXT_0_1_CONSOLE_GETCHAR:
|
||||
ret = sbi_getc();
|
||||
@@ -67,41 +70,45 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
|
||||
sbi_ipi_clear_smode();
|
||||
break;
|
||||
case SBI_EXT_0_1_SEND_IPI:
|
||||
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
|
||||
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
|
||||
&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],
|
||||
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
|
||||
&hmask, out_trap);
|
||||
if (ret != SBI_ETRAP) {
|
||||
SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, 0,
|
||||
SBI_ITLB_FLUSH, source_hart);
|
||||
sbi_tlb_local_fence_i,
|
||||
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],
|
||||
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
|
||||
&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);
|
||||
SBI_TLB_INFO_INIT(&tlb_info, regs->a1, regs->a2, 0, 0,
|
||||
sbi_tlb_local_sfence_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],
|
||||
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
|
||||
&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,
|
||||
SBI_TLB_INFO_INIT(&tlb_info, regs->a1,
|
||||
regs->a2, regs->a3, 0,
|
||||
sbi_tlb_local_sfence_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);
|
||||
sbi_system_reset(SBI_SRST_RESET_TYPE_SHUTDOWN,
|
||||
SBI_SRST_RESET_REASON_NONE);
|
||||
break;
|
||||
default:
|
||||
ret = SBI_ENOTSUPP;
|
||||
|
87
lib/sbi/sbi_ecall_pmu.c
Normal file
87
lib/sbi/sbi_ecall_pmu.c
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2021 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_hart.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
#include <sbi/sbi_version.h>
|
||||
#include <sbi/sbi_pmu.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/riscv_asm.h>
|
||||
|
||||
static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid,
|
||||
const struct sbi_trap_regs *regs,
|
||||
unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
int ret = 0;
|
||||
uint64_t temp;
|
||||
|
||||
switch (funcid) {
|
||||
case SBI_EXT_PMU_NUM_COUNTERS:
|
||||
ret = sbi_pmu_num_ctr();
|
||||
if (ret >= 0) {
|
||||
*out_val = ret;
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
case SBI_EXT_PMU_COUNTER_GET_INFO:
|
||||
ret = sbi_pmu_ctr_get_info(regs->a0, out_val);
|
||||
break;
|
||||
case SBI_EXT_PMU_COUNTER_CFG_MATCH:
|
||||
#if __riscv_xlen == 32
|
||||
temp = ((uint64_t)regs->a5 << 32) | regs->a4;
|
||||
#else
|
||||
temp = regs->a4;
|
||||
#endif
|
||||
ret = sbi_pmu_ctr_cfg_match(regs->a0, regs->a1, regs->a2,
|
||||
regs->a3, temp);
|
||||
if (ret >= 0) {
|
||||
*out_val = ret;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
case SBI_EXT_PMU_COUNTER_FW_READ:
|
||||
ret = sbi_pmu_ctr_read(regs->a0, out_val);
|
||||
break;
|
||||
case SBI_EXT_PMU_COUNTER_START:
|
||||
|
||||
#if __riscv_xlen == 32
|
||||
temp = ((uint64_t)regs->a4 << 32) | regs->a3;
|
||||
#else
|
||||
temp = regs->a3;
|
||||
#endif
|
||||
ret = sbi_pmu_ctr_start(regs->a0, regs->a1, regs->a2, temp);
|
||||
break;
|
||||
case SBI_EXT_PMU_COUNTER_STOP:
|
||||
ret = sbi_pmu_ctr_stop(regs->a0, regs->a1, regs->a2);
|
||||
break;
|
||||
default:
|
||||
ret = SBI_ENOTSUPP;
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sbi_ecall_pmu_probe(unsigned long extid, unsigned long *out_val)
|
||||
{
|
||||
/* PMU extension is always enabled */
|
||||
*out_val = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sbi_ecall_extension ecall_pmu = {
|
||||
.extid_start = SBI_EXT_PMU,
|
||||
.extid_end = SBI_EXT_PMU,
|
||||
.handle = sbi_ecall_pmu_handler,
|
||||
.probe = sbi_ecall_pmu_probe,
|
||||
};
|
@@ -14,20 +14,23 @@
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_hart.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>
|
||||
|
||||
static int sbi_ecall_time_handler(unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
const struct sbi_trap_regs *regs,
|
||||
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]));
|
||||
sbi_timer_event_start((((u64)regs->a1 << 32) | (u64)regs->a0));
|
||||
#else
|
||||
sbi_timer_event_start((u64)args[0]);
|
||||
sbi_timer_event_start((u64)regs->a0);
|
||||
#endif
|
||||
} else
|
||||
ret = SBI_ENOTSUPP;
|
||||
@@ -42,7 +45,8 @@ struct sbi_ecall_extension ecall_time = {
|
||||
};
|
||||
|
||||
static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
const struct sbi_trap_regs *regs,
|
||||
unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -50,50 +54,52 @@ static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
|
||||
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 (funcid >= SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID &&
|
||||
funcid <= SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA)
|
||||
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);
|
||||
sbi_tlb_local_fence_i, source_hart);
|
||||
ret = sbi_tlb_request(regs->a0, regs->a1, &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);
|
||||
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, 0,
|
||||
sbi_tlb_local_hfence_gvma, source_hart);
|
||||
ret = sbi_tlb_request(regs->a0, regs->a1, &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);
|
||||
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, regs->a4,
|
||||
sbi_tlb_local_hfence_gvma_vmid,
|
||||
source_hart);
|
||||
ret = sbi_tlb_request(regs->a0, regs->a1, &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);
|
||||
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, vmid,
|
||||
sbi_tlb_local_hfence_vvma, source_hart);
|
||||
ret = sbi_tlb_request(regs->a0, regs->a1, &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);
|
||||
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, regs->a4,
|
||||
vmid, sbi_tlb_local_hfence_vvma_asid,
|
||||
source_hart);
|
||||
ret = sbi_tlb_request(regs->a0, regs->a1, &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);
|
||||
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, 0,
|
||||
sbi_tlb_local_sfence_vma, source_hart);
|
||||
ret = sbi_tlb_request(regs->a0, regs->a1, &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);
|
||||
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, regs->a4, 0,
|
||||
sbi_tlb_local_sfence_vma_asid, source_hart);
|
||||
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
|
||||
break;
|
||||
default:
|
||||
ret = SBI_ENOTSUPP;
|
||||
@@ -109,13 +115,14 @@ struct sbi_ecall_extension ecall_rfence = {
|
||||
};
|
||||
|
||||
static int sbi_ecall_ipi_handler(unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
const struct sbi_trap_regs *regs,
|
||||
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]);
|
||||
ret = sbi_ipi_send_smode(regs->a0, regs->a1);
|
||||
else
|
||||
ret = SBI_ENOTSUPP;
|
||||
|
||||
@@ -127,3 +134,63 @@ struct sbi_ecall_extension ecall_ipi = {
|
||||
.extid_end = SBI_EXT_IPI,
|
||||
.handle = sbi_ecall_ipi_handler,
|
||||
};
|
||||
|
||||
static int sbi_ecall_srst_handler(unsigned long extid, unsigned long funcid,
|
||||
const struct sbi_trap_regs *regs,
|
||||
unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
if (funcid == SBI_EXT_SRST_RESET) {
|
||||
if ((((u32)-1U) <= ((u64)regs->a0)) ||
|
||||
(((u32)-1U) <= ((u64)regs->a1)))
|
||||
return SBI_EINVAL;
|
||||
|
||||
switch (regs->a0) {
|
||||
case SBI_SRST_RESET_TYPE_SHUTDOWN:
|
||||
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
|
||||
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
|
||||
break;
|
||||
default:
|
||||
return SBI_EINVAL;
|
||||
}
|
||||
|
||||
switch (regs->a1) {
|
||||
case SBI_SRST_RESET_REASON_NONE:
|
||||
case SBI_SRST_RESET_REASON_SYSFAIL:
|
||||
break;
|
||||
default:
|
||||
return SBI_EINVAL;
|
||||
}
|
||||
|
||||
if (sbi_system_reset_supported(regs->a0, regs->a1))
|
||||
sbi_system_reset(regs->a0, regs->a1);
|
||||
}
|
||||
|
||||
return SBI_ENOTSUPP;
|
||||
}
|
||||
|
||||
static int sbi_ecall_srst_probe(unsigned long extid, unsigned long *out_val)
|
||||
{
|
||||
u32 type, count = 0;
|
||||
|
||||
/*
|
||||
* At least one standard reset types should be supported by
|
||||
* the platform for SBI SRST extension to be usable.
|
||||
*/
|
||||
|
||||
for (type = 0; type <= SBI_SRST_RESET_TYPE_LAST; type++) {
|
||||
if (sbi_system_reset_supported(type,
|
||||
SBI_SRST_RESET_REASON_NONE))
|
||||
count++;
|
||||
}
|
||||
|
||||
*out_val = (count) ? 1 : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sbi_ecall_extension ecall_srst = {
|
||||
.extid_start = SBI_EXT_SRST,
|
||||
.extid_end = SBI_EXT_SRST,
|
||||
.handle = sbi_ecall_srst_handler,
|
||||
.probe = sbi_ecall_srst_probe,
|
||||
};
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
|
||||
static int sbi_ecall_vendor_probe(unsigned long extid,
|
||||
unsigned long *out_val)
|
||||
@@ -22,11 +23,12 @@ static int sbi_ecall_vendor_probe(unsigned long extid,
|
||||
}
|
||||
|
||||
static int sbi_ecall_vendor_handler(unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
const struct sbi_trap_regs *regs,
|
||||
unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
return sbi_platform_vendor_ext_provider(sbi_platform_thishart_ptr(),
|
||||
extid, funcid, args,
|
||||
extid, funcid, regs,
|
||||
out_val, out_trap);
|
||||
}
|
||||
|
||||
|
@@ -13,14 +13,40 @@
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_emulate_csr.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/sbi_timer.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
|
||||
static bool hpm_allowed(int hpm_num, ulong prev_mode, bool virt)
|
||||
{
|
||||
ulong cen = -1UL;
|
||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||
|
||||
if (prev_mode <= PRV_S) {
|
||||
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTEREN)) {
|
||||
cen &= csr_read(CSR_MCOUNTEREN);
|
||||
if (virt)
|
||||
cen &= csr_read(CSR_HCOUNTEREN);
|
||||
} else {
|
||||
cen = 0;
|
||||
}
|
||||
}
|
||||
if (prev_mode == PRV_U) {
|
||||
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_SCOUNTEREN))
|
||||
cen &= csr_read(CSR_SCOUNTEREN);
|
||||
else
|
||||
cen = 0;
|
||||
}
|
||||
|
||||
return ((cen >> hpm_num) & 1) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs,
|
||||
ulong *csr_val)
|
||||
{
|
||||
int ret = 0;
|
||||
ulong cen = -1UL;
|
||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||
ulong prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
|
||||
#if __riscv_xlen == 32
|
||||
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
|
||||
@@ -28,9 +54,6 @@ int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs,
|
||||
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
|
||||
#endif
|
||||
|
||||
if (prev_mode == PRV_U)
|
||||
cen = csr_read(CSR_SCOUNTEREN);
|
||||
|
||||
switch (csr_num) {
|
||||
case CSR_HTIMEDELTA:
|
||||
if (prev_mode == PRV_S && !virt)
|
||||
@@ -39,31 +62,27 @@ int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs,
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
case CSR_CYCLE:
|
||||
if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1))
|
||||
return -1;
|
||||
if (!hpm_allowed(csr_num - CSR_CYCLE, prev_mode, virt))
|
||||
return SBI_ENOTSUPP;
|
||||
*csr_val = csr_read(CSR_MCYCLE);
|
||||
break;
|
||||
case CSR_TIME:
|
||||
if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1))
|
||||
return -1;
|
||||
/*
|
||||
* We emulate TIME CSR for both Host (HS/U-mode) and
|
||||
* Guest (VS/VU-mode).
|
||||
*
|
||||
* Faster TIME CSR reads are critical for good performance
|
||||
* in S-mode software so we don't check CSR permissions.
|
||||
*/
|
||||
*csr_val = (virt) ? sbi_timer_virt_value():
|
||||
sbi_timer_value();
|
||||
break;
|
||||
case CSR_INSTRET:
|
||||
if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
|
||||
return -1;
|
||||
if (!hpm_allowed(csr_num - CSR_CYCLE, prev_mode, virt))
|
||||
return SBI_ENOTSUPP;
|
||||
*csr_val = csr_read(CSR_MINSTRET);
|
||||
break;
|
||||
case CSR_MHPMCOUNTER3:
|
||||
if (!((cen >> (3 + CSR_MHPMCOUNTER3 - CSR_MHPMCOUNTER3)) & 1))
|
||||
return -1;
|
||||
*csr_val = csr_read(CSR_MHPMCOUNTER3);
|
||||
break;
|
||||
case CSR_MHPMCOUNTER4:
|
||||
if (!((cen >> (3 + CSR_MHPMCOUNTER4 - CSR_MHPMCOUNTER3)) & 1))
|
||||
return -1;
|
||||
*csr_val = csr_read(CSR_MHPMCOUNTER4);
|
||||
break;
|
||||
|
||||
#if __riscv_xlen == 32
|
||||
case CSR_HTIMEDELTAH:
|
||||
if (prev_mode == PRV_S && !virt)
|
||||
@@ -72,38 +91,61 @@ int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs,
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
case CSR_CYCLEH:
|
||||
if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1))
|
||||
return -1;
|
||||
if (!hpm_allowed(csr_num - CSR_CYCLEH, prev_mode, virt))
|
||||
return SBI_ENOTSUPP;
|
||||
*csr_val = csr_read(CSR_MCYCLEH);
|
||||
break;
|
||||
case CSR_TIMEH:
|
||||
if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1))
|
||||
return -1;
|
||||
/* Refer comments on TIME CSR above. */
|
||||
*csr_val = (virt) ? sbi_timer_virt_value() >> 32:
|
||||
sbi_timer_value() >> 32;
|
||||
break;
|
||||
case CSR_INSTRETH:
|
||||
if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
|
||||
return -1;
|
||||
if (!hpm_allowed(csr_num - CSR_CYCLEH, prev_mode, virt))
|
||||
return SBI_ENOTSUPP;
|
||||
*csr_val = csr_read(CSR_MINSTRETH);
|
||||
break;
|
||||
case CSR_MHPMCOUNTER3H:
|
||||
if (!((cen >> (3 + CSR_MHPMCOUNTER3 - CSR_MHPMCOUNTER3)) & 1))
|
||||
return -1;
|
||||
*csr_val = csr_read(CSR_MHPMCOUNTER3H);
|
||||
break;
|
||||
case CSR_MHPMCOUNTER4H:
|
||||
if (!((cen >> (3 + CSR_MHPMCOUNTER4 - CSR_MHPMCOUNTER3)) & 1))
|
||||
return -1;
|
||||
*csr_val = csr_read(CSR_MHPMCOUNTER4H);
|
||||
break;
|
||||
#endif
|
||||
case CSR_MHPMEVENT3:
|
||||
*csr_val = csr_read(CSR_MHPMEVENT3);
|
||||
break;
|
||||
case CSR_MHPMEVENT4:
|
||||
*csr_val = csr_read(CSR_MHPMEVENT4);
|
||||
|
||||
#define switchcase_hpm(__uref, __mref, __csr) \
|
||||
case __csr: \
|
||||
if ((sbi_hart_mhpm_count(scratch) + 3) <= (__csr - __uref))\
|
||||
return SBI_ENOTSUPP; \
|
||||
if (!hpm_allowed(__csr - __uref, prev_mode, virt)) \
|
||||
return SBI_ENOTSUPP; \
|
||||
*csr_val = csr_read(__mref + __csr - __uref); \
|
||||
break;
|
||||
#define switchcase_hpm_2(__uref, __mref, __csr) \
|
||||
switchcase_hpm(__uref, __mref, __csr + 0) \
|
||||
switchcase_hpm(__uref, __mref, __csr + 1)
|
||||
#define switchcase_hpm_4(__uref, __mref, __csr) \
|
||||
switchcase_hpm_2(__uref, __mref, __csr + 0) \
|
||||
switchcase_hpm_2(__uref, __mref, __csr + 2)
|
||||
#define switchcase_hpm_8(__uref, __mref, __csr) \
|
||||
switchcase_hpm_4(__uref, __mref, __csr + 0) \
|
||||
switchcase_hpm_4(__uref, __mref, __csr + 4)
|
||||
#define switchcase_hpm_16(__uref, __mref, __csr) \
|
||||
switchcase_hpm_8(__uref, __mref, __csr + 0) \
|
||||
switchcase_hpm_8(__uref, __mref, __csr + 8)
|
||||
|
||||
switchcase_hpm(CSR_CYCLE, CSR_MCYCLE, CSR_HPMCOUNTER3)
|
||||
switchcase_hpm_4(CSR_CYCLE, CSR_MCYCLE, CSR_HPMCOUNTER4)
|
||||
switchcase_hpm_8(CSR_CYCLE, CSR_MCYCLE, CSR_HPMCOUNTER8)
|
||||
switchcase_hpm_16(CSR_CYCLE, CSR_MCYCLE, CSR_HPMCOUNTER16)
|
||||
|
||||
#if __riscv_xlen == 32
|
||||
switchcase_hpm(CSR_CYCLEH, CSR_MCYCLEH, CSR_HPMCOUNTER3H)
|
||||
switchcase_hpm_4(CSR_CYCLEH, CSR_MCYCLEH, CSR_HPMCOUNTER4H)
|
||||
switchcase_hpm_8(CSR_CYCLEH, CSR_MCYCLEH, CSR_HPMCOUNTER8H)
|
||||
switchcase_hpm_16(CSR_CYCLEH, CSR_MCYCLEH, CSR_HPMCOUNTER16H)
|
||||
#endif
|
||||
|
||||
#undef switchcase_hpm_16
|
||||
#undef switchcase_hpm_8
|
||||
#undef switchcase_hpm_4
|
||||
#undef switchcase_hpm_2
|
||||
#undef switchcase_hpm
|
||||
|
||||
default:
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
@@ -134,18 +176,6 @@ int sbi_emulate_csr_write(int csr_num, struct sbi_trap_regs *regs,
|
||||
else
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
case CSR_CYCLE:
|
||||
csr_write(CSR_MCYCLE, csr_val);
|
||||
break;
|
||||
case CSR_INSTRET:
|
||||
csr_write(CSR_MINSTRET, csr_val);
|
||||
break;
|
||||
case CSR_MHPMCOUNTER3:
|
||||
csr_write(CSR_MHPMCOUNTER3, csr_val);
|
||||
break;
|
||||
case CSR_MHPMCOUNTER4:
|
||||
csr_write(CSR_MHPMCOUNTER4, csr_val);
|
||||
break;
|
||||
#if __riscv_xlen == 32
|
||||
case CSR_HTIMEDELTAH:
|
||||
if (prev_mode == PRV_S && !virt)
|
||||
@@ -153,25 +183,7 @@ int sbi_emulate_csr_write(int csr_num, struct sbi_trap_regs *regs,
|
||||
else
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
case CSR_CYCLEH:
|
||||
csr_write(CSR_MCYCLEH, csr_val);
|
||||
break;
|
||||
case CSR_INSTRETH:
|
||||
csr_write(CSR_MINSTRETH, csr_val);
|
||||
break;
|
||||
case CSR_MHPMCOUNTER3H:
|
||||
csr_write(CSR_MHPMCOUNTER3H, csr_val);
|
||||
break;
|
||||
case CSR_MHPMCOUNTER4H:
|
||||
csr_write(CSR_MHPMCOUNTER4H, csr_val);
|
||||
break;
|
||||
#endif
|
||||
case CSR_MHPMEVENT3:
|
||||
csr_write(CSR_MHPMEVENT3, csr_val);
|
||||
break;
|
||||
case CSR_MHPMEVENT4:
|
||||
csr_write(CSR_MHPMEVENT4, csr_val);
|
||||
break;
|
||||
default:
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
|
@@ -18,7 +18,7 @@ void sbi_fifo_init(struct sbi_fifo *fifo, void *queue_mem, u16 entries,
|
||||
fifo->queue = queue_mem;
|
||||
fifo->num_entries = entries;
|
||||
fifo->entry_size = entry_size;
|
||||
SPIN_LOCK_INIT(&fifo->qlock);
|
||||
SPIN_LOCK_INIT(fifo->qlock);
|
||||
fifo->avail = fifo->tail = 0;
|
||||
sbi_memset(fifo->queue, 0, (size_t)entries * entry_size);
|
||||
}
|
||||
@@ -43,10 +43,13 @@ u16 sbi_fifo_avail(struct sbi_fifo *fifo)
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool sbi_fifo_is_full(struct sbi_fifo *fifo)
|
||||
int sbi_fifo_is_full(struct sbi_fifo *fifo)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
if (!fifo)
|
||||
return SBI_EINVAL;
|
||||
|
||||
spin_lock(&fifo->qlock);
|
||||
ret = __sbi_fifo_is_full(fifo);
|
||||
spin_unlock(&fifo->qlock);
|
||||
@@ -75,10 +78,13 @@ static inline bool __sbi_fifo_is_empty(struct sbi_fifo *fifo)
|
||||
return (fifo->avail == 0) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
bool sbi_fifo_is_empty(struct sbi_fifo *fifo)
|
||||
int sbi_fifo_is_empty(struct sbi_fifo *fifo)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
if (!fifo)
|
||||
return SBI_EINVAL;
|
||||
|
||||
spin_lock(&fifo->qlock);
|
||||
ret = __sbi_fifo_is_empty(fifo);
|
||||
spin_unlock(&fifo->qlock);
|
||||
@@ -118,7 +124,7 @@ bool sbi_fifo_reset(struct sbi_fifo *fifo)
|
||||
int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
|
||||
int (*fptr)(void *in, void *data))
|
||||
{
|
||||
int i, index = 0;
|
||||
int i, index;
|
||||
int ret = SBI_FIFO_UNCHANGED;
|
||||
void *entry;
|
||||
|
||||
@@ -135,7 +141,7 @@ int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
|
||||
for (i = 0; i < fifo->avail; i++) {
|
||||
index = fifo->tail + i;
|
||||
if (index >= fifo->num_entries)
|
||||
index = index - fifo->num_entries;
|
||||
index -= fifo->num_entries;
|
||||
entry = (void *)fifo->queue + (u32)index * fifo->entry_size;
|
||||
ret = fptr(in, entry);
|
||||
|
||||
|
@@ -13,12 +13,14 @@
|
||||
#include <sbi/riscv_fp.h>
|
||||
#include <sbi/sbi_bitops.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_domain.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>
|
||||
#include <sbi/sbi_trap.h>
|
||||
|
||||
extern void __sbi_expected_trap(void);
|
||||
extern void __sbi_expected_trap_hext(void);
|
||||
@@ -28,10 +30,14 @@ void (*sbi_hart_expected_trap)(void) = &__sbi_expected_trap;
|
||||
struct hart_features {
|
||||
unsigned long features;
|
||||
unsigned int pmp_count;
|
||||
unsigned int pmp_addr_bits;
|
||||
unsigned long pmp_gran;
|
||||
unsigned int mhpm_count;
|
||||
unsigned int mhpm_bits;
|
||||
};
|
||||
static unsigned long hart_features_offset;
|
||||
|
||||
static void mstatus_init(struct sbi_scratch *scratch, u32 hartid)
|
||||
static void mstatus_init(struct sbi_scratch *scratch)
|
||||
{
|
||||
unsigned long mstatus_val = 0;
|
||||
|
||||
@@ -45,13 +51,23 @@ static void mstatus_init(struct sbi_scratch *scratch, u32 hartid)
|
||||
|
||||
csr_write(CSR_MSTATUS, mstatus_val);
|
||||
|
||||
/* Enable user/supervisor use of perf counters */
|
||||
/* Disable user mode usage of all perf counters except default ones (CY, TM, IR) */
|
||||
if (misa_extension('S') &&
|
||||
sbi_hart_has_feature(scratch, SBI_HART_HAS_SCOUNTEREN))
|
||||
csr_write(CSR_SCOUNTEREN, -1);
|
||||
csr_write(CSR_SCOUNTEREN, 7);
|
||||
|
||||
/**
|
||||
* OpenSBI doesn't use any PMU counters in M-mode.
|
||||
* Supervisor mode usage for all counters are enabled by default
|
||||
* But counters will not run until mcountinhibit is set.
|
||||
*/
|
||||
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTEREN))
|
||||
csr_write(CSR_MCOUNTEREN, -1);
|
||||
|
||||
/* All programmable counters will start running at runtime after S-mode request */
|
||||
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT))
|
||||
csr_write(CSR_MCOUNTINHIBIT, 0xFFFFFFF8);
|
||||
|
||||
/* Disable all interrupts */
|
||||
csr_write(CSR_MIE, 0);
|
||||
|
||||
@@ -60,7 +76,7 @@ static void mstatus_init(struct sbi_scratch *scratch, u32 hartid)
|
||||
csr_write(CSR_SATP, 0);
|
||||
}
|
||||
|
||||
static int fp_init(u32 hartid)
|
||||
static int fp_init(struct sbi_scratch *scratch)
|
||||
{
|
||||
#ifdef __riscv_flen
|
||||
int i;
|
||||
@@ -81,7 +97,7 @@ static int fp_init(u32 hartid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
|
||||
static int delegate_traps(struct sbi_scratch *scratch)
|
||||
{
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
unsigned long interrupts, exceptions;
|
||||
@@ -92,6 +108,9 @@ static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
|
||||
|
||||
/* Send M-mode interrupts and most exceptions to S-mode */
|
||||
interrupts = MIP_SSIP | MIP_STIP | MIP_SEIP;
|
||||
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_SSCOFPMF))
|
||||
interrupts |= MIP_LCOFIP;
|
||||
|
||||
exceptions = (1U << CAUSE_MISALIGNED_FETCH) | (1U << CAUSE_BREAKPOINT) |
|
||||
(1U << CAUSE_USER_ECALL);
|
||||
if (sbi_platform_has_mfaults_delegation(plat))
|
||||
@@ -107,7 +126,7 @@ static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
|
||||
* from VS-mode), Guest page faults and Virtual interrupts.
|
||||
*/
|
||||
if (misa_extension('H')) {
|
||||
exceptions |= (1U << CAUSE_SUPERVISOR_ECALL);
|
||||
exceptions |= (1U << CAUSE_VIRTUAL_SUPERVISOR_ECALL);
|
||||
exceptions |= (1U << CAUSE_FETCH_GUEST_PAGE_FAULT);
|
||||
exceptions |= (1U << CAUSE_LOAD_GUEST_PAGE_FAULT);
|
||||
exceptions |= (1U << CAUSE_VIRTUAL_INST_FAULT);
|
||||
@@ -120,19 +139,25 @@ static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sbi_hart_delegation_dump(struct sbi_scratch *scratch)
|
||||
void sbi_hart_delegation_dump(struct sbi_scratch *scratch,
|
||||
const char *prefix, const char *suffix)
|
||||
{
|
||||
if (!misa_extension('S'))
|
||||
/* No delegation possible as mideleg does not exist*/
|
||||
return;
|
||||
|
||||
#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
|
||||
sbi_printf("%sMIDELEG%s: 0x%" PRILX "\n",
|
||||
prefix, suffix, csr_read(CSR_MIDELEG));
|
||||
sbi_printf("%sMEDELEG%s: 0x%" PRILX "\n",
|
||||
prefix, suffix, csr_read(CSR_MEDELEG));
|
||||
}
|
||||
|
||||
unsigned int sbi_hart_mhpm_count(struct sbi_scratch *scratch)
|
||||
{
|
||||
struct hart_features *hfeatures =
|
||||
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||
|
||||
return hfeatures->mhpm_count;
|
||||
}
|
||||
|
||||
unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch)
|
||||
@@ -143,102 +168,69 @@ unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch)
|
||||
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)
|
||||
unsigned long sbi_hart_pmp_granularity(struct sbi_scratch *scratch)
|
||||
{
|
||||
if (sbi_hart_pmp_count(scratch) <= n)
|
||||
return SBI_EINVAL;
|
||||
struct hart_features *hfeatures =
|
||||
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||
|
||||
return pmp_get(n, prot_out, addr_out, size);
|
||||
return hfeatures->pmp_gran;
|
||||
}
|
||||
|
||||
void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
|
||||
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch)
|
||||
{
|
||||
unsigned long prot, addr, size;
|
||||
unsigned int i, pmp_count;
|
||||
struct hart_features *hfeatures =
|
||||
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||
|
||||
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP))
|
||||
return;
|
||||
|
||||
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 __riscv_xlen == 32
|
||||
sbi_printf("PMP%d : 0x%08lx-0x%08lx (A",
|
||||
#else
|
||||
sbi_printf("PMP%d : 0x%016lx-0x%016lx (A",
|
||||
#endif
|
||||
i, addr, addr + size - 1);
|
||||
if (prot & PMP_L)
|
||||
sbi_printf(",L");
|
||||
if (prot & PMP_R)
|
||||
sbi_printf(",R");
|
||||
if (prot & PMP_W)
|
||||
sbi_printf(",W");
|
||||
if (prot & PMP_X)
|
||||
sbi_printf(",X");
|
||||
sbi_printf(")\n");
|
||||
}
|
||||
return hfeatures->pmp_addr_bits;
|
||||
}
|
||||
|
||||
int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long addr,
|
||||
unsigned long attr)
|
||||
unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch)
|
||||
{
|
||||
unsigned long prot, size, tempaddr;
|
||||
unsigned int i, pmp_count;
|
||||
struct hart_features *hfeatures =
|
||||
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||
|
||||
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;
|
||||
return hfeatures->mhpm_bits;
|
||||
}
|
||||
|
||||
static int pmp_init(struct sbi_scratch *scratch, u32 hartid)
|
||||
int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
|
||||
{
|
||||
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);
|
||||
struct sbi_domain_memregion *reg;
|
||||
struct sbi_domain *dom = sbi_domain_thishart_ptr();
|
||||
unsigned int pmp_idx = 0, pmp_flags, pmp_bits, pmp_gran_log2;
|
||||
unsigned int pmp_count = sbi_hart_pmp_count(scratch);
|
||||
unsigned long pmp_addr = 0, pmp_addr_max = 0;
|
||||
|
||||
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP))
|
||||
if (!pmp_count)
|
||||
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(pmp_idx++, 0, fw_start, fw_size_log2);
|
||||
pmp_gran_log2 = log2roundup(sbi_hart_pmp_granularity(scratch));
|
||||
pmp_bits = sbi_hart_pmp_addrbits(scratch) - 1;
|
||||
pmp_addr_max = (1UL << pmp_bits) | ((1UL << pmp_bits) - 1);
|
||||
|
||||
/* Platform specific PMP regions */
|
||||
count = sbi_platform_pmp_region_count(plat, hartid);
|
||||
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(pmp_idx++, prot, addr, log2size);
|
||||
sbi_domain_for_each_memregion(dom, reg) {
|
||||
if (pmp_count <= pmp_idx)
|
||||
break;
|
||||
|
||||
pmp_flags = 0;
|
||||
if (reg->flags & SBI_DOMAIN_MEMREGION_READABLE)
|
||||
pmp_flags |= PMP_R;
|
||||
if (reg->flags & SBI_DOMAIN_MEMREGION_WRITEABLE)
|
||||
pmp_flags |= PMP_W;
|
||||
if (reg->flags & SBI_DOMAIN_MEMREGION_EXECUTABLE)
|
||||
pmp_flags |= PMP_X;
|
||||
if (reg->flags & SBI_DOMAIN_MEMREGION_MMODE)
|
||||
pmp_flags |= PMP_L;
|
||||
|
||||
pmp_addr = reg->base >> PMP_SHIFT;
|
||||
if (pmp_gran_log2 <= reg->order && pmp_addr < pmp_addr_max)
|
||||
pmp_set(pmp_idx++, pmp_flags, reg->base, reg->order);
|
||||
else {
|
||||
sbi_printf("Can not configure pmp for domain %s", dom->name);
|
||||
sbi_printf(" because memory region address %lx or size %lx is not in range\n",
|
||||
reg->base, reg->order);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
@@ -276,15 +268,18 @@ static inline char *sbi_hart_feature_id2string(unsigned long 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_MCOUNTINHIBIT:
|
||||
fstr = "mcountinhibit";
|
||||
break;
|
||||
case SBI_HART_HAS_SSCOFPMF:
|
||||
fstr = "sscofpmf";
|
||||
break;
|
||||
case SBI_HART_HAS_TIME:
|
||||
fstr = "time";
|
||||
break;
|
||||
@@ -338,6 +333,56 @@ done:
|
||||
sbi_strncpy(features_str, "none", nfstr);
|
||||
}
|
||||
|
||||
static unsigned long hart_pmp_get_allowed_addr(void)
|
||||
{
|
||||
unsigned long val = 0;
|
||||
struct sbi_trap_info trap = {0};
|
||||
|
||||
csr_write_allowed(CSR_PMPCFG0, (ulong)&trap, 0);
|
||||
if (trap.cause)
|
||||
return 0;
|
||||
|
||||
csr_write_allowed(CSR_PMPADDR0, (ulong)&trap, PMP_ADDR_MASK);
|
||||
if (!trap.cause) {
|
||||
val = csr_read_allowed(CSR_PMPADDR0, (ulong)&trap);
|
||||
if (trap.cause)
|
||||
val = 0;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int hart_pmu_get_allowed_bits(void)
|
||||
{
|
||||
unsigned long val = ~(0UL);
|
||||
struct sbi_trap_info trap = {0};
|
||||
int num_bits = 0;
|
||||
|
||||
/**
|
||||
* It is assumed that platforms will implement same number of bits for
|
||||
* all the performance counters including mcycle/minstret.
|
||||
*/
|
||||
csr_write_allowed(CSR_MHPMCOUNTER3, (ulong)&trap, val);
|
||||
if (!trap.cause) {
|
||||
val = csr_read_allowed(CSR_MHPMCOUNTER3, (ulong)&trap);
|
||||
if (trap.cause)
|
||||
return 0;
|
||||
}
|
||||
num_bits = __fls(val) + 1;
|
||||
#if __riscv_xlen == 32
|
||||
csr_write_allowed(CSR_MHPMCOUNTER3H, (ulong)&trap, val);
|
||||
if (!trap.cause) {
|
||||
val = csr_read_allowed(CSR_MHPMCOUNTER3H, (ulong)&trap);
|
||||
if (trap.cause)
|
||||
return num_bits;
|
||||
}
|
||||
num_bits += __fls(val) + 1;
|
||||
|
||||
#endif
|
||||
|
||||
return num_bits;
|
||||
}
|
||||
|
||||
static void hart_detect_features(struct sbi_scratch *scratch)
|
||||
{
|
||||
struct sbi_trap_info trap = {0};
|
||||
@@ -348,39 +393,83 @@ static void hart_detect_features(struct sbi_scratch *scratch)
|
||||
hfeatures = sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||
hfeatures->features = 0;
|
||||
hfeatures->pmp_count = 0;
|
||||
hfeatures->mhpm_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++; \
|
||||
#define __check_csr(__csr, __rdonly, __wrval, __field, __skip) \
|
||||
val = csr_read_allowed(__csr, (ulong)&trap); \
|
||||
if (!trap.cause) { \
|
||||
if (__rdonly) { \
|
||||
(hfeatures->__field)++; \
|
||||
} else { \
|
||||
csr_write_allowed(__csr, (ulong)&trap, __wrval);\
|
||||
if (!trap.cause) { \
|
||||
if (csr_swap(__csr, val) == __wrval) \
|
||||
(hfeatures->__field)++; \
|
||||
else \
|
||||
goto __skip; \
|
||||
} else { \
|
||||
goto __skip; \
|
||||
} \
|
||||
} \
|
||||
} else { \
|
||||
goto __skip; \
|
||||
}
|
||||
__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
|
||||
#define __check_csr_2(__csr, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr(__csr + 0, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr(__csr + 1, __rdonly, __wrval, __field, __skip)
|
||||
#define __check_csr_4(__csr, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr_2(__csr + 0, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr_2(__csr + 2, __rdonly, __wrval, __field, __skip)
|
||||
#define __check_csr_8(__csr, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr_4(__csr + 0, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr_4(__csr + 4, __rdonly, __wrval, __field, __skip)
|
||||
#define __check_csr_16(__csr, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr_8(__csr + 0, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr_8(__csr + 8, __rdonly, __wrval, __field, __skip)
|
||||
#define __check_csr_32(__csr, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr_16(__csr + 0, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr_16(__csr + 16, __rdonly, __wrval, __field, __skip)
|
||||
#define __check_csr_64(__csr, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr_32(__csr + 0, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr_32(__csr + 32, __rdonly, __wrval, __field, __skip)
|
||||
|
||||
/* Set hart PMP feature if we have at least one PMP region */
|
||||
if (hfeatures->pmp_count)
|
||||
hfeatures->features |= SBI_HART_HAS_PMP;
|
||||
/**
|
||||
* Detect the allowed address bits & granularity. At least PMPADDR0
|
||||
* should be implemented.
|
||||
*/
|
||||
val = hart_pmp_get_allowed_addr();
|
||||
if (val) {
|
||||
hfeatures->pmp_gran = 1 << (__ffs(val) + 2);
|
||||
hfeatures->pmp_addr_bits = __fls(val) + 1;
|
||||
/* Detect number of PMP regions. At least PMPADDR0 should be implemented*/
|
||||
__check_csr_64(CSR_PMPADDR0, 0, val, pmp_count, __pmp_skip);
|
||||
}
|
||||
__pmp_skip:
|
||||
|
||||
/* Detect number of MHPM counters */
|
||||
__check_csr(CSR_MHPMCOUNTER3, 0, 1UL, mhpm_count, __mhpm_skip);
|
||||
hfeatures->mhpm_bits = hart_pmu_get_allowed_bits();
|
||||
|
||||
__check_csr_4(CSR_MHPMCOUNTER4, 0, 1UL, mhpm_count, __mhpm_skip);
|
||||
__check_csr_8(CSR_MHPMCOUNTER8, 0, 1UL, mhpm_count, __mhpm_skip);
|
||||
__check_csr_16(CSR_MHPMCOUNTER16, 0, 1UL, mhpm_count, __mhpm_skip);
|
||||
|
||||
/**
|
||||
* No need to check for MHPMCOUNTERH for RV32 as they are expected to be
|
||||
* implemented if MHPMCOUNTER is implemented.
|
||||
*/
|
||||
|
||||
__mhpm_skip:
|
||||
|
||||
#undef __check_csr_64
|
||||
#undef __check_csr_32
|
||||
#undef __check_csr_16
|
||||
#undef __check_csr_8
|
||||
#undef __check_csr_4
|
||||
#undef __check_csr_2
|
||||
#undef __check_csr
|
||||
|
||||
/* 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);
|
||||
@@ -389,7 +478,6 @@ static void hart_detect_features(struct sbi_scratch *scratch)
|
||||
}
|
||||
|
||||
/* 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);
|
||||
@@ -397,41 +485,61 @@ static void hart_detect_features(struct sbi_scratch *scratch)
|
||||
hfeatures->features |= SBI_HART_HAS_MCOUNTEREN;
|
||||
}
|
||||
|
||||
/* Detect if hart supports MCOUNTINHIBIT feature */
|
||||
val = csr_read_allowed(CSR_MCOUNTINHIBIT, (unsigned long)&trap);
|
||||
if (!trap.cause) {
|
||||
csr_write_allowed(CSR_MCOUNTINHIBIT, (unsigned long)&trap, val);
|
||||
if (!trap.cause)
|
||||
hfeatures->features |= SBI_HART_HAS_MCOUNTINHIBIT;
|
||||
}
|
||||
|
||||
/* Counter overflow/filtering is not useful without mcounter/inhibit */
|
||||
if (hfeatures->features & SBI_HART_HAS_MCOUNTINHIBIT &&
|
||||
hfeatures->features & SBI_HART_HAS_MCOUNTEREN) {
|
||||
/* Detect if hart supports sscofpmf */
|
||||
csr_read_allowed(CSR_SCOUNTOVF, (unsigned long)&trap);
|
||||
if (!trap.cause)
|
||||
hfeatures->features |= SBI_HART_HAS_SSCOFPMF;
|
||||
}
|
||||
|
||||
/* 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 sbi_hart_reinit(struct sbi_scratch *scratch)
|
||||
{
|
||||
int rc;
|
||||
|
||||
mstatus_init(scratch);
|
||||
|
||||
rc = fp_init(scratch);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = delegate_traps(scratch);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||
{
|
||||
if (cold_boot) {
|
||||
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");
|
||||
sizeof(struct hart_features));
|
||||
if (!hart_features_offset)
|
||||
return SBI_ENOMEM;
|
||||
}
|
||||
|
||||
hart_detect_features(scratch);
|
||||
|
||||
mstatus_init(scratch, hartid);
|
||||
|
||||
rc = fp_init(hartid);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = delegate_traps(scratch, hartid);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return pmp_init(scratch, hartid);
|
||||
return sbi_hart_reinit(scratch);
|
||||
}
|
||||
|
||||
void __attribute__((noreturn)) sbi_hart_hang(void)
|
||||
@@ -496,9 +604,11 @@ sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
|
||||
csr_write(CSR_SIE, 0);
|
||||
csr_write(CSR_SATP, 0);
|
||||
} else if (next_mode == PRV_U) {
|
||||
csr_write(CSR_UTVEC, next_addr);
|
||||
csr_write(CSR_USCRATCH, 0);
|
||||
csr_write(CSR_UIE, 0);
|
||||
if (misa_extension('N')) {
|
||||
csr_write(CSR_UTVEC, next_addr);
|
||||
csr_write(CSR_USCRATCH, 0);
|
||||
csr_write(CSR_UIE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
register unsigned long a0 asm("a0") = arg0;
|
||||
|
@@ -27,7 +27,7 @@
|
||||
.global __sbi_hfence_gvma_vmid_gpa
|
||||
__sbi_hfence_gvma_vmid_gpa:
|
||||
/*
|
||||
* rs1 = a0 (GPA)
|
||||
* rs1 = a0 (GPA >> 2)
|
||||
* rs2 = a1 (VMID)
|
||||
* HFENCE.GVMA a0, a1
|
||||
* 0110001 01011 01010 000 00000 1110011
|
||||
@@ -51,7 +51,7 @@ __sbi_hfence_gvma_vmid:
|
||||
.global __sbi_hfence_gvma_gpa
|
||||
__sbi_hfence_gvma_gpa:
|
||||
/*
|
||||
* rs1 = a0 (GPA)
|
||||
* rs1 = a0 (GPA >> 2)
|
||||
* rs2 = zero
|
||||
* HFENCE.GVMA a0
|
||||
* 0110001 00000 01010 000 00000 1110011
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include <sbi/riscv_atomic.h>
|
||||
#include <sbi/sbi_bitops.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_domain.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
@@ -20,85 +21,73 @@
|
||||
#include <sbi/sbi_hsm.h>
|
||||
#include <sbi/sbi_init.h>
|
||||
#include <sbi/sbi_ipi.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/sbi_system.h>
|
||||
#include <sbi/sbi_timer.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
|
||||
static const struct sbi_hsm_device *hsm_dev = NULL;
|
||||
static unsigned long hart_data_offset;
|
||||
|
||||
/** Per hart specific data to manage state transition **/
|
||||
struct sbi_hsm_data {
|
||||
atomic_t state;
|
||||
unsigned long suspend_type;
|
||||
unsigned long saved_mie;
|
||||
unsigned long saved_mip;
|
||||
};
|
||||
|
||||
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)
|
||||
static inline 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;
|
||||
return SBI_EINVAL;
|
||||
|
||||
hdata = sbi_scratch_offset_ptr(scratch, hart_data_offset);
|
||||
|
||||
return atomic_read(&hdata->state);
|
||||
}
|
||||
|
||||
bool sbi_hsm_hart_started(u32 hartid)
|
||||
int sbi_hsm_hart_get_state(const struct sbi_domain *dom, u32 hartid)
|
||||
{
|
||||
if (sbi_hsm_hart_get_state(hartid) == SBI_HART_STARTED)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
if (!sbi_domain_is_assigned_hart(dom, hartid))
|
||||
return SBI_EINVAL;
|
||||
|
||||
return __sbi_hsm_hart_get_state(hartid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ulong HART mask for given HART base ID
|
||||
* @param dom the domain to be used for output HART mask
|
||||
* @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)
|
||||
int sbi_hsm_hart_interruptible_mask(const struct sbi_domain *dom,
|
||||
ulong hbase, ulong *out_hmask)
|
||||
{
|
||||
ulong i;
|
||||
ulong hcount = sbi_scratch_last_hartid() + 1;
|
||||
int hstate;
|
||||
ulong i, hmask, dmask;
|
||||
ulong hend = sbi_scratch_last_hartid() + 1;
|
||||
|
||||
*out_hmask = 0;
|
||||
if (hcount <= hbase)
|
||||
if (hend <= hbase)
|
||||
return SBI_EINVAL;
|
||||
if (BITS_PER_LONG < (hcount - hbase))
|
||||
hcount = BITS_PER_LONG;
|
||||
if (BITS_PER_LONG < (hend - hbase))
|
||||
hend = hbase + BITS_PER_LONG;
|
||||
|
||||
for (i = hbase; i < hcount; i++) {
|
||||
if (sbi_hsm_hart_get_state(i) == SBI_HART_STARTED)
|
||||
*out_hmask |= 1UL << (i - hbase);
|
||||
dmask = sbi_domain_get_assigned_hartmask(dom, hbase);
|
||||
for (i = hbase; i < hend; i++) {
|
||||
hmask = 1UL << (i - hbase);
|
||||
if (dmask & hmask) {
|
||||
hstate = __sbi_hsm_hart_get_state(i);
|
||||
if (hstate == SBI_HSM_STATE_STARTED ||
|
||||
hstate == SBI_HSM_STATE_SUSPENDED)
|
||||
*out_hmask |= hmask;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -110,16 +99,15 @@ void sbi_hsm_prepare_next_jump(struct sbi_scratch *scratch, u32 hartid)
|
||||
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)
|
||||
oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_START_PENDING,
|
||||
SBI_HSM_STATE_STARTED);
|
||||
if (oldstate != SBI_HSM_STATE_START_PENDING)
|
||||
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 */
|
||||
@@ -129,15 +117,65 @@ static void sbi_hsm_hart_wait(struct sbi_scratch *scratch, u32 hartid)
|
||||
csr_set(CSR_MIE, MIP_MSIP);
|
||||
|
||||
/* Wait for hart_add call*/
|
||||
while (atomic_read(&hdata->state) != SBI_HART_STARTING) {
|
||||
while (atomic_read(&hdata->state) != SBI_HSM_STATE_START_PENDING) {
|
||||
wfi();
|
||||
};
|
||||
|
||||
/* Restore MIE CSR */
|
||||
csr_write(CSR_MIE, saved_mie);
|
||||
|
||||
/* Clear current HART IPI */
|
||||
sbi_platform_ipi_clear(plat, hartid);
|
||||
/*
|
||||
* No need to clear IPI here because the sbi_ipi_init() will
|
||||
* clear it for current HART via sbi_platform_ipi_init().
|
||||
*/
|
||||
}
|
||||
|
||||
const struct sbi_hsm_device *sbi_hsm_get_device(void)
|
||||
{
|
||||
return hsm_dev;
|
||||
}
|
||||
|
||||
void sbi_hsm_set_device(const struct sbi_hsm_device *dev)
|
||||
{
|
||||
if (!dev || hsm_dev)
|
||||
return;
|
||||
|
||||
hsm_dev = dev;
|
||||
}
|
||||
|
||||
static bool hsm_device_has_hart_hotplug(void)
|
||||
{
|
||||
if (hsm_dev && hsm_dev->hart_start && hsm_dev->hart_stop)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool hsm_device_has_hart_secondary_boot(void)
|
||||
{
|
||||
if (hsm_dev && hsm_dev->hart_start && !hsm_dev->hart_stop)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int hsm_device_hart_start(u32 hartid, ulong saddr)
|
||||
{
|
||||
if (hsm_dev && hsm_dev->hart_start)
|
||||
return hsm_dev->hart_start(hartid, saddr);
|
||||
return SBI_ENOTSUPP;
|
||||
}
|
||||
|
||||
static int hsm_device_hart_stop(void)
|
||||
{
|
||||
if (hsm_dev && hsm_dev->hart_stop)
|
||||
return hsm_dev->hart_stop();
|
||||
return SBI_ENOTSUPP;
|
||||
}
|
||||
|
||||
static int hsm_device_hart_suspend(u32 suspend_type, ulong raddr)
|
||||
{
|
||||
if (hsm_dev && hsm_dev->hart_suspend)
|
||||
return hsm_dev->hart_suspend(suspend_type, raddr);
|
||||
return SBI_ENOTSUPP;
|
||||
}
|
||||
|
||||
int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
|
||||
@@ -147,8 +185,7 @@ int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
|
||||
struct sbi_hsm_data *hdata;
|
||||
|
||||
if (cold_boot) {
|
||||
hart_data_offset = sbi_scratch_alloc_offset(sizeof(*hdata),
|
||||
"HART_DATA");
|
||||
hart_data_offset = sbi_scratch_alloc_offset(sizeof(*hdata));
|
||||
if (!hart_data_offset)
|
||||
return SBI_ENOMEM;
|
||||
|
||||
@@ -161,7 +198,9 @@ int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
|
||||
hdata = sbi_scratch_offset_ptr(rscratch,
|
||||
hart_data_offset);
|
||||
ATOMIC_INIT(&hdata->state,
|
||||
(i == hartid) ? SBI_HART_STARTING : SBI_HART_STOPPED);
|
||||
(i == hartid) ?
|
||||
SBI_HSM_STATE_START_PENDING :
|
||||
SBI_HSM_STATE_STOPPED);
|
||||
}
|
||||
} else {
|
||||
sbi_hsm_hart_wait(scratch, hartid);
|
||||
@@ -173,18 +212,17 @@ int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
|
||||
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)
|
||||
hstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_STOP_PENDING,
|
||||
SBI_HSM_STATE_STOPPED);
|
||||
if (hstate != SBI_HSM_STATE_STOP_PENDING)
|
||||
goto fail_exit;
|
||||
|
||||
if (sbi_platform_has_hart_hotplug(plat)) {
|
||||
sbi_platform_hart_stop(plat);
|
||||
if (hsm_device_has_hart_hotplug()) {
|
||||
hsm_device_hart_stop();
|
||||
/* It should never reach here */
|
||||
goto fail_exit;
|
||||
}
|
||||
@@ -202,47 +240,50 @@ fail_exit:
|
||||
sbi_hart_hang();
|
||||
}
|
||||
|
||||
int sbi_hsm_hart_start(struct sbi_scratch *scratch, u32 hartid,
|
||||
ulong saddr, ulong priv)
|
||||
int sbi_hsm_hart_start(struct sbi_scratch *scratch,
|
||||
const struct sbi_domain *dom,
|
||||
u32 hartid, ulong saddr, ulong smode, 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);
|
||||
|
||||
/* For now, we only allow start mode to be S-mode or U-mode. */
|
||||
if (smode != PRV_S && smode != PRV_U)
|
||||
return SBI_EINVAL;
|
||||
if (dom && !sbi_domain_is_assigned_hart(dom, hartid))
|
||||
return SBI_EINVAL;
|
||||
if (dom && !sbi_domain_check_addr(dom, saddr, smode,
|
||||
SBI_DOMAIN_EXECUTE))
|
||||
return SBI_EINVALID_ADDR;
|
||||
|
||||
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)
|
||||
hstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_STOPPED,
|
||||
SBI_HSM_STATE_START_PENDING);
|
||||
if (hstate == SBI_HSM_STATE_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)
|
||||
if (hstate != SBI_HSM_STATE_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;
|
||||
rscratch->next_mode = smode;
|
||||
|
||||
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);
|
||||
if (hsm_device_has_hart_hotplug() ||
|
||||
(hsm_device_has_hart_secondary_boot() && !init_count)) {
|
||||
return hsm_device_hart_start(hartid, scratch->warmboot_addr);
|
||||
} else {
|
||||
sbi_platform_ipi_send(plat, hartid);
|
||||
sbi_ipi_raw_send(hartid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -251,19 +292,19 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch, u32 hartid,
|
||||
int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow)
|
||||
{
|
||||
int oldstate;
|
||||
u32 hartid = current_hartid();
|
||||
const struct sbi_domain *dom = sbi_domain_thishart_ptr();
|
||||
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
|
||||
hart_data_offset);
|
||||
|
||||
if (!sbi_hsm_hart_started(hartid))
|
||||
return SBI_EINVAL;
|
||||
if (!dom)
|
||||
return SBI_EFAIL;
|
||||
|
||||
oldstate = atomic_cmpxchg(&hdata->state, SBI_HART_STARTED,
|
||||
SBI_HART_STOPPING);
|
||||
if (oldstate != SBI_HART_STARTED) {
|
||||
oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_STARTED,
|
||||
SBI_HSM_STATE_STOP_PENDING);
|
||||
if (oldstate != SBI_HSM_STATE_STARTED) {
|
||||
sbi_printf("%s: ERR: The hart is in invalid state [%u]\n",
|
||||
__func__, oldstate);
|
||||
return SBI_EDENIED;
|
||||
return SBI_EFAIL;
|
||||
}
|
||||
|
||||
if (exitnow)
|
||||
@@ -271,3 +312,182 @@ int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __sbi_hsm_suspend_ret_default(struct sbi_scratch *scratch)
|
||||
{
|
||||
/* Wait for interrupt */
|
||||
wfi();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __sbi_hsm_suspend_non_ret_save(struct sbi_scratch *scratch)
|
||||
{
|
||||
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
|
||||
hart_data_offset);
|
||||
|
||||
/*
|
||||
* We will be resuming in warm-boot path so the MIE and MIP CSRs
|
||||
* will be back to initial state. It is possible that HART has
|
||||
* configured timer event before going to suspend state so we
|
||||
* should save MIE and MIP CSRs and restore it after resuming.
|
||||
*
|
||||
* Further, the M-mode bits in MIP CSR are read-only and set by
|
||||
* external devices (such as interrupt controller) whereas all
|
||||
* VS-mode bits in MIP are read-only alias of bits in HVIP CSR.
|
||||
*
|
||||
* This means we should only save/restore S-mode bits of MIP CSR
|
||||
* such as MIP.SSIP and MIP.STIP.
|
||||
*/
|
||||
|
||||
hdata->saved_mie = csr_read(CSR_MIE);
|
||||
hdata->saved_mip = csr_read(CSR_MIP) & (MIP_SSIP | MIP_STIP);
|
||||
}
|
||||
|
||||
static void __sbi_hsm_suspend_non_ret_restore(struct sbi_scratch *scratch)
|
||||
{
|
||||
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
|
||||
hart_data_offset);
|
||||
|
||||
csr_write(CSR_MIE, hdata->saved_mie);
|
||||
csr_write(CSR_MIP, (hdata->saved_mip & (MIP_SSIP | MIP_STIP)));
|
||||
}
|
||||
|
||||
static int __sbi_hsm_suspend_non_ret_default(struct sbi_scratch *scratch,
|
||||
ulong raddr)
|
||||
{
|
||||
void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr;
|
||||
|
||||
/* Wait for interrupt */
|
||||
wfi();
|
||||
|
||||
/*
|
||||
* Directly jump to warm reboot to simulate resume from a
|
||||
* non-retentive suspend.
|
||||
*/
|
||||
jump_warmboot();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch)
|
||||
{
|
||||
int oldstate;
|
||||
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
|
||||
hart_data_offset);
|
||||
|
||||
/* If current HART was SUSPENDED then set RESUME_PENDING state */
|
||||
oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_SUSPENDED,
|
||||
SBI_HSM_STATE_RESUME_PENDING);
|
||||
if (oldstate != SBI_HSM_STATE_SUSPENDED) {
|
||||
sbi_printf("%s: ERR: The hart is in invalid state [%u]\n",
|
||||
__func__, oldstate);
|
||||
sbi_hart_hang();
|
||||
}
|
||||
}
|
||||
|
||||
void sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch)
|
||||
{
|
||||
u32 oldstate;
|
||||
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
|
||||
hart_data_offset);
|
||||
|
||||
/* If current HART was RESUME_PENDING then set STARTED state */
|
||||
oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_RESUME_PENDING,
|
||||
SBI_HSM_STATE_STARTED);
|
||||
if (oldstate != SBI_HSM_STATE_RESUME_PENDING) {
|
||||
sbi_printf("%s: ERR: The hart is in invalid state [%u]\n",
|
||||
__func__, oldstate);
|
||||
sbi_hart_hang();
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore some of the M-mode CSRs which we are re-configured by
|
||||
* the warm-boot sequence.
|
||||
*/
|
||||
__sbi_hsm_suspend_non_ret_restore(scratch);
|
||||
}
|
||||
|
||||
int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type,
|
||||
ulong raddr, ulong rmode, ulong priv)
|
||||
{
|
||||
int oldstate, ret;
|
||||
const struct sbi_domain *dom = sbi_domain_thishart_ptr();
|
||||
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
|
||||
hart_data_offset);
|
||||
|
||||
/* For now, we only allow suspend from S-mode or U-mode. */
|
||||
|
||||
/* Sanity check on domain assigned to current HART */
|
||||
if (!dom)
|
||||
return SBI_EINVAL;
|
||||
|
||||
/* Sanity check on suspend type */
|
||||
if (SBI_HSM_SUSPEND_RET_DEFAULT < suspend_type &&
|
||||
suspend_type < SBI_HSM_SUSPEND_RET_PLATFORM)
|
||||
return SBI_EINVAL;
|
||||
if (SBI_HSM_SUSPEND_NON_RET_DEFAULT < suspend_type &&
|
||||
suspend_type < SBI_HSM_SUSPEND_NON_RET_PLATFORM)
|
||||
return SBI_EINVAL;
|
||||
|
||||
/* Additional sanity check for non-retentive suspend */
|
||||
if (suspend_type & SBI_HSM_SUSP_NON_RET_BIT) {
|
||||
if (rmode != PRV_S && rmode != PRV_U)
|
||||
return SBI_EINVAL;
|
||||
if (dom && !sbi_domain_check_addr(dom, raddr, rmode,
|
||||
SBI_DOMAIN_EXECUTE))
|
||||
return SBI_EINVALID_ADDR;
|
||||
}
|
||||
|
||||
/* Save the resume address and resume mode */
|
||||
scratch->next_arg1 = priv;
|
||||
scratch->next_addr = raddr;
|
||||
scratch->next_mode = rmode;
|
||||
|
||||
/* Directly move from STARTED to SUSPENDED state */
|
||||
oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_STARTED,
|
||||
SBI_HSM_STATE_SUSPENDED);
|
||||
if (oldstate != SBI_HSM_STATE_STARTED) {
|
||||
sbi_printf("%s: ERR: The hart is in invalid state [%u]\n",
|
||||
__func__, oldstate);
|
||||
ret = SBI_EDENIED;
|
||||
goto fail_restore_state;
|
||||
}
|
||||
|
||||
/* Save the suspend type */
|
||||
hdata->suspend_type = suspend_type;
|
||||
|
||||
/*
|
||||
* Save context which will be restored after resuming from
|
||||
* non-retentive suspend.
|
||||
*/
|
||||
if (suspend_type & SBI_HSM_SUSP_NON_RET_BIT)
|
||||
__sbi_hsm_suspend_non_ret_save(scratch);
|
||||
|
||||
/* Try platform specific suspend */
|
||||
ret = hsm_device_hart_suspend(suspend_type, scratch->warmboot_addr);
|
||||
if (ret == SBI_ENOTSUPP) {
|
||||
/* Try generic implementation of default suspend types */
|
||||
if (suspend_type == SBI_HSM_SUSPEND_RET_DEFAULT) {
|
||||
ret = __sbi_hsm_suspend_ret_default(scratch);
|
||||
} else if (suspend_type == SBI_HSM_SUSPEND_NON_RET_DEFAULT) {
|
||||
ret = __sbi_hsm_suspend_non_ret_default(scratch,
|
||||
scratch->warmboot_addr);
|
||||
}
|
||||
}
|
||||
|
||||
fail_restore_state:
|
||||
/*
|
||||
* We might have successfully resumed from retentive suspend
|
||||
* or suspend failed. In both cases, we restore state of hart.
|
||||
*/
|
||||
oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_SUSPENDED,
|
||||
SBI_HSM_STATE_STARTED);
|
||||
if (oldstate != SBI_HSM_STATE_SUSPENDED) {
|
||||
sbi_printf("%s: ERR: The hart is in invalid state [%u]\n",
|
||||
__func__, oldstate);
|
||||
sbi_hart_hang();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include <sbi/sbi_emulate_csr.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_illegal_insn.h>
|
||||
#include <sbi/sbi_pmu.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
#include <sbi/sbi_unpriv.h>
|
||||
|
||||
@@ -118,13 +119,23 @@ int sbi_illegal_insn_handler(ulong insn, struct sbi_trap_regs *regs)
|
||||
{
|
||||
struct sbi_trap_info uptrap;
|
||||
|
||||
/*
|
||||
* We only deal with 32-bit (or longer) illegal instructions. If we
|
||||
* see instruction is zero OR instruction is 16-bit then we fetch and
|
||||
* check the instruction encoding using unprivilege access.
|
||||
*
|
||||
* The program counter (PC) in RISC-V world is always 2-byte aligned
|
||||
* so handling only 32-bit (or longer) illegal instructions also help
|
||||
* the case where MTVAL CSR contains instruction address for illegal
|
||||
* instruction trap.
|
||||
*/
|
||||
|
||||
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_ILLEGAL_INSN);
|
||||
if (unlikely((insn & 3) != 3)) {
|
||||
if (insn == 0) {
|
||||
insn = sbi_get_insn(regs->mepc, &uptrap);
|
||||
if (uptrap.cause) {
|
||||
uptrap.epc = regs->mepc;
|
||||
return sbi_trap_redirect(regs, &uptrap);
|
||||
}
|
||||
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, regs);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user