forked from Mirrors/opensbi
Compare commits
447 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a2b255b889 | ||
![]() |
bbd065d903 | ||
![]() |
ba29293dc9 | ||
![]() |
63e09ad3f7 | ||
![]() |
2b80b92f02 | ||
![]() |
5a57e8cd41 | ||
![]() |
3284bea833 | ||
![]() |
cdebae2cc9 | ||
![]() |
80169b25f8 | ||
![]() |
416ceb3cd7 | ||
![]() |
3daac8fb87 | ||
![]() |
776770d2ad | ||
![]() |
056fe6f85d | ||
![]() |
2c8be566f3 | ||
![]() |
925ce14622 | ||
![]() |
2707250495 | ||
![]() |
446fa65eb5 | ||
![]() |
a894187e28 | ||
![]() |
35cba92655 | ||
![]() |
6112d584d4 | ||
![]() |
a2e254e881 | ||
![]() |
87aa3069d1 | ||
![]() |
a25fc74699 | ||
![]() |
06968103dc | ||
![]() |
11a0ba5d4b | ||
![]() |
ee725174ba | ||
![]() |
93da66b7d4 | ||
![]() |
07419ec84b | ||
![]() |
88398696c8 | ||
![]() |
11bf49b444 | ||
![]() |
6b9a849482 | ||
![]() |
d162009612 | ||
![]() |
e19d419f15 | ||
![]() |
0308f93dc4 | ||
![]() |
009ae4e602 | ||
![]() |
0b3262efc6 | ||
![]() |
535c661d87 | ||
![]() |
2e50c24399 | ||
![]() |
1b9e743c3d | ||
![]() |
effd89aa05 | ||
![]() |
51ec60c9ea | ||
![]() |
a48f2cfd94 | ||
![]() |
090fa99d7c | ||
![]() |
291403f6f2 | ||
![]() |
bd74931d79 | ||
![]() |
b70d6285f0 | ||
![]() |
f520256d03 | ||
![]() |
791704cd09 | ||
![]() |
574b9c8ec2 | ||
![]() |
16bb930533 | ||
![]() |
dc0bb19bd2 | ||
![]() |
3aaed4fadf | ||
![]() |
6602e11de3 | ||
![]() |
6e5b0cfb45 | ||
![]() |
efcac338bd | ||
![]() |
280f7ae627 | ||
![]() |
2bfdb9e5c2 | ||
![]() |
3b03cdd60c | ||
![]() |
5b2f55d65a | ||
![]() |
98bc25f181 | ||
![]() |
accafb13d4 | ||
![]() |
896d2c99e2 | ||
![]() |
d1e0f7f25b | ||
![]() |
fccdf41d32 | ||
![]() |
07f2ccd990 | ||
![]() |
52fd64b82c | ||
![]() |
88ae718d36 | ||
![]() |
a140a4e862 | ||
![]() |
3e21b96003 | ||
![]() |
492d9b153d | ||
![]() |
8e941e7fe3 | ||
![]() |
c1a6987447 | ||
![]() |
5d0ed1bfb8 | ||
![]() |
cbdd869739 | ||
![]() |
ec0559eb31 | ||
![]() |
3632f2b5c4 | ||
![]() |
e8114c6ae2 | ||
![]() |
d891caeae9 | ||
![]() |
f831b93357 | ||
![]() |
942aca232e | ||
![]() |
9da30f6105 | ||
![]() |
8197c2f1ec | ||
![]() |
d36709fcaf | ||
![]() |
a12542316c | ||
![]() |
e21901d317 | ||
![]() |
6ed125a602 | ||
![]() |
2a6d72534d | ||
![]() |
de525ac18d | ||
![]() |
3669153e06 | ||
![]() |
b7e9d34edf | ||
![]() |
e8bc1621c6 | ||
![]() |
73aea28264 | ||
![]() |
2b51a9dd9c | ||
![]() |
5240d312d3 | ||
![]() |
bff27c1fb4 | ||
![]() |
b8fb96eceb | ||
![]() |
9560fb38fe | ||
![]() |
112daa2e64 | ||
![]() |
22d6ff8675 | ||
![]() |
78c667b6fc | ||
![]() |
e632cd7c81 | ||
![]() |
296e70d69d | ||
![]() |
e6125c3c4f | ||
![]() |
d1e4dff45b | ||
![]() |
130e65dd9d | ||
![]() |
5bd969477f | ||
![]() |
cacfba32cc | ||
![]() |
901d3d7bff | ||
![]() |
c9a296d0ed | ||
![]() |
664692f507 | ||
![]() |
b20bd479ef | ||
![]() |
a9cffd6532 | ||
![]() |
ee1f83ca84 | ||
![]() |
e7e73aa532 | ||
![]() |
7aabeee93e | ||
![]() |
c104c60912 | ||
![]() |
94197a8c49 | ||
![]() |
f46a5643bc | ||
![]() |
6259b2ec2d | ||
![]() |
c744ed77b1 | ||
![]() |
f536e0b02e | ||
![]() |
c2e602707d | ||
![]() |
4a344a9b4c | ||
![]() |
f21d8f7d59 | ||
![]() |
8e97275d97 | ||
![]() |
14a35b0e0e | ||
![]() |
44c5151293 | ||
![]() |
5e20d25f19 | ||
![]() |
e05a9cfefc | ||
![]() |
0e2111e12c | ||
![]() |
0ad866067d | ||
![]() |
6e44ef686a | ||
![]() |
5dd8db5b10 | ||
![]() |
f3fdd041ac | ||
![]() |
4a42a2347c | ||
![]() |
d72f5f1747 | ||
![]() |
cbcfc7b10c | ||
![]() |
6c202c5efd | ||
![]() |
1c099c4f36 | ||
![]() |
c3b98c610b | ||
![]() |
ea6533ada8 | ||
![]() |
a73982d737 | ||
![]() |
ff43168137 | ||
![]() |
cc89fa7b54 | ||
![]() |
3b6fcddceb | ||
![]() |
c6ee5ae5a4 | ||
![]() |
fe0828142f | ||
![]() |
05cbb6e908 | ||
![]() |
458fa74266 | ||
![]() |
40dac06e3c | ||
![]() |
35ef182690 | ||
![]() |
6053917626 | ||
![]() |
976895c57e | ||
![]() |
5359fc6955 | ||
![]() |
72b9c8ff89 | ||
![]() |
669089c5f2 | ||
![]() |
1a398d9faa | ||
![]() |
c6a35733b7 | ||
![]() |
7828eebaaa | ||
![]() |
eb736a5118 | ||
![]() |
0907de38db | ||
![]() |
2552799a1d | ||
![]() |
8bd666a25b | ||
![]() |
27c957a43b | ||
![]() |
d64942f0e4 | ||
![]() |
8153b2622b | ||
![]() |
932be2cde1 | ||
![]() |
524feec7b7 | ||
![]() |
355796c5bc | ||
![]() |
1df52fa7e8 | ||
![]() |
b3594ac1d1 | ||
![]() |
f0516beae0 | ||
![]() |
acbd8fce9e | ||
![]() |
3c1c972cb6 | ||
![]() |
7e5636ac37 | ||
![]() |
30137166c6 | ||
![]() |
5a8cfcdf19 | ||
![]() |
903e88caaf | ||
![]() |
fa5ad2e6f9 | ||
![]() |
66daafe3ba | ||
![]() |
ef4542dc13 | ||
![]() |
bbff53fe3b | ||
![]() |
2a04f70373 | ||
![]() |
40d36a6673 | ||
![]() |
5cf9a54016 | ||
![]() |
aad7a37705 | ||
![]() |
bdde2ecd27 | ||
![]() |
df75e09956 | ||
![]() |
122f2260b3 | ||
![]() |
9a0bdd0c84 | ||
![]() |
264d0be1fd | ||
![]() |
8b99a7f7d8 | ||
![]() |
d4c46e0ff1 | ||
![]() |
33f1722f2b | ||
![]() |
c3e31cbf36 | ||
![]() |
767b5fc418 | ||
![]() |
8b952d4fcd | ||
![]() |
042f0c3ea2 | ||
![]() |
e307ba7d46 | ||
![]() |
f58c14090f | ||
![]() |
dc1c7db05e | ||
![]() |
6bc02dede8 | ||
![]() |
4e3353057a | ||
![]() |
7919530308 | ||
![]() |
f5dfd99139 | ||
![]() |
674e0199b2 | ||
![]() |
bdb3c42bca | ||
![]() |
e41dbb507c | ||
![]() |
f692289ed4 | ||
![]() |
eeab500a65 | ||
![]() |
bf40e07f6f | ||
![]() |
80078ab088 | ||
![]() |
24dde46b8d | ||
![]() |
66fa925353 | ||
![]() |
2868f26131 | ||
![]() |
ee016a7bb0 | ||
![]() |
edc9914392 | ||
![]() |
91767d093b | ||
![]() |
33caae8069 | ||
![]() |
45ba2b203c | ||
![]() |
8e90259da8 | ||
![]() |
30b9e7ee14 | ||
![]() |
f64dfcd2b5 | ||
![]() |
73ab11dfb0 | ||
![]() |
ed88a63b90 | ||
![]() |
c6a092cd80 | ||
![]() |
e8e9ed3790 | ||
![]() |
d56049e299 | ||
![]() |
c631a7da27 | ||
![]() |
57d3aa3b0d | ||
![]() |
641d2e9f38 | ||
![]() |
b51ddffcc0 | ||
![]() |
548e4b4b28 | ||
![]() |
60c358e677 | ||
![]() |
51951d9e9a | ||
![]() |
1fe8dc9955 | ||
![]() |
506144f398 | ||
![]() |
568ea49490 | ||
![]() |
e9d08bd99c | ||
![]() |
4b28afc98b | ||
![]() |
908be1b85c | ||
![]() |
5ccebf0a7e | ||
![]() |
37558dccbe | ||
![]() |
7c964e279c | ||
![]() |
c9917b6108 | ||
![]() |
73623a0aca | ||
![]() |
8a40306371 | ||
![]() |
07673fc063 | ||
![]() |
b1ae6ef33b | ||
![]() |
c88e039ec2 | ||
![]() |
40f16a81d3 | ||
![]() |
1364d5adb2 | ||
![]() |
17b3776c81 | ||
![]() |
bc06ff65bf | ||
![]() |
5a75f5309c | ||
![]() |
67b2a40892 | ||
![]() |
2491242282 | ||
![]() |
c10095132a | ||
![]() |
31b82e0d50 | ||
![]() |
81adc62f45 | ||
![]() |
30ea8069f4 | ||
![]() |
4f2be40102 | ||
![]() |
6861ee996c | ||
![]() |
99d09b601e | ||
![]() |
745aaecc64 | ||
![]() |
aafcc90a87 | ||
![]() |
321293c644 | ||
![]() |
65c2190b47 | ||
![]() |
29285aead0 | ||
![]() |
c43903c4ea | ||
![]() |
5a41a3884f | ||
![]() |
eab48c33a1 | ||
![]() |
4e0572f57b | ||
![]() |
0ee3a86fed | ||
![]() |
e3bf1afcc5 | ||
![]() |
aa5dafcb5b | ||
![]() |
b224ddb41f | ||
![]() |
680bea02bf | ||
![]() |
09b34d8cca | ||
![]() |
642f3de9b9 | ||
![]() |
66b0e23a0c | ||
![]() |
199189bd1c | ||
![]() |
84d15f4f52 | ||
![]() |
8050081f68 | ||
![]() |
c8ea836ee3 | ||
![]() |
c45992cc2b | ||
![]() |
33bf917460 | ||
![]() |
dea0922f86 | ||
![]() |
230278dcf1 | ||
![]() |
b666760bfa | ||
![]() |
c10e3fe5f9 | ||
![]() |
2f40a99c9e | ||
![]() |
fefa548803 | ||
![]() |
a990309fa3 | ||
![]() |
7aaeeab9e7 | ||
![]() |
787296ae92 | ||
![]() |
9c4eb3521e | ||
![]() |
b1818ee244 | ||
![]() |
8ecbe6d3fb | ||
![]() |
ce2a834c98 | ||
![]() |
da5594bf85 | ||
![]() |
001106d19b | ||
![]() |
59a08cd7d6 | ||
![]() |
3e2f573e70 | ||
![]() |
20646e0184 | ||
![]() |
44f736c96e | ||
![]() |
1ac14f10f6 | ||
![]() |
22dbdb3d60 | ||
![]() |
aace1e145d | ||
![]() |
9e0ba09076 | ||
![]() |
9e397e3960 | ||
![]() |
6997552ea2 | ||
![]() |
8020df8733 | ||
![]() |
cb7e7c3325 | ||
![]() |
6957ae0e91 | ||
![]() |
f14595a7cf | ||
![]() |
65638f8d6b | ||
![]() |
6509127ad6 | ||
![]() |
440fa818fb | ||
![]() |
6b5188ca14 | ||
![]() |
d5d12a91d1 | ||
![]() |
0412460baf | ||
![]() |
391ec85875 | ||
![]() |
b848d8763a | ||
![]() |
ca7810aecd | ||
![]() |
a8ee82cd8c | ||
![]() |
9a2eeb4aae | ||
![]() |
fabbc00668 | ||
![]() |
91c8a7d5ce | ||
![]() |
8509e46ca6 | ||
![]() |
34da6638ad | ||
![]() |
7a3354ac15 | ||
![]() |
8b1617d13a | ||
![]() |
684090272a | ||
![]() |
0021b43737 | ||
![]() |
64e8b9f72e | ||
![]() |
506928a1be | ||
![]() |
cb568b9b29 | ||
![]() |
7b087781c2 | ||
![]() |
c2be21432c | ||
![]() |
8b00be6927 | ||
![]() |
ed8b8f5254 | ||
![]() |
e1a0cb062a | ||
![]() |
e9775120f5 | ||
![]() |
4640d041d3 | ||
![]() |
d3fcff77a1 | ||
![]() |
6cd4b9b223 | ||
![]() |
a36d455182 | ||
![]() |
cfbabb9ec6 | ||
![]() |
ad2ac29263 | ||
![]() |
1f6866e015 | ||
![]() |
5daa0ef087 | ||
![]() |
e9bc7f1757 | ||
![]() |
cc54184619 | ||
![]() |
f8eec91de8 | ||
![]() |
fc82e84329 | ||
![]() |
74e20293c4 | ||
![]() |
49b0e355e6 | ||
![]() |
ba32021683 | ||
![]() |
9a740f5c46 | ||
![]() |
1b0d71bb9f | ||
![]() |
8e63716c1c | ||
![]() |
14f5c4cb4d | ||
![]() |
7b29264f11 | ||
![]() |
8e9966c1a7 | ||
![]() |
21ba418f1a | ||
![]() |
85cf56c159 | ||
![]() |
22f38ee6c6 | ||
![]() |
56bed1a0fe | ||
![]() |
9d54f431e8 | ||
![]() |
51acd4956a | ||
![]() |
0fee0bf826 | ||
![]() |
d682a0afa1 | ||
![]() |
c8683c57f6 | ||
![]() |
ce7c490719 | ||
![]() |
6f3258e671 | ||
![]() |
127a3f2ab4 | ||
![]() |
8234fc1bdf | ||
![]() |
ef9f02e7fb | ||
![]() |
88f58a3694 | ||
![]() |
9899b59beb | ||
![]() |
bd7ef41398 | ||
![]() |
dcdaf30274 | ||
![]() |
60b78fee92 | ||
![]() |
11d14ae7f2 | ||
![]() |
98aa12738d | ||
![]() |
b6e520b2a8 | ||
![]() |
2f63f2465c | ||
![]() |
4f2acb53e2 | ||
![]() |
c316fa38c2 | ||
![]() |
e54cb3298b | ||
![]() |
3f3d401d2d | ||
![]() |
7105c189f6 | ||
![]() |
7f09fba86e | ||
![]() |
49372f2691 | ||
![]() |
8ce486a781 | ||
![]() |
46e744ab67 | ||
![]() |
37a0d83b6d | ||
![]() |
19664f6757 | ||
![]() |
d32b0a92db | ||
![]() |
5019fd124b | ||
![]() |
ee69f8eeb3 | ||
![]() |
d10c1f4acd | ||
![]() |
c9b388d578 | ||
![]() |
e238459fab | ||
![]() |
1664d0efce | ||
![]() |
a90cf6b186 | ||
![]() |
622cc5f014 | ||
![]() |
cbaa9b0333 | ||
![]() |
adf44b51ba | ||
![]() |
111afc1230 | ||
![]() |
a69eb6cc65 | ||
![]() |
5a0ca098f1 | ||
![]() |
1c4ce74f51 | ||
![]() |
1fbe7778c9 | ||
![]() |
9529e360df | ||
![]() |
a6a85579b6 | ||
![]() |
0723bab8fe | ||
![]() |
eccb9df5cf | ||
![]() |
bc317a378f | ||
![]() |
d514a8f0dc | ||
![]() |
68d7b85ec7 | ||
![]() |
5616aa4f4a | ||
![]() |
b126ce4a8f | ||
![]() |
0b1cf2f645 | ||
![]() |
76af9d40da | ||
![]() |
013dbb3a60 | ||
![]() |
3e76a607b5 | ||
![]() |
2adc94b466 | ||
![]() |
26bbff5f76 | ||
![]() |
de80e9337d | ||
![]() |
662e631cce | ||
![]() |
422f0e0486 | ||
![]() |
b9edf49b67 | ||
![]() |
f27203525a | ||
![]() |
7198e1d06f | ||
![]() |
7d28d3be50 | ||
![]() |
8e86b23db9 | ||
![]() |
11c0008862 | ||
![]() |
860a376817 | ||
![]() |
83db3af5f9 | ||
![]() |
1545afd342 | ||
![]() |
88b790f129 | ||
![]() |
4e21ccacd1 | ||
![]() |
0374ccf3f1 | ||
![]() |
caa5eeacac | ||
![]() |
994c8cfb29 |
8
.gitignore
vendored
8
.gitignore
vendored
@@ -1,3 +1,10 @@
|
|||||||
|
# ignore anything begin with dot
|
||||||
|
.*
|
||||||
|
|
||||||
|
# exceptions we need even begin with dot
|
||||||
|
!.clang-format
|
||||||
|
!.gitignore
|
||||||
|
|
||||||
# Object files
|
# Object files
|
||||||
*.o
|
*.o
|
||||||
*.a
|
*.a
|
||||||
@@ -9,3 +16,4 @@ install/
|
|||||||
|
|
||||||
# Development friendly files
|
# Development friendly files
|
||||||
tags
|
tags
|
||||||
|
cscope*
|
||||||
|
25
Kconfig
Normal file
25
Kconfig
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
mainmenu "OpenSBI $(OPENSBI_PLATFORM) Configuration"
|
||||||
|
|
||||||
|
config OPENSBI_SRC_DIR
|
||||||
|
string
|
||||||
|
option env="OPENSBI_SRC_DIR"
|
||||||
|
|
||||||
|
config OPENSBI_PLATFORM
|
||||||
|
string
|
||||||
|
option env="OPENSBI_PLATFORM"
|
||||||
|
|
||||||
|
config OPENSBI_PLATFORM_SRC_DIR
|
||||||
|
string
|
||||||
|
option env="OPENSBI_PLATFORM_SRC_DIR"
|
||||||
|
|
||||||
|
menu "Platform Options"
|
||||||
|
source "$(OPENSBI_PLATFORM_SRC_DIR)/Kconfig"
|
||||||
|
endmenu
|
||||||
|
|
||||||
|
source "$(OPENSBI_SRC_DIR)/lib/sbi/Kconfig"
|
||||||
|
|
||||||
|
source "$(OPENSBI_SRC_DIR)/lib/utils/Kconfig"
|
||||||
|
|
||||||
|
source "$(OPENSBI_SRC_DIR)/firmware/Kconfig"
|
171
Makefile
171
Makefile
@@ -47,11 +47,14 @@ ifdef PLATFORM_DIR
|
|||||||
platform_parent_dir=$(platform_dir_path)
|
platform_parent_dir=$(platform_dir_path)
|
||||||
else
|
else
|
||||||
PLATFORM=$(shell basename $(platform_dir_path))
|
PLATFORM=$(shell basename $(platform_dir_path))
|
||||||
platform_parent_dir=$(subst $(PLATFORM),,$(platform_dir_path))
|
platform_parent_dir=$(shell realpath ${platform_dir_path}/..)
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
platform_parent_dir=$(src_dir)/platform
|
platform_parent_dir=$(src_dir)/platform
|
||||||
endif
|
endif
|
||||||
|
ifndef PLATFORM_DEFCONFIG
|
||||||
|
PLATFORM_DEFCONFIG=defconfig
|
||||||
|
endif
|
||||||
|
|
||||||
# Check if verbosity is ON for build process
|
# Check if verbosity is ON for build process
|
||||||
CMD_PREFIX_DEFAULT := @
|
CMD_PREFIX_DEFAULT := @
|
||||||
@@ -70,6 +73,20 @@ export libsbi_dir=$(CURDIR)/lib/sbi
|
|||||||
export libsbiutils_dir=$(CURDIR)/lib/utils
|
export libsbiutils_dir=$(CURDIR)/lib/utils
|
||||||
export firmware_dir=$(CURDIR)/firmware
|
export firmware_dir=$(CURDIR)/firmware
|
||||||
|
|
||||||
|
# Setup variables for kconfig
|
||||||
|
ifdef PLATFORM
|
||||||
|
export PYTHONDONTWRITEBYTECODE=1
|
||||||
|
export KCONFIG_DIR=$(platform_build_dir)/kconfig
|
||||||
|
export KCONFIG_AUTOLIST=$(KCONFIG_DIR)/auto.list
|
||||||
|
export KCONFIG_AUTOHEADER=$(KCONFIG_DIR)/autoconf.h
|
||||||
|
export KCONFIG_AUTOCMD=$(KCONFIG_DIR)/auto.conf.cmd
|
||||||
|
export KCONFIG_CONFIG=$(KCONFIG_DIR)/.config
|
||||||
|
# Additional exports for include paths in Kconfig files
|
||||||
|
export OPENSBI_SRC_DIR=$(src_dir)
|
||||||
|
export OPENSBI_PLATFORM=$(PLATFORM)
|
||||||
|
export OPENSBI_PLATFORM_SRC_DIR=$(platform_src_dir)
|
||||||
|
endif
|
||||||
|
|
||||||
# Find library version
|
# Find library version
|
||||||
OPENSBI_VERSION_MAJOR=`grep "define OPENSBI_VERSION_MAJOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MAJOR.*\([0-9][0-9]*\)/\1/'`
|
OPENSBI_VERSION_MAJOR=`grep "define OPENSBI_VERSION_MAJOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MAJOR.*\([0-9][0-9]*\)/\1/'`
|
||||||
OPENSBI_VERSION_MINOR=`grep "define OPENSBI_VERSION_MINOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MINOR.*\([0-9][0-9]*\)/\1/'`
|
OPENSBI_VERSION_MINOR=`grep "define OPENSBI_VERSION_MINOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MINOR.*\([0-9][0-9]*\)/\1/'`
|
||||||
@@ -151,7 +168,7 @@ endif
|
|||||||
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)
|
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
|
# 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)
|
CC_SUPPORT_SAVE_RESTORE := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -mno-save-restore -x c /dev/null -o /dev/null 2>&1 | grep -e "-save-restore" >/dev/null && echo n || echo y)
|
||||||
|
|
||||||
# Check whether the assembler and the compiler support the Zicsr and Zifencei extensions
|
# Check whether the assembler and the compiler support the Zicsr and Zifencei extensions
|
||||||
CC_SUPPORT_ZICSR_ZIFENCEI := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -march=rv$(OPENSBI_CC_XLEN)imafd_zicsr_zifencei -x c /dev/null -o /dev/null 2>&1 | grep "zicsr\|zifencei" > /dev/null && echo n || echo y)
|
CC_SUPPORT_ZICSR_ZIFENCEI := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -march=rv$(OPENSBI_CC_XLEN)imafd_zicsr_zifencei -x c /dev/null -o /dev/null 2>&1 | grep "zicsr\|zifencei" > /dev/null && echo n || echo y)
|
||||||
@@ -183,12 +200,38 @@ libsbi-object-mks=$(shell if [ -d $(libsbi_dir) ]; then find $(libsbi_dir) -inam
|
|||||||
libsbiutils-object-mks=$(shell if [ -d $(libsbiutils_dir) ]; then find $(libsbiutils_dir) -iname "objects.mk" | sort -r; fi)
|
libsbiutils-object-mks=$(shell if [ -d $(libsbiutils_dir) ]; then find $(libsbiutils_dir) -iname "objects.mk" | sort -r; fi)
|
||||||
firmware-object-mks=$(shell if [ -d $(firmware_dir) ]; then find $(firmware_dir) -iname "objects.mk" | sort -r; fi)
|
firmware-object-mks=$(shell if [ -d $(firmware_dir) ]; then find $(firmware_dir) -iname "objects.mk" | sort -r; fi)
|
||||||
|
|
||||||
# Include platform specifig config.mk
|
# The "make all" rule should always be first rule
|
||||||
|
.PHONY: all
|
||||||
|
all:
|
||||||
|
|
||||||
|
# Include platform specific .config
|
||||||
ifdef PLATFORM
|
ifdef PLATFORM
|
||||||
include $(platform_src_dir)/config.mk
|
.PHONY: menuconfig
|
||||||
|
menuconfig: $(platform_src_dir)/Kconfig $(src_dir)/Kconfig
|
||||||
|
$(CMD_PREFIX)mkdir -p $(KCONFIG_DIR)
|
||||||
|
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/menuconfig.py $(src_dir)/Kconfig
|
||||||
|
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/genconfig.py --header-path $(KCONFIG_AUTOHEADER) --sync-deps $(KCONFIG_DIR) --file-list $(KCONFIG_AUTOLIST) $(src_dir)/Kconfig
|
||||||
|
|
||||||
|
.PHONY: savedefconfig
|
||||||
|
savedefconfig: $(platform_src_dir)/Kconfig $(src_dir)/Kconfig
|
||||||
|
$(CMD_PREFIX)mkdir -p $(KCONFIG_DIR)
|
||||||
|
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/savedefconfig.py --kconfig $(src_dir)/Kconfig --out $(KCONFIG_DIR)/defconfig
|
||||||
|
|
||||||
|
$(KCONFIG_CONFIG): $(platform_src_dir)/configs/$(PLATFORM_DEFCONFIG) $(platform_src_dir)/Kconfig $(src_dir)/Kconfig
|
||||||
|
$(CMD_PREFIX)mkdir -p $(KCONFIG_DIR)
|
||||||
|
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/defconfig.py --kconfig $(src_dir)/Kconfig $(platform_src_dir)/configs/$(PLATFORM_DEFCONFIG)
|
||||||
|
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/genconfig.py --header-path $(KCONFIG_AUTOHEADER) --sync-deps $(KCONFIG_DIR) --file-list $(KCONFIG_AUTOLIST) $(src_dir)/Kconfig
|
||||||
|
|
||||||
|
$(KCONFIG_AUTOCMD): $(KCONFIG_CONFIG)
|
||||||
|
$(CMD_PREFIX)mkdir -p $(KCONFIG_DIR)
|
||||||
|
$(CMD_PREFIX)printf "%s: " $(KCONFIG_CONFIG) > $(KCONFIG_AUTOCMD)
|
||||||
|
$(CMD_PREFIX)cat $(KCONFIG_AUTOLIST) | tr '\n' ' ' >> $(KCONFIG_AUTOCMD)
|
||||||
|
|
||||||
|
include $(KCONFIG_CONFIG)
|
||||||
|
include $(KCONFIG_AUTOCMD)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Include all object.mk files
|
# Include all objects.mk files
|
||||||
ifdef PLATFORM
|
ifdef PLATFORM
|
||||||
include $(platform-object-mks)
|
include $(platform-object-mks)
|
||||||
endif
|
endif
|
||||||
@@ -198,8 +241,8 @@ include $(firmware-object-mks)
|
|||||||
|
|
||||||
# Setup list of objects
|
# Setup list of objects
|
||||||
libsbi-objs-path-y=$(foreach obj,$(libsbi-objs-y),$(build_dir)/lib/sbi/$(obj))
|
libsbi-objs-path-y=$(foreach obj,$(libsbi-objs-y),$(build_dir)/lib/sbi/$(obj))
|
||||||
libsbiutils-objs-path-y=$(foreach obj,$(libsbiutils-objs-y),$(build_dir)/lib/utils/$(obj))
|
|
||||||
ifdef PLATFORM
|
ifdef PLATFORM
|
||||||
|
libsbiutils-objs-path-y=$(foreach obj,$(libsbiutils-objs-y),$(platform_build_dir)/lib/utils/$(obj))
|
||||||
platform-objs-path-y=$(foreach obj,$(platform-objs-y),$(platform_build_dir)/$(obj))
|
platform-objs-path-y=$(foreach obj,$(platform-objs-y),$(platform_build_dir)/$(obj))
|
||||||
firmware-bins-path-y=$(foreach bin,$(firmware-bins-y),$(platform_build_dir)/firmware/$(bin))
|
firmware-bins-path-y=$(foreach bin,$(firmware-bins-y),$(platform_build_dir)/firmware/$(bin))
|
||||||
endif
|
endif
|
||||||
@@ -211,6 +254,7 @@ deps-y=$(platform-objs-path-y:.o=.dep)
|
|||||||
deps-y+=$(libsbi-objs-path-y:.o=.dep)
|
deps-y+=$(libsbi-objs-path-y:.o=.dep)
|
||||||
deps-y+=$(libsbiutils-objs-path-y:.o=.dep)
|
deps-y+=$(libsbiutils-objs-path-y:.o=.dep)
|
||||||
deps-y+=$(firmware-objs-path-y:.o=.dep)
|
deps-y+=$(firmware-objs-path-y:.o=.dep)
|
||||||
|
deps-y+=$(firmware-elfs-path-y:=.dep)
|
||||||
|
|
||||||
# Setup platform ABI, ISA and Code Model
|
# Setup platform ABI, ISA and Code Model
|
||||||
ifndef PLATFORM_RISCV_ABI
|
ifndef PLATFORM_RISCV_ABI
|
||||||
@@ -280,11 +324,19 @@ ifeq ($(BUILD_INFO),y)
|
|||||||
GENFLAGS += -DOPENSBI_BUILD_TIME_STAMP="\"$(OPENSBI_BUILD_TIME_STAMP)\""
|
GENFLAGS += -DOPENSBI_BUILD_TIME_STAMP="\"$(OPENSBI_BUILD_TIME_STAMP)\""
|
||||||
GENFLAGS += -DOPENSBI_BUILD_COMPILER_VERSION="\"$(OPENSBI_BUILD_COMPILER_VERSION)\""
|
GENFLAGS += -DOPENSBI_BUILD_COMPILER_VERSION="\"$(OPENSBI_BUILD_COMPILER_VERSION)\""
|
||||||
endif
|
endif
|
||||||
|
ifdef PLATFORM
|
||||||
|
GENFLAGS += -include $(KCONFIG_AUTOHEADER)
|
||||||
|
endif
|
||||||
GENFLAGS += $(libsbiutils-genflags-y)
|
GENFLAGS += $(libsbiutils-genflags-y)
|
||||||
GENFLAGS += $(platform-genflags-y)
|
GENFLAGS += $(platform-genflags-y)
|
||||||
GENFLAGS += $(firmware-genflags-y)
|
GENFLAGS += $(firmware-genflags-y)
|
||||||
|
|
||||||
CFLAGS = -g -Wall -Werror -ffreestanding -nostdlib -fno-stack-protector -fno-strict-aliasing -O2
|
CFLAGS = -g -Wall -Werror -ffreestanding -nostdlib -fno-stack-protector -fno-strict-aliasing
|
||||||
|
ifneq ($(DEBUG),)
|
||||||
|
CFLAGS += -O0
|
||||||
|
else
|
||||||
|
CFLAGS += -O2
|
||||||
|
endif
|
||||||
CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls -mstrict-align
|
CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls -mstrict-align
|
||||||
# enable -m(no-)save-restore option by CC_SUPPORT_SAVE_RESTORE
|
# enable -m(no-)save-restore option by CC_SUPPORT_SAVE_RESTORE
|
||||||
ifeq ($(CC_SUPPORT_SAVE_RESTORE),y)
|
ifeq ($(CC_SUPPORT_SAVE_RESTORE),y)
|
||||||
@@ -323,7 +375,8 @@ ASFLAGS += $(firmware-asflags-y)
|
|||||||
ARFLAGS = rcs
|
ARFLAGS = rcs
|
||||||
|
|
||||||
ELFFLAGS += $(USE_LD_FLAG)
|
ELFFLAGS += $(USE_LD_FLAG)
|
||||||
ELFFLAGS += -Wl,--build-id=none -Wl,-N
|
ELFFLAGS += -Wl,--exclude-libs,ALL
|
||||||
|
ELFFLAGS += -Wl,--build-id=none
|
||||||
ELFFLAGS += $(platform-ldflags-y)
|
ELFFLAGS += $(platform-ldflags-y)
|
||||||
ELFFLAGS += $(firmware-ldflags-y)
|
ELFFLAGS += $(firmware-ldflags-y)
|
||||||
|
|
||||||
@@ -349,10 +402,10 @@ merge_deps = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
|||||||
cat $(2) > $(1)
|
cat $(2) > $(1)
|
||||||
copy_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
copy_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
||||||
echo " COPY $(subst $(build_dir)/,,$(1))"; \
|
echo " COPY $(subst $(build_dir)/,,$(1))"; \
|
||||||
cp -f $(2) $(1)
|
cp -L -f $(2) $(1)
|
||||||
inst_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
inst_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
||||||
echo " INSTALL $(subst $(install_root_dir)/,,$(1))"; \
|
echo " INSTALL $(subst $(install_root_dir)/,,$(1))"; \
|
||||||
cp -f $(2) $(1)
|
cp -L -f $(2) $(1)
|
||||||
inst_file_list = $(CMD_PREFIX)if [ ! -z "$(4)" ]; then \
|
inst_file_list = $(CMD_PREFIX)if [ ! -z "$(4)" ]; then \
|
||||||
mkdir -p $(1)/$(3); \
|
mkdir -p $(1)/$(3); \
|
||||||
for file in $(4) ; do \
|
for file in $(4) ; do \
|
||||||
@@ -361,12 +414,17 @@ inst_file_list = $(CMD_PREFIX)if [ ! -z "$(4)" ]; then \
|
|||||||
dest_dir=`dirname $$dest_file`; \
|
dest_dir=`dirname $$dest_file`; \
|
||||||
echo " INSTALL "$(3)"/"`echo $$rel_file`; \
|
echo " INSTALL "$(3)"/"`echo $$rel_file`; \
|
||||||
mkdir -p $$dest_dir; \
|
mkdir -p $$dest_dir; \
|
||||||
cp -f $$file $$dest_file; \
|
cp -L -f $$file $$dest_file; \
|
||||||
done \
|
done \
|
||||||
fi
|
fi
|
||||||
inst_header_dir = $(CMD_PREFIX)mkdir -p $(1); \
|
inst_header_dir = $(CMD_PREFIX)mkdir -p $(1); \
|
||||||
echo " INSTALL $(subst $(install_root_dir)/,,$(1))"; \
|
echo " INSTALL $(subst $(install_root_dir)/,,$(1))"; \
|
||||||
cp -rf $(2) $(1)
|
cp -L -rf $(2) $(1)
|
||||||
|
compile_cpp_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
||||||
|
echo " CPP-DEP $(subst $(build_dir)/,,$(1))"; \
|
||||||
|
printf %s `dirname $(1)`/ > $(1) && \
|
||||||
|
$(CC) $(CPPFLAGS) -x c -MM $(3) \
|
||||||
|
-MT `basename $(1:.dep=$(2))` >> $(1) || rm -f $(1)
|
||||||
compile_cpp = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
compile_cpp = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
||||||
echo " CPP $(subst $(build_dir)/,,$(1))"; \
|
echo " CPP $(subst $(build_dir)/,,$(1))"; \
|
||||||
$(CPP) $(CPPFLAGS) -x c $(2) | grep -v "\#" > $(1)
|
$(CPP) $(CPPFLAGS) -x c $(2) | grep -v "\#" > $(1)
|
||||||
@@ -413,29 +471,33 @@ compile_gen_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
|||||||
echo "$(1:.dep=$(2)): $(3)" >> $(1)
|
echo "$(1:.dep=$(2)): $(3)" >> $(1)
|
||||||
|
|
||||||
targets-y = $(build_dir)/lib/libsbi.a
|
targets-y = $(build_dir)/lib/libsbi.a
|
||||||
targets-y += $(build_dir)/lib/libsbiutils.a
|
|
||||||
ifdef PLATFORM
|
ifdef PLATFORM
|
||||||
targets-y += $(platform_build_dir)/lib/libplatsbi.a
|
targets-y += $(platform_build_dir)/lib/libplatsbi.a
|
||||||
endif
|
endif
|
||||||
targets-y += $(firmware-bins-path-y)
|
targets-y += $(firmware-bins-path-y)
|
||||||
|
|
||||||
# Default rule "make" should always be first rule
|
# The default "make all" rule
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: $(targets-y)
|
all: $(targets-y)
|
||||||
|
|
||||||
# Preserve all intermediate files
|
# Preserve all intermediate files
|
||||||
.SECONDARY:
|
.SECONDARY:
|
||||||
|
|
||||||
|
# Rules for lib/sbi sources
|
||||||
$(build_dir)/lib/libsbi.a: $(libsbi-objs-path-y)
|
$(build_dir)/lib/libsbi.a: $(libsbi-objs-path-y)
|
||||||
$(call compile_ar,$@,$^)
|
$(call compile_ar,$@,$^)
|
||||||
|
|
||||||
$(build_dir)/lib/libsbiutils.a: $(libsbi-objs-path-y) $(libsbiutils-objs-path-y)
|
|
||||||
$(call compile_ar,$@,$^)
|
|
||||||
|
|
||||||
$(platform_build_dir)/lib/libplatsbi.a: $(libsbi-objs-path-y) $(libsbiutils-objs-path-y) $(platform-objs-path-y)
|
$(platform_build_dir)/lib/libplatsbi.a: $(libsbi-objs-path-y) $(libsbiutils-objs-path-y) $(platform-objs-path-y)
|
||||||
$(call compile_ar,$@,$^)
|
$(call compile_ar,$@,$^)
|
||||||
|
|
||||||
$(build_dir)/%.dep: $(src_dir)/%.c
|
$(build_dir)/%.dep: $(src_dir)/%.carray $(KCONFIG_CONFIG)
|
||||||
|
$(call compile_gen_dep,$@,.c,$< $(KCONFIG_CONFIG))
|
||||||
|
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
|
||||||
|
|
||||||
|
$(build_dir)/%.c: $(src_dir)/%.carray
|
||||||
|
$(call compile_carray,$@,$<)
|
||||||
|
|
||||||
|
$(build_dir)/%.dep: $(src_dir)/%.c $(KCONFIG_CONFIG)
|
||||||
$(call compile_cc_dep,$@,$<)
|
$(call compile_cc_dep,$@,$<)
|
||||||
|
|
||||||
$(build_dir)/%.o: $(src_dir)/%.c
|
$(build_dir)/%.o: $(src_dir)/%.c
|
||||||
@@ -449,32 +511,24 @@ $(build_dir)/lib/sbi/sbi_init.o: $(libsbi_dir)/sbi_init.c FORCE
|
|||||||
$(call compile_cc,$@,$<)
|
$(call compile_cc,$@,$<)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
$(build_dir)/%.dep: $(src_dir)/%.S
|
$(build_dir)/%.dep: $(src_dir)/%.S $(KCONFIG_CONFIG)
|
||||||
$(call compile_as_dep,$@,$<)
|
$(call compile_as_dep,$@,$<)
|
||||||
|
|
||||||
$(build_dir)/%.o: $(src_dir)/%.S
|
$(build_dir)/%.o: $(src_dir)/%.S
|
||||||
$(call compile_as,$@,$<)
|
$(call compile_as,$@,$<)
|
||||||
|
|
||||||
$(build_dir)/%.dep: $(src_dir)/%.carray
|
# Rules for platform sources
|
||||||
$(call compile_gen_dep,$@,.c,$<)
|
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.carray $(KCONFIG_CONFIG)
|
||||||
|
$(call compile_gen_dep,$@,.c,$< $(KCONFIG_CONFIG))
|
||||||
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
|
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
|
||||||
|
|
||||||
$(build_dir)/%.c: $(src_dir)/%.carray
|
$(platform_build_dir)/%.c: $(platform_src_dir)/%.carray
|
||||||
$(call compile_carray,$@,$<)
|
$(call compile_carray,$@,$<)
|
||||||
|
|
||||||
$(platform_build_dir)/%.bin: $(platform_build_dir)/%.elf
|
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.c $(KCONFIG_CONFIG)
|
||||||
$(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,$@,$<)
|
$(call compile_cc_dep,$@,$<)
|
||||||
|
|
||||||
$(platform_build_dir)/%.o: $(platform_src_dir)/%.c
|
$(platform_build_dir)/%.o: $(platform_src_dir)/%.c $(KCONFIG_CONFIG)
|
||||||
$(call compile_cc,$@,$<)
|
$(call compile_cc,$@,$<)
|
||||||
|
|
||||||
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.S
|
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.S
|
||||||
@@ -483,8 +537,8 @@ $(platform_build_dir)/%.dep: $(platform_src_dir)/%.S
|
|||||||
$(platform_build_dir)/%.o: $(platform_src_dir)/%.S
|
$(platform_build_dir)/%.o: $(platform_src_dir)/%.S
|
||||||
$(call compile_as,$@,$<)
|
$(call compile_as,$@,$<)
|
||||||
|
|
||||||
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.dts
|
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.dts $(KCONFIG_CONFIG)
|
||||||
$(call compile_gen_dep,$@,.dtb,$<)
|
$(call compile_gen_dep,$@,.dtb,$< $(KCONFIG_CONFIG))
|
||||||
$(call compile_gen_dep,$@,.c,$(@:.dep=.dtb))
|
$(call compile_gen_dep,$@,.c,$(@:.dep=.dtb))
|
||||||
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
|
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
|
||||||
|
|
||||||
@@ -494,13 +548,33 @@ $(platform_build_dir)/%.c: $(platform_build_dir)/%.dtb
|
|||||||
$(platform_build_dir)/%.dtb: $(platform_src_dir)/%.dts
|
$(platform_build_dir)/%.dtb: $(platform_src_dir)/%.dts
|
||||||
$(call compile_dts,$@,$<)
|
$(call compile_dts,$@,$<)
|
||||||
|
|
||||||
$(platform_build_dir)/%.dep: $(src_dir)/%.c
|
# Rules for lib/utils and firmware sources
|
||||||
|
$(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)/%.dep: $(src_dir)/%.ldS $(KCONFIG_CONFIG)
|
||||||
|
$(call compile_cpp_dep,$@,.ld,$<)
|
||||||
|
|
||||||
|
$(platform_build_dir)/%.ld: $(src_dir)/%.ldS
|
||||||
|
$(call compile_cpp,$@,$<)
|
||||||
|
|
||||||
|
$(platform_build_dir)/%.dep: $(src_dir)/%.carray $(KCONFIG_CONFIG)
|
||||||
|
$(call compile_gen_dep,$@,.c,$< $(KCONFIG_CONFIG))
|
||||||
|
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
|
||||||
|
|
||||||
|
$(platform_build_dir)/%.c: $(src_dir)/%.carray
|
||||||
|
$(call compile_carray,$@,$<)
|
||||||
|
|
||||||
|
$(platform_build_dir)/%.dep: $(src_dir)/%.c $(KCONFIG_CONFIG)
|
||||||
$(call compile_cc_dep,$@,$<)
|
$(call compile_cc_dep,$@,$<)
|
||||||
|
|
||||||
$(platform_build_dir)/%.o: $(src_dir)/%.c
|
$(platform_build_dir)/%.o: $(src_dir)/%.c
|
||||||
$(call compile_cc,$@,$<)
|
$(call compile_cc,$@,$<)
|
||||||
|
|
||||||
$(platform_build_dir)/%.dep: $(src_dir)/%.S
|
$(platform_build_dir)/%.dep: $(src_dir)/%.S $(KCONFIG_CONFIG)
|
||||||
$(call compile_as_dep,$@,$<)
|
$(call compile_as_dep,$@,$<)
|
||||||
|
|
||||||
$(platform_build_dir)/%.o: $(src_dir)/%.S
|
$(platform_build_dir)/%.o: $(src_dir)/%.S
|
||||||
@@ -544,7 +618,6 @@ endif
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
install_targets-y = install_libsbi
|
install_targets-y = install_libsbi
|
||||||
install_targets-y += install_libsbiutils
|
|
||||||
ifdef PLATFORM
|
ifdef PLATFORM
|
||||||
install_targets-y += install_libplatsbi
|
install_targets-y += install_libplatsbi
|
||||||
install_targets-y += install_firmwares
|
install_targets-y += install_firmwares
|
||||||
@@ -559,17 +632,12 @@ install_libsbi: $(build_dir)/lib/libsbi.a
|
|||||||
$(call inst_header_dir,$(install_root_dir)/$(install_include_path),$(include_dir)/sbi)
|
$(call inst_header_dir,$(install_root_dir)/$(install_include_path),$(include_dir)/sbi)
|
||||||
$(call inst_file,$(install_root_dir)/$(install_lib_path)/libsbi.a,$(build_dir)/lib/libsbi.a)
|
$(call inst_file,$(install_root_dir)/$(install_lib_path)/libsbi.a,$(build_dir)/lib/libsbi.a)
|
||||||
|
|
||||||
.PHONY: install_libsbiutils
|
|
||||||
install_libsbiutils: $(build_dir)/lib/libsbiutils.a
|
|
||||||
$(call inst_header_dir,$(install_root_dir)/$(install_include_path),$(include_dir)/sbi_utils)
|
|
||||||
$(call inst_file,$(install_root_dir)/$(install_lib_path)/libsbiutils.a,$(build_dir)/lib/libsbiutils.a)
|
|
||||||
|
|
||||||
.PHONY: install_libplatsbi
|
.PHONY: install_libplatsbi
|
||||||
install_libplatsbi: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(build_dir)/lib/libsbiutils.a
|
install_libplatsbi: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a
|
||||||
$(call inst_file,$(install_root_dir)/$(install_lib_path)/opensbi/$(platform_subdir)/lib/libplatsbi.a,$(platform_build_dir)/lib/libplatsbi.a)
|
$(call inst_file,$(install_root_dir)/$(install_lib_path)/opensbi/$(platform_subdir)/lib/libplatsbi.a,$(platform_build_dir)/lib/libplatsbi.a)
|
||||||
|
|
||||||
.PHONY: install_firmwares
|
.PHONY: install_firmwares
|
||||||
install_firmwares: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(build_dir)/lib/libsbiutils.a $(firmware-bins-path-y)
|
install_firmwares: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(firmware-bins-path-y)
|
||||||
$(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-elfs-path-y))
|
$(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-elfs-path-y))
|
||||||
$(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-bins-path-y))
|
$(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-bins-path-y))
|
||||||
|
|
||||||
@@ -577,6 +645,17 @@ install_firmwares: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsb
|
|||||||
install_docs: $(build_dir)/docs/latex/refman.pdf
|
install_docs: $(build_dir)/docs/latex/refman.pdf
|
||||||
$(call inst_file,$(install_root_dir)/$(install_docs_path)/refman.pdf,$(build_dir)/docs/latex/refman.pdf)
|
$(call inst_file,$(install_root_dir)/$(install_docs_path)/refman.pdf,$(build_dir)/docs/latex/refman.pdf)
|
||||||
|
|
||||||
|
.PHONY: cscope
|
||||||
|
cscope:
|
||||||
|
$(CMD_PREFIX)find \
|
||||||
|
"$(src_dir)/firmware" \
|
||||||
|
"$(src_dir)/include" \
|
||||||
|
"$(src_dir)/lib" \
|
||||||
|
"$(platform_src_dir)" \
|
||||||
|
-name "*.[chS]" -print > cscope.files
|
||||||
|
$(CMD_PREFIX)echo "$(KCONFIG_AUTOHEADER)" >> cscope.files
|
||||||
|
$(CMD_PREFIX)cscope -bkq -i cscope.files -f cscope.out
|
||||||
|
|
||||||
# Rule for "make clean"
|
# Rule for "make clean"
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
@@ -606,6 +685,8 @@ ifeq ($(install_root_dir),$(install_root_dir_default)/usr)
|
|||||||
$(if $(V), @echo " RM $(install_root_dir_default)")
|
$(if $(V), @echo " RM $(install_root_dir_default)")
|
||||||
$(CMD_PREFIX)rm -rf $(install_root_dir_default)
|
$(CMD_PREFIX)rm -rf $(install_root_dir_default)
|
||||||
endif
|
endif
|
||||||
|
$(if $(V), @echo " RM $(src_dir)/cscope*")
|
||||||
|
$(CMD_PREFIX)rm -f $(src_dir)/cscope*
|
||||||
|
|
||||||
.PHONY: FORCE
|
.PHONY: FORCE
|
||||||
FORCE:
|
FORCE:
|
||||||
|
46
README.md
46
README.md
@@ -1,11 +1,15 @@
|
|||||||
RISC-V Open Source Supervisor Binary Interface (OpenSBI)
|
RISC-V Open Source Supervisor Binary Interface (OpenSBI)
|
||||||
========================================================
|
========================================================
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
Copyright and License
|
Copyright and License
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
The OpenSBI project is copyright (c) 2019 Western Digital Corporation
|
The OpenSBI project is:
|
||||||
or its affiliates and other contributors.
|
|
||||||
|
* Copyright (c) 2019 Western Digital Corporation or its affiliates
|
||||||
|
* Copyright (c) 2023 RISC-V International
|
||||||
|
|
||||||
It is distributed under the terms of the BSD 2-clause license
|
It is distributed under the terms of the BSD 2-clause license
|
||||||
("Simplified BSD License" or "FreeBSD License", SPDX: *BSD-2-Clause*).
|
("Simplified BSD License" or "FreeBSD License", SPDX: *BSD-2-Clause*).
|
||||||
@@ -92,8 +96,8 @@ N.B. Any S-mode boot loader (i.e. U-Boot) doesn't need to support HSM extension,
|
|||||||
as it doesn't need to boot all the harts. The operating system should be
|
as it doesn't need to boot all the harts. The operating system should be
|
||||||
capable enough to bring up all other non-booting harts using HSM extension.
|
capable enough to bring up all other non-booting harts using HSM extension.
|
||||||
|
|
||||||
Required Toolchain
|
Required Toolchain and Packages
|
||||||
------------------
|
-------------------------------
|
||||||
|
|
||||||
OpenSBI can be compiled natively or cross-compiled on a x86 host. For
|
OpenSBI can be compiled natively or cross-compiled on a x86 host. For
|
||||||
cross-compilation, you can build your own toolchain, download a prebuilt one
|
cross-compilation, you can build your own toolchain, download a prebuilt one
|
||||||
@@ -115,6 +119,14 @@ triple is used (e.g. *-target riscv64-unknown-elf*).
|
|||||||
Please note that only a 64-bit version of the toolchain is available in
|
Please note that only a 64-bit version of the toolchain is available in
|
||||||
the Bootlin toolchain repository for now.
|
the Bootlin toolchain repository for now.
|
||||||
|
|
||||||
|
In addition to a toolchain, OpenSBI also requires the following packages on
|
||||||
|
the host:
|
||||||
|
|
||||||
|
1. device-tree-compiler: The device tree compiler for compiling device
|
||||||
|
tree sources (DTS files).
|
||||||
|
2. python3: The python 3.0 (or compatible) language support for various
|
||||||
|
scripts.
|
||||||
|
|
||||||
Building and Installing the OpenSBI Platform-Independent Library
|
Building and Installing the OpenSBI Platform-Independent Library
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
||||||
@@ -196,6 +208,19 @@ top-level make command line. These options, such as *PLATFORM_<xyz>* or
|
|||||||
*docs/platform/<platform_name>.md* files and
|
*docs/platform/<platform_name>.md* files and
|
||||||
*docs/firmware/<firmware_name>.md* files.
|
*docs/firmware/<firmware_name>.md* files.
|
||||||
|
|
||||||
|
All OpenSBI platforms support Kconfig style build-time configuration. Users
|
||||||
|
can change the build-time configuration of a platform using a graphical
|
||||||
|
interface as follows:
|
||||||
|
```
|
||||||
|
make PLATFORM=<platform_subdir> menuconfig
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternately, an OpenSBI platform can have multiple default configurations
|
||||||
|
and users can select a custom default configuration as follows:
|
||||||
|
```
|
||||||
|
make PLATFORM=<platform_subdir> PLATFORM_DEFCONFIG=<platform_custom_defconfig>
|
||||||
|
```
|
||||||
|
|
||||||
Building 32-bit / 64-bit OpenSBI Images
|
Building 32-bit / 64-bit OpenSBI Images
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
By default, building OpenSBI generates 32-bit or 64-bit images based on the
|
By default, building OpenSBI generates 32-bit or 64-bit images based on the
|
||||||
@@ -277,6 +302,19 @@ NOTE: Using `BUILD_INFO=y` without specifying SOURCE_DATE_EPOCH will violate
|
|||||||
purpose, and should NOT be used in a product which follows "reproducible
|
purpose, and should NOT be used in a product which follows "reproducible
|
||||||
builds".
|
builds".
|
||||||
|
|
||||||
|
Building with optimization off for debugging
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
When debugging OpenSBI, we may want to turn off the compiler optimization and
|
||||||
|
make debugging produce the expected results for a better debugging experience.
|
||||||
|
To build with optimization off we can just simply add `DEBUG=1`, like:
|
||||||
|
```
|
||||||
|
make DEBUG=1
|
||||||
|
```
|
||||||
|
|
||||||
|
This definition is ONLY for development and debug purpose, and should NOT be
|
||||||
|
used in a product build.
|
||||||
|
|
||||||
Contributing to OpenSBI
|
Contributing to OpenSBI
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
|
@@ -29,7 +29,7 @@ and "top:".
|
|||||||
5. Maintainers should use "Rebase and Merge" when using GitHub to merge pull
|
5. Maintainers should use "Rebase and Merge" when using GitHub to merge pull
|
||||||
requests to avoid creating unnecessary merge commits.
|
requests to avoid creating unnecessary merge commits.
|
||||||
6. Maintainers should avoid creating branches directly in the main
|
6. Maintainers should avoid creating branches directly in the main
|
||||||
riscv/opensbi repository. Instead prefer using a fork of the riscv/opensbi main
|
riscv/opensbi repository. Instead, prefer using a fork of the riscv/opensbi main
|
||||||
repository and branches within that fork to create pull requests.
|
repository and branches within that fork to create pull requests.
|
||||||
7. A maintainer cannot merge his own pull requests in the riscv/opensbi main
|
7. A maintainer cannot merge his own pull requests in the riscv/opensbi main
|
||||||
repository.
|
repository.
|
||||||
|
@@ -2,7 +2,7 @@ OpenSBI Domain Support
|
|||||||
======================
|
======================
|
||||||
|
|
||||||
An OpenSBI domain is a system-level partition (subset) of underlying hardware
|
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
|
having its own memory regions (RAM and MMIO devices) and HARTs. The OpenSBI
|
||||||
will try to achieve secure isolation between domains using RISC-V platform
|
will try to achieve secure isolation between domains using RISC-V platform
|
||||||
features such as PMP, ePMP, IOPMP, SiFive Shield, etc.
|
features such as PMP, ePMP, IOPMP, SiFive Shield, etc.
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ Important entities which help implement OpenSBI domain support are:
|
|||||||
Each HART of a RISC-V platform must have an OpenSBI domain assigned to it.
|
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
|
The OpenSBI platform support is responsible for populating domains and
|
||||||
providing HART id to domain mapping. The OpenSBI domain support will by
|
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
|
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.
|
it is not mandatory for the OpenSBI platform support to populate domains.
|
||||||
|
|
||||||
Domain Memory Region
|
Domain Memory Region
|
||||||
@@ -29,7 +29,7 @@ OpenSBI and has following details:
|
|||||||
* **base** - The base address of a memory region is **2 ^ order**
|
* **base** - The base address of a memory region is **2 ^ order**
|
||||||
aligned start address
|
aligned start address
|
||||||
* **flags** - The flags of a memory region represent memory type (i.e.
|
* **flags** - The flags of a memory region represent memory type (i.e.
|
||||||
RAM or MMIO) and allowed accesses (i.e. READ, WRITE, EXECUTE, etc)
|
RAM or MMIO) and allowed accesses (i.e. READ, WRITE, EXECUTE, etc.)
|
||||||
|
|
||||||
Domain Instance
|
Domain Instance
|
||||||
---------------
|
---------------
|
||||||
@@ -52,6 +52,7 @@ has following details:
|
|||||||
* **next_mode** - Privilege mode of the next booting stage for this
|
* **next_mode** - Privilege mode of the next booting stage for this
|
||||||
domain. This can be either S-mode or U-mode.
|
domain. This can be either S-mode or U-mode.
|
||||||
* **system_reset_allowed** - Is domain allowed to reset the system?
|
* **system_reset_allowed** - Is domain allowed to reset the system?
|
||||||
|
* **system_suspend_allowed** - Is domain allowed to suspend the system?
|
||||||
|
|
||||||
The memory regions represented by **regions** in **struct sbi_domain** have
|
The memory regions represented by **regions** in **struct sbi_domain** have
|
||||||
following additional constraints to align with RISC-V PMP requirements:
|
following additional constraints to align with RISC-V PMP requirements:
|
||||||
@@ -91,6 +92,7 @@ following manner:
|
|||||||
* **next_mode** - Next booting stage mode in coldboot HART scratch space
|
* **next_mode** - Next booting stage mode in coldboot HART scratch space
|
||||||
is the next mode for the ROOT domain
|
is the next mode for the ROOT domain
|
||||||
* **system_reset_allowed** - The ROOT domain is allowed to reset the system
|
* **system_reset_allowed** - The ROOT domain is allowed to reset the system
|
||||||
|
* **system_suspend_allowed** - The ROOT domain is allowed to suspend the system
|
||||||
|
|
||||||
Domain Effects
|
Domain Effects
|
||||||
--------------
|
--------------
|
||||||
@@ -124,6 +126,9 @@ The DT properties of a domain configuration DT node are as follows:
|
|||||||
* **compatible** (Mandatory) - The compatible string of the domain
|
* **compatible** (Mandatory) - The compatible string of the domain
|
||||||
configuration. This DT property should have value *"opensbi,domain,config"*
|
configuration. This DT property should have value *"opensbi,domain,config"*
|
||||||
|
|
||||||
|
* **system-suspend-test** (Optional) - When present, enable a system
|
||||||
|
suspend test implementation which simply waits five seconds and issues a WFI.
|
||||||
|
|
||||||
### Domain Memory Region Node
|
### Domain Memory Region Node
|
||||||
|
|
||||||
The domain memory region DT node describes details of a memory region and
|
The domain memory region DT node describes details of a memory region and
|
||||||
@@ -160,8 +165,16 @@ The DT properties of a domain instance DT node are as follows:
|
|||||||
* **regions** (Optional) - The list of domain memory region DT node phandle
|
* **regions** (Optional) - The list of domain memory region DT node phandle
|
||||||
and access permissions for the domain instance. Each list entry is a pair
|
and access permissions for the domain instance. Each list entry is a pair
|
||||||
of DT node phandle and access permissions. The access permissions are
|
of DT node phandle and access permissions. The access permissions are
|
||||||
represented as a 32bit bitmask having bits: **readable** (BIT[0]),
|
represented as a 32bit bitmask having bits: **M readable** (BIT[0]),
|
||||||
**writeable** (BIT[1]), **executable** (BIT[2]), and **m-mode** (BIT[3]).
|
**M writeable** (BIT[1]), **M executable** (BIT[2]), **SU readable**
|
||||||
|
(BIT[3]), **SU writable** (BIT[4]), and **SU executable** (BIT[5]).
|
||||||
|
The enforce permission bit (BIT[6]), if set, will lock the permissions
|
||||||
|
in the PMP. This will enforce the permissions on M-mode as well which
|
||||||
|
otherwise will have unrestricted access. This bit must be used with
|
||||||
|
caution because no changes can be made to a PMP entry once its locked
|
||||||
|
until the hart is reset.
|
||||||
|
Any region of a domain defined in DT node cannot have only M-bits set
|
||||||
|
in access permissions i.e. it cannot be an m-mode only accessible region.
|
||||||
* **boot-hart** (Optional) - The DT node phandle of the HART booting the
|
* **boot-hart** (Optional) - The DT node phandle of the HART booting the
|
||||||
domain instance. If coldboot HART is assigned to the domain instance then
|
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
|
this DT property is ignored and the coldboot HART is assumed to be the
|
||||||
@@ -180,13 +193,15 @@ The DT properties of a domain instance DT node are as follows:
|
|||||||
is used as default value.
|
is used as default value.
|
||||||
* **next-mode** (Optional) - The 32 bit next booting stage mode for the
|
* **next-mode** (Optional) - The 32 bit next booting stage mode for the
|
||||||
domain instance. The possible values of this DT property are: **0x1**
|
domain instance. The possible values of this DT property are: **0x1**
|
||||||
(s-mode), and **0x0** (u-mode). If this DT property is not available
|
(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**
|
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
|
is used as default value. If this DT property is not available and
|
||||||
coldboot HART is assigned to the domain instance then **next booting
|
coldboot HART is assigned to the domain instance then **next booting
|
||||||
stage mode of coldboot HART** is used as default value.
|
stage mode of coldboot HART** is used as default value.
|
||||||
* **system-reset-allowed** (Optional) - A boolean flag representing
|
* **system-reset-allowed** (Optional) - A boolean flag representing
|
||||||
whether the domain instance is allowed to do system reset.
|
whether the domain instance is allowed to do system reset.
|
||||||
|
* **system-suspend-allowed** (Optional) - A boolean flag representing
|
||||||
|
whether the domain instance is allowed to do system suspend.
|
||||||
|
|
||||||
### Assigning HART To Domain Instance
|
### Assigning HART To Domain Instance
|
||||||
|
|
||||||
@@ -195,9 +210,9 @@ platform support can provide the HART to domain instance assignment using
|
|||||||
platform specific callback.
|
platform specific callback.
|
||||||
|
|
||||||
The HART to domain instance assignment can be parsed from the device tree
|
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
|
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
|
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
|
instance DT node. If **opensbi-domain** DT property is not specified then
|
||||||
corresponding HART is assigned to **the ROOT domain**.
|
corresponding HART is assigned to **the ROOT domain**.
|
||||||
|
|
||||||
### Domain Configuration Only Accessible to OpenSBI
|
### Domain Configuration Only Accessible to OpenSBI
|
||||||
@@ -222,6 +237,7 @@ be done:
|
|||||||
chosen {
|
chosen {
|
||||||
opensbi-domains {
|
opensbi-domains {
|
||||||
compatible = "opensbi,domain,config";
|
compatible = "opensbi,domain,config";
|
||||||
|
system-suspend-test;
|
||||||
|
|
||||||
tmem: tmem {
|
tmem: tmem {
|
||||||
compatible = "opensbi,domain,memregion";
|
compatible = "opensbi,domain,memregion";
|
||||||
@@ -246,18 +262,19 @@ be done:
|
|||||||
tdomain: trusted-domain {
|
tdomain: trusted-domain {
|
||||||
compatible = "opensbi,domain,instance";
|
compatible = "opensbi,domain,instance";
|
||||||
possible-harts = <&cpu0>;
|
possible-harts = <&cpu0>;
|
||||||
regions = <&tmem 0x7>, <&tuart 0x7>;
|
regions = <&tmem 0x3f>, <&tuart 0x3f>;
|
||||||
boot-hart = <&cpu0>;
|
boot-hart = <&cpu0>;
|
||||||
next-arg1 = <0x0 0x0>;
|
next-arg1 = <0x0 0x0>;
|
||||||
next-addr = <0x0 0x80100000>;
|
next-addr = <0x0 0x80100000>;
|
||||||
next-mode = <0x0>;
|
next-mode = <0x0>;
|
||||||
system-reset-allowed;
|
system-reset-allowed;
|
||||||
|
system-suspend-allowed;
|
||||||
};
|
};
|
||||||
|
|
||||||
udomain: untrusted-domain {
|
udomain: untrusted-domain {
|
||||||
compatible = "opensbi,domain,instance";
|
compatible = "opensbi,domain,instance";
|
||||||
possible-harts = <&cpu1 &cpu2 &cpu3 &cpu4>;
|
possible-harts = <&cpu1 &cpu2 &cpu3 &cpu4>;
|
||||||
regions = <&tmem 0x0>, <&tuart 0x0>, <&allmem 0x7>;
|
regions = <&tmem 0x0>, <&tuart 0x0>, <&allmem 0x3f>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@@ -53,7 +53,7 @@ the booting stage to follow OpenSBI firmware.
|
|||||||
A *FW_PAYLOAD* firmware is also useful for cases where the booting stage prior
|
A *FW_PAYLOAD* firmware is also useful for cases where the booting stage prior
|
||||||
to OpenSBI firmware does not pass a *flattened device tree (FDT file)*. In such
|
to OpenSBI firmware does not pass a *flattened device tree (FDT file)*. In such
|
||||||
case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree in the
|
case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree in the
|
||||||
.text section of the final firmware.
|
.rodata section of the final firmware.
|
||||||
|
|
||||||
Firmware Configuration and Compilation
|
Firmware Configuration and Compilation
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
@@ -61,7 +61,7 @@ Firmware Configuration and Compilation
|
|||||||
All firmware types support the following common compile time configuration
|
All firmware types support the following common compile time configuration
|
||||||
parameters:
|
parameters:
|
||||||
|
|
||||||
* **FW_TEXT_ADDR** - Defines the execution address of the OpenSBI firmware.
|
* **FW_TEXT_START** - Defines the execution address of the OpenSBI firmware.
|
||||||
This configuration parameter is mandatory.
|
This configuration parameter is mandatory.
|
||||||
* **FW_FDT_PATH** - Path to an external flattened device tree binary file to
|
* **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
|
be embedded in the *.rodata* section of the final firmware. If this option
|
||||||
|
@@ -20,7 +20,7 @@ the booting stage binary to follow OpenSBI firmware.
|
|||||||
A platform can enable *FW_DYNAMIC* firmware using any of the following methods.
|
A platform can enable *FW_DYNAMIC* firmware using any of the following methods.
|
||||||
|
|
||||||
1. Specifying `FW_DYNAMIC=y` on the top level `make` command line.
|
1. Specifying `FW_DYNAMIC=y` on the top level `make` command line.
|
||||||
2. Specifying `FW_DYNAMIC=y` in the target platform *config.mk* configuration
|
2. Specifying `FW_DYNAMIC=y` in the target platform *objects.mk* configuration
|
||||||
file.
|
file.
|
||||||
|
|
||||||
The compiled *FW_DYNAMIC* firmware ELF file is named *fw_dynamic.elf*. It's
|
The compiled *FW_DYNAMIC* firmware ELF file is named *fw_dynamic.elf*. It's
|
||||||
@@ -31,6 +31,6 @@ directory.
|
|||||||
*FW_DYNAMIC* Firmware Configuration Options
|
*FW_DYNAMIC* Firmware Configuration Options
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
|
||||||
The *FW_DYNAMIC* firmware does not requires any platform specific configuration
|
The *FW_DYNAMIC* firmware does not require any platform specific configuration
|
||||||
parameters because all required information is passed by previous booting stage
|
parameters because all required information is passed by previous booting stage
|
||||||
at runtime via *struct fw_dynamic_info*.
|
at runtime via *struct fw_dynamic_info*.
|
||||||
|
@@ -15,7 +15,7 @@ and the booting stage binary to follow the OpenSBI firmware.
|
|||||||
A platform *FW_JUMP* firmware can be enabled by any of the following methods:
|
A platform *FW_JUMP* firmware can be enabled by any of the following methods:
|
||||||
|
|
||||||
1. Specifying `FW_JUMP=y` on the top level `make` command line.
|
1. Specifying `FW_JUMP=y` on the top level `make` command line.
|
||||||
2. Specifying `FW_JUMP=y` in the target platform *config.mk* configuration file.
|
2. Specifying `FW_JUMP=y` in the target platform *objects.mk* configuration file.
|
||||||
|
|
||||||
The compiled *FW_JUMP* firmware ELF file is named *fw_jump.elf*. Its expanded
|
The compiled *FW_JUMP* firmware ELF file is named *fw_jump.elf*. Its expanded
|
||||||
image file is *fw_jump.bin*. Both files are created in the platform-specific
|
image file is *fw_jump.bin*. Both files are created in the platform-specific
|
||||||
@@ -26,7 +26,7 @@ build directory under the *build/platform/<platform_subdir>/firmware* directory.
|
|||||||
|
|
||||||
To operate correctly, a *FW_JUMP* firmware requires some configuration
|
To operate correctly, a *FW_JUMP* firmware requires some configuration
|
||||||
parameters to be defined using either the top level `make` command line or the
|
parameters to be defined using either the top level `make` command line or the
|
||||||
target platform *config.mk* configuration file. The possible parameters are as
|
target platform *objects.mk* configuration file. The possible parameters are as
|
||||||
follows:
|
follows:
|
||||||
|
|
||||||
* **FW_JUMP_ADDR** - Address of the entry point of the booting stage to be
|
* **FW_JUMP_ADDR** - Address of the entry point of the booting stage to be
|
||||||
@@ -41,6 +41,22 @@ follows:
|
|||||||
provided, then the OpenSBI firmware will pass the FDT address passed by the
|
provided, then the OpenSBI firmware will pass the FDT address passed by the
|
||||||
previous booting stage to the next booting stage.
|
previous booting stage to the next booting stage.
|
||||||
|
|
||||||
|
When using the default *FW_JUMP_FDT_ADDR* with *PLATFORM=generic*, you must
|
||||||
|
ensure *FW_JUMP_FDT_ADDR* is set high enough to avoid overwriting the kernel.
|
||||||
|
You can use the following method (e.g., using bash or zsh):
|
||||||
|
|
||||||
|
```
|
||||||
|
${CROSS_COMPILE}objdump -h $KERNEL_ELF | sort -k 5,5 | awk -n '
|
||||||
|
/^ +[0-9]+ / {addr="0x"$3; size="0x"$5; printf "0x""%x\n",addr+size}' |
|
||||||
|
(( `tail -1` > (FW_JUMP_FDT_ADDR - FW_JUMP_ADDR) )) &&
|
||||||
|
echo fdt overlaps kernel, increase FW_JUMP_FDT_ADDR
|
||||||
|
|
||||||
|
${LLVM}objdump -h --show-lma $KERNEL_ELF | sort -k 5,5 | awk -n '
|
||||||
|
/^ +[0-9]+ / {addr="0x"$3; size="0x"$5; printf "0x""%x\n",addr+size}' |
|
||||||
|
(( `tail -1` > (FW_JUMP_FDT_ADDR - FW_JUMP_ADDR) )) &&
|
||||||
|
echo fdt overlaps kernel, increase FW_JUMP_FDT_ADDR
|
||||||
|
```
|
||||||
|
|
||||||
*FW_JUMP* Example
|
*FW_JUMP* Example
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
@@ -12,7 +12,7 @@ firmware and the booting stage to follow OpenSBI firmware.
|
|||||||
A *FW_PAYLOAD* firmware is also useful for cases where the booting stage prior
|
A *FW_PAYLOAD* firmware is also useful for cases where the booting stage prior
|
||||||
to the OpenSBI firmware does not pass a *flattened device tree (FDT file)*. In
|
to the OpenSBI firmware does not pass a *flattened device tree (FDT file)*. In
|
||||||
such a case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree
|
such a case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree
|
||||||
in the .text section of the final firmware.
|
in the .rodata section of the final firmware.
|
||||||
|
|
||||||
Enabling *FW_PAYLOAD* compilation
|
Enabling *FW_PAYLOAD* compilation
|
||||||
---------------------------------
|
---------------------------------
|
||||||
@@ -20,7 +20,7 @@ Enabling *FW_PAYLOAD* compilation
|
|||||||
The *FW_PAYLOAD* firmware can be enabled by any of the following methods:
|
The *FW_PAYLOAD* firmware can be enabled by any of the following methods:
|
||||||
|
|
||||||
1. Specifying `FW_PAYLOAD=y` on the top level `make` command line.
|
1. Specifying `FW_PAYLOAD=y` on the top level `make` command line.
|
||||||
2. Specifying `FW_PAYLOAD=y` in the target platform *config.mk* configuration
|
2. Specifying `FW_PAYLOAD=y` in the target platform *objects.mk* configuration
|
||||||
file.
|
file.
|
||||||
|
|
||||||
The compiled *FW_PAYLOAD* firmware ELF file is named *fw_jump.elf*. Its
|
The compiled *FW_PAYLOAD* firmware ELF file is named *fw_jump.elf*. Its
|
||||||
@@ -33,10 +33,10 @@ Configuration Options
|
|||||||
|
|
||||||
A *FW_PAYLOAD* firmware is built according to configuration parameters and
|
A *FW_PAYLOAD* firmware is built according to configuration parameters and
|
||||||
options. These configuration parameters can be defined using either the top
|
options. These configuration parameters can be defined using either the top
|
||||||
level `make` command line or the target platform *config.mk* configuration
|
level `make` command line or the target platform *objects.mk* configuration
|
||||||
file. The parameters currently defined are as follows:
|
file. The parameters currently defined are as follows:
|
||||||
|
|
||||||
* **FW_PAYLOAD_OFFSET** - Offset from *FW_TEXT_BASE* where the payload binary
|
* **FW_PAYLOAD_OFFSET** - Offset from *FW_TEXT_START* where the payload binary
|
||||||
will be linked in the final *FW_PAYLOAD* firmware binary image. This
|
will be linked in the final *FW_PAYLOAD* firmware binary image. This
|
||||||
configuration parameter is mandatory if *FW_PAYLOAD_ALIGN* is not defined.
|
configuration parameter is mandatory if *FW_PAYLOAD_ALIGN* is not defined.
|
||||||
Compilation errors will result from an incorrect definition of
|
Compilation errors will result from an incorrect definition of
|
||||||
|
@@ -8,11 +8,7 @@ OpenSBI provides two types of static libraries:
|
|||||||
hooks for the execution of this interface must be provided by the firmware or
|
hooks for the execution of this interface must be provided by the firmware or
|
||||||
bootloader linking with this library. This library is installed as
|
bootloader linking with this library. This library is installed as
|
||||||
*<install_directory>/lib/libsbi.a*
|
*<install_directory>/lib/libsbi.a*
|
||||||
2. *libsbiutils.a* - A static library that will contain all common code required
|
2. *libplatsbi.a* - An example platform-specific static library integrating
|
||||||
by any platform supported in OpenSBI. It will be built by default and included
|
|
||||||
in libplatsbi.a. This library is installed as
|
|
||||||
*<install_directory>/lib/libsbiutils.a*.
|
|
||||||
3. *libplatsbi.a* - An example platform-specific static library integrating
|
|
||||||
*libsbi.a* with platform-specific hooks. This library is available only for
|
*libsbi.a* with platform-specific hooks. This library is available only for
|
||||||
the platforms supported by OpenSBI. This library is installed as
|
the platforms supported by OpenSBI. This library is installed as
|
||||||
*<install_directory>/platform/<platform_subdir>/lib/libplatsbi.a*
|
*<install_directory>/platform/<platform_subdir>/lib/libplatsbi.a*
|
||||||
@@ -77,7 +73,7 @@ firmware drivers based on the external firmware architecture.
|
|||||||
**OPENSBI_EXTERNAL_SBI_TYPES** identifier is introduced to *sbi_types.h* for selecting
|
**OPENSBI_EXTERNAL_SBI_TYPES** identifier is introduced to *sbi_types.h* for selecting
|
||||||
external header file during the build preprocess in order to define OpensSBI data types
|
external header file during the build preprocess in order to define OpensSBI data types
|
||||||
based on external firmware data type binding.
|
based on external firmware data type binding.
|
||||||
For example, *bool* is declared as *int* in sbi_types.h. However in EDK2 build system,
|
For example, *bool* is declared as *int* in sbi_types.h. However, in EDK2 build system,
|
||||||
*bool* is declared as *BOOLEAN* which is defined as *unsigned char* data type.
|
*bool* is declared as *BOOLEAN* which is defined as *unsigned char* data type.
|
||||||
|
|
||||||
External firmware can define **OPENSBI_EXTERNAL_SBI_TYPES** in CFLAGS and specify it to the
|
External firmware can define **OPENSBI_EXTERNAL_SBI_TYPES** in CFLAGS and specify it to the
|
||||||
|
@@ -8,7 +8,7 @@ AHB/APB IPs suites a majority embedded systems, and the verified platform serves
|
|||||||
as a starting point to jump start SoC designs.
|
as a starting point to jump start SoC designs.
|
||||||
|
|
||||||
To build platform specific library and firmwares, provide the
|
To build platform specific library and firmwares, provide the
|
||||||
*PLATFORM=andes/ae350* parameter to the top level make command.
|
*PLATFORM=generic* parameter to the top level `make` command.
|
||||||
|
|
||||||
Platform Options
|
Platform Options
|
||||||
----------------
|
----------------
|
||||||
@@ -18,13 +18,190 @@ The Andes AE350 platform does not have any platform-specific options.
|
|||||||
Building Andes AE350 Platform
|
Building Andes AE350 Platform
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
To use Linux v5.2 should be used to build Andes AE350 OpenSBI binaries by using
|
AE350's dts is included in https://github.com/andestech/linux/tree/RISCV-Linux-5.4-ast-v5_1_0-branch
|
||||||
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**
|
**Linux Kernel Payload**
|
||||||
|
|
||||||
```
|
```
|
||||||
make PLATFORM=andes/ae350 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<ae350.dtb path>
|
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<ae350.dtb path>
|
||||||
|
```
|
||||||
|
|
||||||
|
DTS Example: (Quad-core AX45MP)
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
```
|
||||||
|
compatible = "andestech,ae350";
|
||||||
|
cpus {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
timebase-frequency = <60000000>;
|
||||||
|
|
||||||
|
CPU0: cpu@0 {
|
||||||
|
device_type = "cpu";
|
||||||
|
reg = <0>;
|
||||||
|
status = "okay";
|
||||||
|
compatible = "riscv";
|
||||||
|
riscv,isa = "rv64imafdc";
|
||||||
|
riscv,priv-major = <1>;
|
||||||
|
riscv,priv-minor = <10>;
|
||||||
|
mmu-type = "riscv,sv48";
|
||||||
|
clock-frequency = <60000000>;
|
||||||
|
i-cache-size = <0x8000>;
|
||||||
|
i-cache-sets = <256>;
|
||||||
|
i-cache-line-size = <64>;
|
||||||
|
i-cache-block-size = <64>;
|
||||||
|
d-cache-size = <0x8000>;
|
||||||
|
d-cache-sets = <128>;
|
||||||
|
d-cache-line-size = <64>;
|
||||||
|
d-cache-block-size = <64>;
|
||||||
|
next-level-cache = <&L2>;
|
||||||
|
CPU0_intc: interrupt-controller {
|
||||||
|
#interrupt-cells = <1>;
|
||||||
|
interrupt-controller;
|
||||||
|
compatible = "riscv,cpu-intc";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
CPU1: cpu@1 {
|
||||||
|
device_type = "cpu";
|
||||||
|
reg = <1>;
|
||||||
|
status = "okay";
|
||||||
|
compatible = "riscv";
|
||||||
|
riscv,isa = "rv64imafdc";
|
||||||
|
riscv,priv-major = <1>;
|
||||||
|
riscv,priv-minor = <10>;
|
||||||
|
mmu-type = "riscv,sv48";
|
||||||
|
clock-frequency = <60000000>;
|
||||||
|
i-cache-size = <0x8000>;
|
||||||
|
i-cache-sets = <256>;
|
||||||
|
i-cache-line-size = <64>;
|
||||||
|
i-cache-block-size = <64>;
|
||||||
|
d-cache-size = <0x8000>;
|
||||||
|
d-cache-sets = <128>;
|
||||||
|
d-cache-line-size = <64>;
|
||||||
|
d-cache-block-size = <64>;
|
||||||
|
next-level-cache = <&L2>;
|
||||||
|
CPU1_intc: interrupt-controller {
|
||||||
|
#interrupt-cells = <1>;
|
||||||
|
interrupt-controller;
|
||||||
|
compatible = "riscv,cpu-intc";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
CPU2: cpu@2 {
|
||||||
|
device_type = "cpu";
|
||||||
|
reg = <2>;
|
||||||
|
status = "okay";
|
||||||
|
compatible = "riscv";
|
||||||
|
riscv,isa = "rv64imafdc";
|
||||||
|
riscv,priv-major = <1>;
|
||||||
|
riscv,priv-minor = <10>;
|
||||||
|
mmu-type = "riscv,sv48";
|
||||||
|
clock-frequency = <60000000>;
|
||||||
|
i-cache-size = <0x8000>;
|
||||||
|
i-cache-sets = <256>;
|
||||||
|
i-cache-line-size = <64>;
|
||||||
|
i-cache-block-size = <64>;
|
||||||
|
d-cache-size = <0x8000>;
|
||||||
|
d-cache-sets = <128>;
|
||||||
|
d-cache-line-size = <64>;
|
||||||
|
d-cache-block-size = <64>;
|
||||||
|
next-level-cache = <&L2>;
|
||||||
|
CPU2_intc: interrupt-controller {
|
||||||
|
#interrupt-cells = <1>;
|
||||||
|
interrupt-controller;
|
||||||
|
compatible = "riscv,cpu-intc";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
CPU3: cpu@3 {
|
||||||
|
device_type = "cpu";
|
||||||
|
reg = <3>;
|
||||||
|
status = "okay";
|
||||||
|
compatible = "riscv";
|
||||||
|
riscv,isa = "rv64imafdc";
|
||||||
|
riscv,priv-major = <1>;
|
||||||
|
riscv,priv-minor = <10>;
|
||||||
|
mmu-type = "riscv,sv48";
|
||||||
|
clock-frequency = <60000000>;
|
||||||
|
i-cache-size = <0x8000>;
|
||||||
|
i-cache-sets = <256>;
|
||||||
|
i-cache-line-size = <64>;
|
||||||
|
i-cache-block-size = <64>;
|
||||||
|
d-cache-size = <0x8000>;
|
||||||
|
d-cache-sets = <128>;
|
||||||
|
d-cache-line-size = <64>;
|
||||||
|
d-cache-block-size = <64>;
|
||||||
|
next-level-cache = <&L2>;
|
||||||
|
CPU3_intc: interrupt-controller {
|
||||||
|
#interrupt-cells = <1>;
|
||||||
|
interrupt-controller;
|
||||||
|
compatible = "riscv,cpu-intc";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
soc {
|
||||||
|
#address-cells = <2>;
|
||||||
|
#size-cells = <2>;
|
||||||
|
compatible = "andestech,riscv-ae350-soc", "simple-bus";
|
||||||
|
ranges;
|
||||||
|
|
||||||
|
plic0: interrupt-controller@e4000000 {
|
||||||
|
compatible = "riscv,plic0";
|
||||||
|
reg = <0x00000000 0xe4000000 0x00000000 0x02000000>;
|
||||||
|
interrupts-extended = < &CPU0_intc 11 &CPU0_intc 9
|
||||||
|
&CPU1_intc 11 &CPU1_intc 9
|
||||||
|
&CPU2_intc 11 &CPU2_intc 9
|
||||||
|
&CPU3_intc 11 &CPU3_intc 9 >;
|
||||||
|
interrupt-controller;
|
||||||
|
#address-cells = <2>;
|
||||||
|
#interrupt-cells = <2>;
|
||||||
|
riscv,ndev = <71>;
|
||||||
|
};
|
||||||
|
|
||||||
|
plicsw: interrupt-controller@e6400000 {
|
||||||
|
compatible = "andestech,plicsw";
|
||||||
|
reg = <0x00000000 0xe6400000 0x00000000 0x00400000>;
|
||||||
|
interrupts-extended = < &CPU0_intc 3
|
||||||
|
&CPU1_intc 3
|
||||||
|
&CPU2_intc 3
|
||||||
|
&CPU3_intc 3 >;
|
||||||
|
interrupt-controller;
|
||||||
|
#address-cells = <2>;
|
||||||
|
#interrupt-cells = <2>;
|
||||||
|
};
|
||||||
|
|
||||||
|
plmt0: plmt0@e6000000 {
|
||||||
|
compatible = "andestech,plmt0";
|
||||||
|
reg = <0x00000000 0xe6000000 0x00000000 0x00100000>;
|
||||||
|
interrupts-extended = < &CPU0_intc 7
|
||||||
|
&CPU1_intc 7
|
||||||
|
&CPU2_intc 7
|
||||||
|
&CPU3_intc 7 >;
|
||||||
|
};
|
||||||
|
|
||||||
|
wdt: watchdog@f0500000 {
|
||||||
|
compatible = "andestech,atcwdt200";
|
||||||
|
reg = <0x00000000 0xf0500000 0x00000000 0x00001000>;
|
||||||
|
interrupts = <3 4>;
|
||||||
|
interrupt-parent = <&plic0>;
|
||||||
|
clock-frequency = <15000000>;
|
||||||
|
};
|
||||||
|
|
||||||
|
serial0: serial@f0300000 {
|
||||||
|
compatible = "andestech,uart16550", "ns16550a";
|
||||||
|
reg = <0x00000000 0xf0300000 0x00000000 0x00001000>;
|
||||||
|
interrupts = <9 4>;
|
||||||
|
interrupt-parent = <&plic0>;
|
||||||
|
clock-frequency = <19660800>;
|
||||||
|
current-speed = <38400>;
|
||||||
|
reg-shift = <2>;
|
||||||
|
reg-offset = <32>;
|
||||||
|
reg-io-width = <4>;
|
||||||
|
no-loopback-test = <1>;
|
||||||
|
};
|
||||||
|
|
||||||
|
smu: smu@f0100000 {
|
||||||
|
compatible = "andestech,atcsmu";
|
||||||
|
reg = <0x00000000 0xf0100000 0x00000000 0x00001000>;
|
||||||
|
};
|
||||||
|
};
|
||||||
```
|
```
|
||||||
|
@@ -7,7 +7,7 @@ Linux.
|
|||||||
|
|
||||||
The FPGA SoC currently contains the following peripherals:
|
The FPGA SoC currently contains the following peripherals:
|
||||||
- DDR3 memory controller
|
- DDR3 memory controller
|
||||||
- SPI controller to conncet to an SDCard
|
- SPI controller to connect to an SDCard
|
||||||
- Ethernet controller
|
- Ethernet controller
|
||||||
- JTAG port (see debugging section below)
|
- JTAG port (see debugging section below)
|
||||||
- Bootrom containing zero stage bootloader and device tree.
|
- Bootrom containing zero stage bootloader and device tree.
|
||||||
|
@@ -45,13 +45,17 @@ The *Generic* platform does not have any platform-specific options.
|
|||||||
RISC-V Platforms Using Generic Platform
|
RISC-V Platforms Using Generic Platform
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
|
|
||||||
|
* **Andes AE350 Platform** (*[andes-ae350.md]*)
|
||||||
* **QEMU RISC-V Virt Machine** (*[qemu_virt.md]*)
|
* **QEMU RISC-V Virt Machine** (*[qemu_virt.md]*)
|
||||||
|
* **Renesas RZ/Five SoC** (*[renesas-rzfive.md]*)
|
||||||
* **Shakti C-class SoC Platform** (*[shakti_cclass.md]*)
|
* **Shakti C-class SoC Platform** (*[shakti_cclass.md]*)
|
||||||
* **SiFive HiFive Unleashed** (*[sifive_fu540.md]*)
|
* **SiFive HiFive Unleashed** (*[sifive_fu540.md]*)
|
||||||
* **Spike** (*[spike.md]*)
|
* **Spike** (*[spike.md]*)
|
||||||
* **T-HEAD C9xx series Processors** (*[thead-c9xx.md]*)
|
* **T-HEAD C9xx series Processors** (*[thead-c9xx.md]*)
|
||||||
|
|
||||||
|
[andes-ae350.md]: andes-ae350.md
|
||||||
[qemu_virt.md]: qemu_virt.md
|
[qemu_virt.md]: qemu_virt.md
|
||||||
|
[renesas-rzfive.md]: renesas-rzfive.md
|
||||||
[shakti_cclass.md]: shakti_cclass.md
|
[shakti_cclass.md]: shakti_cclass.md
|
||||||
[sifive_fu540.md]: sifive_fu540.md
|
[sifive_fu540.md]: sifive_fu540.md
|
||||||
[spike.md]: spike.md
|
[spike.md]: spike.md
|
||||||
|
@@ -39,11 +39,15 @@ OpenSBI currently supports the following virtual and hardware platforms:
|
|||||||
processor based SOCs. More details on this platform can be found in the
|
processor based SOCs. More details on this platform can be found in the
|
||||||
file *[shakti_cclass.md]*.
|
file *[shakti_cclass.md]*.
|
||||||
|
|
||||||
|
* **Renesas RZ/Five SoC**: Platform support for Renesas RZ/Five (R9A07G043F) SoC
|
||||||
|
used on the Renesas RZ/Five SMARC EVK board. More details on this platform can
|
||||||
|
be found in the file *[renesas-rzfive.md]*.
|
||||||
|
|
||||||
The code for these supported platforms can be used as example to implement
|
The code for these supported platforms can be used as example to implement
|
||||||
support for other platforms. The *platform/template* directory also provides
|
support for other platforms. The *platform/template* directory also provides
|
||||||
template files for implementing support for a new platform. The *object.mk*,
|
template files for implementing support for a new platform. The *objects.mk*,
|
||||||
*config.mk* and *platform.c* template files provides enough comments to
|
*Kconfig*, *configs/defconfig* and *platform.c* template files provides enough
|
||||||
facilitate the implementation.
|
comments to facilitate the implementation.
|
||||||
|
|
||||||
[generic.md]: generic.md
|
[generic.md]: generic.md
|
||||||
[qemu_virt.md]: qemu_virt.md
|
[qemu_virt.md]: qemu_virt.md
|
||||||
@@ -54,3 +58,4 @@ facilitate the implementation.
|
|||||||
[spike.md]: spike.md
|
[spike.md]: spike.md
|
||||||
[fpga-openpiton.md]: fpga-openpiton.md
|
[fpga-openpiton.md]: fpga-openpiton.md
|
||||||
[shakti_cclass.md]: shakti_cclass.md
|
[shakti_cclass.md]: shakti_cclass.md
|
||||||
|
[renesas-rzfive.md]: renesas-rzfive.md
|
||||||
|
160
docs/platform/renesas-rzfive.md
Normal file
160
docs/platform/renesas-rzfive.md
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
Renesas RZ/Five SoC (R9A07G043F) Platform
|
||||||
|
=========================================
|
||||||
|
The RZ/Five microprocessor includes a single RISC-V CPU Core (Andes AX45MP)
|
||||||
|
1.0 GHz, 16-bit DDR3L/DDR4 interface. Supported interfaces include:
|
||||||
|
- Memory controller for DDR4-1600 / DDR3L-1333 with 16 bits
|
||||||
|
- System RAM (RAM of 128 Kbytes (ECC))
|
||||||
|
- SPI Multi I/O Bus Controller 1ch
|
||||||
|
- SD Card Host Interface/Multimedia Card Interface (SD/MMC) 2ch
|
||||||
|
- Serial Sound Interface (SSI) 4ch
|
||||||
|
- Sampling Rate Converter (SRC) 1ch
|
||||||
|
- USB2.0 host/function interface 2ch (ch0: Host-Function ch1: Host only)
|
||||||
|
- Gigabit Ethernet Interface (GbE) 2ch
|
||||||
|
- Controller Area Network Interface (CAN) 2ch (CAN-FD ISO 11898-1 (CD2014) compliant)
|
||||||
|
- Multi-function Timer Pulse Unit 3 (MTU3a) 9 ch (16 bits × 8 channels, 32 bits × 1 channel)
|
||||||
|
- Port Output Enable 3 (POE3)
|
||||||
|
- Watchdog Timer (WDT) 1ch
|
||||||
|
- General Timer (GTM) 3ch (32bits)
|
||||||
|
- I2C Bus Interface (I2C) 4ch
|
||||||
|
- Serial Communication Interface with FIFO (SCIFA) 5ch
|
||||||
|
- Serial Communication Interface (SCI) 2ch
|
||||||
|
- Renesas Serial Peripheral Interface (RSPI) 3ch
|
||||||
|
- A/D Converter (ADC) 2ch
|
||||||
|
making it ideal for applications such as entry-class social infrastructure
|
||||||
|
gateway control and industrial gateway control. More details can be found at
|
||||||
|
below link [0].
|
||||||
|
|
||||||
|
[0] https://www.renesas.com/us/en/products/microcontrollers-microprocessors/rz-mpus/rzfive-general-purpose-microprocessors-risc-v-cpu-core-andes-ax45mp-single-10-ghz-2ch-gigabit-ethernet
|
||||||
|
|
||||||
|
To build platform specific library and firmwares, provide the
|
||||||
|
*PLATFORM=generic* parameter to the top level make command.
|
||||||
|
|
||||||
|
Platform Options
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The Renesas RZ/Five platform does not have any platform-specific options.
|
||||||
|
|
||||||
|
Building Renesas RZ/Five Platform
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
```
|
||||||
|
make PLATFORM=generic
|
||||||
|
```
|
||||||
|
|
||||||
|
DTS Example: (RZ/Five AX45MP)
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
```
|
||||||
|
compatible = "renesas,r9a07g043f01", "renesas,r9a07g043";
|
||||||
|
|
||||||
|
cpus {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
timebase-frequency = <12000000>;
|
||||||
|
|
||||||
|
cpu0: cpu@0 {
|
||||||
|
compatible = "andestech,ax45mp", "riscv";
|
||||||
|
device_type = "cpu";
|
||||||
|
reg = <0x0>;
|
||||||
|
status = "okay";
|
||||||
|
riscv,isa = "rv64imafdc";
|
||||||
|
mmu-type = "riscv,sv39";
|
||||||
|
i-cache-size = <0x8000>;
|
||||||
|
i-cache-line-size = <0x40>;
|
||||||
|
d-cache-size = <0x8000>;
|
||||||
|
d-cache-line-size = <0x40>;
|
||||||
|
clocks = <&cpg CPG_CORE R9A07G043_CLK_I>;
|
||||||
|
|
||||||
|
cpu0_intc: interrupt-controller {
|
||||||
|
#interrupt-cells = <1>;
|
||||||
|
compatible = "riscv,cpu-intc";
|
||||||
|
interrupt-controller;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
soc {
|
||||||
|
compatible = "simple-bus";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
ranges;
|
||||||
|
|
||||||
|
scif0: serial@1004b800 {
|
||||||
|
compatible = "renesas,scif-r9a07g043",
|
||||||
|
"renesas,scif-r9a07g044";
|
||||||
|
reg = <0 0x1004b800 0 0x400>;
|
||||||
|
interrupts = <412 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<414 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<415 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<413 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<416 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<416 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
interrupt-names = "eri", "rxi", "txi",
|
||||||
|
"bri", "dri", "tei";
|
||||||
|
clocks = <&cpg CPG_MOD R9A07G043_SCIF0_CLK_PCK>;
|
||||||
|
clock-names = "fck";
|
||||||
|
power-domains = <&cpg>;
|
||||||
|
resets = <&cpg R9A07G043_SCIF0_RST_SYSTEM_N>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
cpg: clock-controller@11010000 {
|
||||||
|
compatible = "renesas,r9a07g043-cpg";
|
||||||
|
reg = <0 0x11010000 0 0x10000>;
|
||||||
|
clocks = <&extal_clk>;
|
||||||
|
clock-names = "extal";
|
||||||
|
#clock-cells = <2>;
|
||||||
|
#reset-cells = <1>;
|
||||||
|
#power-domain-cells = <0>;
|
||||||
|
};
|
||||||
|
|
||||||
|
sysc: system-controller@11020000 {
|
||||||
|
compatible = "renesas,r9a07g043-sysc";
|
||||||
|
reg = <0 0x11020000 0 0x10000>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
pinctrl: pinctrl@11030000 {
|
||||||
|
compatible = "renesas,r9a07g043-pinctrl";
|
||||||
|
reg = <0 0x11030000 0 0x10000>;
|
||||||
|
gpio-controller;
|
||||||
|
#gpio-cells = <2>;
|
||||||
|
#interrupt-cells = <2>;
|
||||||
|
interrupt-controller;
|
||||||
|
gpio-ranges = <&pinctrl 0 0 152>;
|
||||||
|
clocks = <&cpg CPG_MOD R9A07G043_GPIO_HCLK>;
|
||||||
|
power-domains = <&cpg>;
|
||||||
|
resets = <&cpg R9A07G043_GPIO_RSTN>,
|
||||||
|
<&cpg R9A07G043_GPIO_PORT_RESETN>,
|
||||||
|
<&cpg R9A07G043_GPIO_SPARE_RESETN>;
|
||||||
|
};
|
||||||
|
|
||||||
|
plmt0: plmt0@110c0000 {
|
||||||
|
compatible = "andestech,plmt0", "riscv,plmt0";
|
||||||
|
reg = <0x0 0x110c0000 0x0 0x10000>;
|
||||||
|
interrupts-extended = <&cpu0_intc 7>;
|
||||||
|
};
|
||||||
|
|
||||||
|
plic: interrupt-controller@12c00000 {
|
||||||
|
compatible = "renesas,r9a07g043-plic", "andestech,nceplic100";
|
||||||
|
#interrupt-cells = <2>;
|
||||||
|
#address-cells = <0>;
|
||||||
|
riscv,ndev = <511>;
|
||||||
|
interrupt-controller;
|
||||||
|
reg = <0x0 0x12c00000 0x0 0x400000>;
|
||||||
|
clocks = <&cpg CPG_MOD R9A07G043_NCEPLIC_ACLK>;
|
||||||
|
power-domains = <&cpg>;
|
||||||
|
resets = <&cpg R9A07G043_NCEPLIC_ARESETN>;
|
||||||
|
interrupts-extended = <&cpu0_intc 11 &cpu0_intc 9>;
|
||||||
|
};
|
||||||
|
|
||||||
|
plicsw: interrupt-controller@13000000 {
|
||||||
|
compatible = "andestech,plicsw";
|
||||||
|
reg = <0x0 0x13000000 0x0 0x400000>;
|
||||||
|
interrupts-extended = <&cpu0_intc 3>;
|
||||||
|
interrupt-controller;
|
||||||
|
#address-cells = <2>;
|
||||||
|
#interrupt-cells = <2>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
@@ -150,7 +150,7 @@ If you want to test OpenSBI with QEMU 'sifive_u' machine, please follow the
|
|||||||
same instructions above, with the exception of not passing FW_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
|
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
|
command line parameters, and it's compatible with the one used in the upstream
|
||||||
Linux kernel.
|
Linux kernel.
|
||||||
|
|
||||||
When U-Boot v2021.07 (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
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
T-HEAD C9xx Series Processors
|
T-HEAD C9xx Series Processors
|
||||||
=============================
|
=============================
|
||||||
|
|
||||||
The **C9xx** series processors are high-performance RISC-V architecture
|
The C9xx series processors are high-performance RISC-V architecture
|
||||||
multi-core processors with AI vector acceleration engine.
|
multi-core processors with AI vector acceleration engine.
|
||||||
|
|
||||||
For more details, refer [T-HEAD.CN](https://www.t-head.cn/)
|
For more details, refer [T-HEAD.CN](https://www.t-head.cn/)
|
||||||
@@ -12,185 +12,16 @@ To build the platform-specific library and firmware images, provide the
|
|||||||
Platform Options
|
Platform Options
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
The *T-HEAD C9xx* does not have any platform-specific compile options
|
The T-HEAD C9xx does not have any platform-specific compile options
|
||||||
because it use generic platform.
|
because it uses generic platform.
|
||||||
|
|
||||||
```
|
```
|
||||||
CROSS_COMPILE=riscv64-linux-gnu- PLATFORM=generic /usr/bin/make
|
CROSS_COMPILE=riscv64-linux-gnu- PLATFORM=generic make
|
||||||
```
|
```
|
||||||
|
|
||||||
The *T-HEAD C9xx* DTB provided to OpenSBI generic firmwares will usually have
|
Here is the simplest boot flow for a fpga prototype:
|
||||||
"riscv,clint0", "riscv,plic0", "thead,reset-sample" compatible strings.
|
|
||||||
|
|
||||||
DTS Example1: (Single core, eg: Allwinner D1 - c906)
|
(Jtag gdbinit) -> (zsb) -> (opensbi) -> (linux)
|
||||||
----------------------------------------------------
|
|
||||||
|
|
||||||
```
|
For more details, refer:
|
||||||
cpus {
|
[zero stage boot](https://github.com/c-sky/zero_stage_boot)
|
||||||
#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 = "allwinner,sun20i-d1-clint";
|
|
||||||
interrupts-extended = <
|
|
||||||
&cpu0_intc 3 &cpu0_intc 7
|
|
||||||
>;
|
|
||||||
reg = <0x0 0x14000000 0x0 0x04000000>;
|
|
||||||
};
|
|
||||||
|
|
||||||
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>;
|
|
||||||
};
|
|
||||||
|
|
||||||
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>;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
@@ -28,11 +28,12 @@ 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
|
2. Create platform configuration files named *Kconfig* and *configs/defconfig*
|
||||||
*platform/<xyz>/* directory. This configuration file will provide
|
under the *platform/<xyz>/* directory. These configuration files will
|
||||||
|
provide the build time configuration for the sources to be compiled.
|
||||||
|
3. Create a *platform/<xyz>/objects.mk* file for listing the platform
|
||||||
|
object files to be compiled. This file also provides platform-specific
|
||||||
compiler flags, and select firmware options.
|
compiler flags, and select firmware options.
|
||||||
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
|
4. Create a *platform/<xyz>/platform.c* file providing a
|
||||||
*struct sbi_platform* instance.
|
*struct sbi_platform* instance.
|
||||||
|
|
||||||
|
@@ -10,7 +10,7 @@ To handle this, we have two types of RISC-V platform requirements:
|
|||||||
2. **Release specific platform requirements** which apply to a OpenSBI
|
2. **Release specific platform requirements** which apply to a OpenSBI
|
||||||
release and later releases
|
release and later releases
|
||||||
|
|
||||||
Currently, we don't have any **Release specific platform requirements**
|
Currently, we don't have any **Release specific platform requirements**,
|
||||||
but such platform requirements will be added in future.
|
but such platform requirements will be added in future.
|
||||||
|
|
||||||
Base Platform Requirements
|
Base Platform Requirements
|
||||||
@@ -18,7 +18,7 @@ Base Platform Requirements
|
|||||||
|
|
||||||
The base RISC-V platform requirements for OpenSBI are as follows:
|
The base RISC-V platform requirements for OpenSBI are as follows:
|
||||||
|
|
||||||
1. At least rv32ima or rv64ima required on all HARTs
|
1. At least rv32ima_zicsr or rv64ima_zicsr required on all HARTs
|
||||||
2. At least one HART should have S-mode support because:
|
2. At least one HART should have S-mode support because:
|
||||||
|
|
||||||
* SBI calls are meant for RISC-V S-mode (Supervisor mode)
|
* SBI calls are meant for RISC-V S-mode (Supervisor mode)
|
||||||
@@ -33,7 +33,7 @@ The base RISC-V platform requirements for OpenSBI are as follows:
|
|||||||
6. Hardware support for injecting M-mode software interrupts on
|
6. Hardware support for injecting M-mode software interrupts on
|
||||||
a multi-HART platform
|
a multi-HART platform
|
||||||
|
|
||||||
The RISC-V extensions not covered by rv32ima or rv64ima are optional
|
The RISC-V extensions not covered by rv32ima_zicsr or rv64ima_zicsr are optional
|
||||||
for OpenSBI. Although, OpenSBI will detect and handle some of these
|
for OpenSBI. Although, OpenSBI will detect and handle some of these
|
||||||
optional RISC-V extensions at runtime.
|
optional RISC-V extensions at runtime.
|
||||||
|
|
||||||
|
@@ -1,14 +1,11 @@
|
|||||||
OpenSBI SBI PMU extension support
|
OpenSBI SBI PMU extension support
|
||||||
==================================
|
==================================
|
||||||
SBI PMU extension supports allow supervisor software to configure/start/stop
|
SBI PMU extension supports allow supervisor software to configure/start/stop
|
||||||
any performance counter at anytime. Thus, an user can leverage full
|
any performance counter at anytime. Thus, a user can leverage full
|
||||||
capability of performance analysis tools such as perf if SBI PMU extension is
|
capability of performance analysis tools such as perf if SBI PMU extension is
|
||||||
enabled. The OpenSBI implementation makes the following assumptions about the
|
enabled. The OpenSBI implementation makes the following assumptions about the
|
||||||
hardware platform.
|
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
|
* The platform must provide information about PMU event to counter mapping
|
||||||
via device tree or platform specific hooks. Otherwise, SBI PMU extension will
|
via device tree or platform specific hooks. Otherwise, SBI PMU extension will
|
||||||
not be enabled.
|
not be enabled.
|
||||||
@@ -25,7 +22,7 @@ SBI PMU Device Tree Bindings
|
|||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
Platforms may choose to describe PMU event selector and event to counter mapping
|
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
|
values via device tree. The following sections describe the PMU DT node
|
||||||
bindings in details.
|
bindings in details.
|
||||||
|
|
||||||
* **compatible** (Mandatory) - The compatible string of SBI PMU device tree node.
|
* **compatible** (Mandatory) - The compatible string of SBI PMU device tree node.
|
||||||
@@ -42,21 +39,21 @@ This property shouldn't encode any raw hardware event.
|
|||||||
* **riscv,event-to-mhpmcounters**(Optional) - It represents a MANY-to-MANY
|
* **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
|
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
|
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
|
a table format where each row represents a certain range of events and
|
||||||
corresponding counters. The first column represents starting of the pmu event id
|
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
|
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
|
represent a bitmap of all the MHPMCOUNTERx. This property is mandatory if
|
||||||
event-to-mhpmevent is present. Otherwise, it can be omitted. This property
|
riscv,event-to-mhpmevent is present. Otherwise, it can be omitted. This property
|
||||||
shouldn't encode any raw event.
|
shouldn't encode any raw event.
|
||||||
|
|
||||||
* **riscv,raw-event-to-mhpmcounters**(Optional) - It represents an ONE-to-MANY
|
* **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
|
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. The encoding of the
|
a bitmap format that can be used to monitor that raw event. The encoding of the
|
||||||
raw events are platform specific. The information is encoded in a table format
|
raw events are platform specific. The information is encoded in a table format
|
||||||
where each row represent the specific raw event(s). The first column is a 64bit
|
where each row represents the specific raw event(s). The first column is a 64bit
|
||||||
match value where the invariant bits of range of events are set. The second
|
match value where the invariant bits of range of events are set. The second
|
||||||
column is a 64 bit mask that will have all the variant bits of the range of
|
column is a 64 bit mask that will have all the variant bits of the range of
|
||||||
events cleared. Every other bits should be set in the mask.
|
events cleared. All other bits should be set in the mask.
|
||||||
The third column is a 32bit value to represent bitmap of all MHPMCOUNTERx that
|
The third column is a 32bit value to represent bitmap of all MHPMCOUNTERx that
|
||||||
can monitor these set of event(s).
|
can monitor these set of event(s).
|
||||||
If a platform directly encodes each raw PMU event as a unique ID, the value of
|
If a platform directly encodes each raw PMU event as a unique ID, the value of
|
||||||
@@ -70,17 +67,17 @@ via platform hooks rather than the device tree.
|
|||||||
```
|
```
|
||||||
pmu {
|
pmu {
|
||||||
compatible = "riscv,pmu";
|
compatible = "riscv,pmu";
|
||||||
riscv,event-to-mhpmevent = <0x0000B 0x0000 0x0001>,
|
riscv,event-to-mhpmevent = <0x0000B 0x0000 0x0001>;
|
||||||
riscv,event-to-mhpmcounters = <0x00001 0x00001 0x00000001>,
|
riscv,event-to-mhpmcounters = <0x00001 0x00001 0x00000001>,
|
||||||
<0x00002 0x00002 0x00000004>,
|
<0x00002 0x00002 0x00000004>,
|
||||||
<0x00003 0x0000A 0x00000ff8>,
|
<0x00003 0x0000A 0x00000ff8>,
|
||||||
<0x10000 0x10033 0x000ff000>,
|
<0x10000 0x10033 0x000ff000>;
|
||||||
/* For event ID 0x0002 */
|
/* For event ID 0x0002 */
|
||||||
riscv,raw-event-to-mhpmcounters = <0x0000 0x0002 0xffffffff 0xffffffff 0x00000f8>,
|
riscv,raw-event-to-mhpmcounters = <0x0000 0x0002 0xffffffff 0xffffffff 0x00000f8>,
|
||||||
/* For event ID 0-4 */
|
/* For event ID 0-4 */
|
||||||
<0x0 0x0 0xffffffff 0xfffffff0 0x00000ff0>,
|
<0x0 0x0 0xffffffff 0xfffffff0 0x00000ff0>,
|
||||||
/* For event ID 0xffffffff0000000f - 0xffffffff000000ff */
|
/* For event ID 0xffffffff0000000f - 0xffffffff000000ff */
|
||||||
<0xffffffff 0x0 0xffffffff 0xffffff0f 0x00000ff0>,
|
<0xffffffff 0x0 0xffffffff 0xffffff0f 0x00000ff0>;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -90,11 +87,123 @@ pmu {
|
|||||||
/*
|
/*
|
||||||
* For HiFive Unmatched board. The encodings can be found here
|
* For HiFive Unmatched board. The encodings can be found here
|
||||||
* https://sifive.cdn.prismic.io/sifive/1a82e600-1f93-4f41-b2d8-86ed8b16acba_fu740-c000-manual-v1p6.pdf
|
* https://sifive.cdn.prismic.io/sifive/1a82e600-1f93-4f41-b2d8-86ed8b16acba_fu740-c000-manual-v1p6.pdf
|
||||||
|
* This example also binds standard SBI PMU hardware id's to U74 PMU event codes, U74 uses bitfield for
|
||||||
|
* events encoding, so several U74 events can be bound to single perf id.
|
||||||
|
* See SBI PMU hardware id's in include/sbi/sbi_ecall_interface.h
|
||||||
*/
|
*/
|
||||||
pmu {
|
pmu {
|
||||||
compatible = "riscv,pmu";
|
compatible = "riscv,pmu";
|
||||||
riscv,raw-event-to-mhpmcounters = <0x0 0x0 0xffffffff 0xfc0000ff 0xc>,
|
riscv,event-to-mhpmevent =
|
||||||
<0x0 0x1 0xffffffff 0xfff800ff 0xc>,
|
/* SBI_PMU_HW_CACHE_REFERENCES -> Instruction cache/ITIM busy | Data cache/DTIM busy */
|
||||||
<0x0 0x2 0xffffffff 0xffffe0ff 0xc>;
|
<0x00003 0x00000000 0x1801>,
|
||||||
|
/* SBI_PMU_HW_CACHE_MISSES -> Instruction cache miss | Data cache miss or memory-mapped I/O access */
|
||||||
|
<0x00004 0x00000000 0x0302>,
|
||||||
|
/* SBI_PMU_HW_BRANCH_INSTRUCTIONS -> Conditional branch retired */
|
||||||
|
<0x00005 0x00000000 0x4000>,
|
||||||
|
/* SBI_PMU_HW_BRANCH_MISSES -> Branch direction misprediction | Branch/jump target misprediction */
|
||||||
|
<0x00006 0x00000000 0x6001>,
|
||||||
|
/* L1D_READ_MISS -> Data cache miss or memory-mapped I/O access */
|
||||||
|
<0x10001 0x00000000 0x0202>,
|
||||||
|
/* L1D_WRITE_ACCESS -> Data cache write-back */
|
||||||
|
<0x10002 0x00000000 0x0402>,
|
||||||
|
/* L1I_READ_ACCESS -> Instruction cache miss */
|
||||||
|
<0x10009 0x00000000 0x0102>,
|
||||||
|
/* LL_READ_MISS -> UTLB miss */
|
||||||
|
<0x10011 0x00000000 0x2002>,
|
||||||
|
/* DTLB_READ_MISS -> Data TLB miss */
|
||||||
|
<0x10019 0x00000000 0x1002>,
|
||||||
|
/* ITLB_READ_MISS-> Instruction TLB miss */
|
||||||
|
<0x10021 0x00000000 0x0802>;
|
||||||
|
riscv,event-to-mhpmcounters = <0x00003 0x00006 0x18>,
|
||||||
|
<0x10001 0x10002 0x18>,
|
||||||
|
<0x10009 0x10009 0x18>,
|
||||||
|
<0x10011 0x10011 0x18>,
|
||||||
|
<0x10019 0x10019 0x18>,
|
||||||
|
<0x10021 0x10021 0x18>;
|
||||||
|
riscv,raw-event-to-mhpmcounters = <0x0 0x0 0xffffffff 0xfc0000ff 0x18>,
|
||||||
|
<0x0 0x1 0xffffffff 0xfff800ff 0x18>,
|
||||||
|
<0x0 0x2 0xffffffff 0xffffe0ff 0x18>;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 3
|
||||||
|
|
||||||
|
```
|
||||||
|
/*
|
||||||
|
* For Andes 45-series platforms. The encodings can be found in the
|
||||||
|
* "Machine Performance Monitoring Event Selector" section
|
||||||
|
* http://www.andestech.com/wp-content/uploads/AX45MP-1C-Rev.-5.0.0-Datasheet.pdf
|
||||||
|
*/
|
||||||
|
pmu {
|
||||||
|
compatible = "riscv,pmu";
|
||||||
|
riscv,event-to-mhpmevent =
|
||||||
|
<0x1 0x0000 0x10>, /* CPU_CYCLES -> Cycle count */
|
||||||
|
<0x2 0x0000 0x20>, /* INSTRUCTIONS -> Retired instruction count */
|
||||||
|
<0x3 0x0000 0x41>, /* CACHE_REFERENCES -> D-Cache access */
|
||||||
|
<0x4 0x0000 0x51>, /* CACHE_MISSES -> D-Cache miss */
|
||||||
|
<0x5 0x0000 0x80>, /* BRANCH_INSTRUCTIONS -> Conditional branch instruction count */
|
||||||
|
<0x6 0x0000 0x02>, /* BRANCH_MISSES -> Misprediction of conditional branches */
|
||||||
|
<0x10000 0x0000 0x61>, /* L1D_READ_ACCESS -> D-Cache load access */
|
||||||
|
<0x10001 0x0000 0x71>, /* L1D_READ_MISS -> D-Cache load miss */
|
||||||
|
<0x10002 0x0000 0x81>, /* L1D_WRITE_ACCESS -> D-Cache store access */
|
||||||
|
<0x10003 0x0000 0x91>, /* L1D_WRITE_MISS -> D-Cache store miss */
|
||||||
|
<0x10008 0x0000 0x21>, /* L1I_READ_ACCESS -> I-Cache access */
|
||||||
|
<0x10009 0x0000 0x31>; /* L1I_READ_MISS -> I-Cache miss */
|
||||||
|
riscv,event-to-mhpmcounters = <0x1 0x6 0x78>,
|
||||||
|
<0x10000 0x10003 0x78>,
|
||||||
|
<0x10008 0x10009 0x78>;
|
||||||
|
riscv,raw-event-to-mhpmcounters =
|
||||||
|
<0x0 0x10 0xffffffff 0xffffffff 0x78>, /* Cycle count */
|
||||||
|
<0x0 0x20 0xffffffff 0xffffffff 0x78>, /* Retired instruction count */
|
||||||
|
<0x0 0x30 0xffffffff 0xffffffff 0x78>, /* Integer load instruction count */
|
||||||
|
<0x0 0x40 0xffffffff 0xffffffff 0x78>, /* Integer store instruction count */
|
||||||
|
<0x0 0x50 0xffffffff 0xffffffff 0x78>, /* Atomic instruction count */
|
||||||
|
<0x0 0x60 0xffffffff 0xffffffff 0x78>, /* System instruction count */
|
||||||
|
<0x0 0x70 0xffffffff 0xffffffff 0x78>, /* Integer computational instruction count */
|
||||||
|
<0x0 0x80 0xffffffff 0xffffffff 0x78>, /* Conditional branch instruction count */
|
||||||
|
<0x0 0x90 0xffffffff 0xffffffff 0x78>, /* Taken conditional branch instruction count */
|
||||||
|
<0x0 0xA0 0xffffffff 0xffffffff 0x78>, /* JAL instruction count */
|
||||||
|
<0x0 0xB0 0xffffffff 0xffffffff 0x78>, /* JALR instruction count */
|
||||||
|
<0x0 0xC0 0xffffffff 0xffffffff 0x78>, /* Return instruction count */
|
||||||
|
<0x0 0xD0 0xffffffff 0xffffffff 0x78>, /* Control transfer instruction count */
|
||||||
|
<0x0 0xE0 0xffffffff 0xffffffff 0x78>, /* EXEC.IT instruction count */
|
||||||
|
<0x0 0xF0 0xffffffff 0xffffffff 0x78>, /* Integer multiplication instruction count */
|
||||||
|
<0x0 0x100 0xffffffff 0xffffffff 0x78>, /* Integer division instruction count */
|
||||||
|
<0x0 0x110 0xffffffff 0xffffffff 0x78>, /* Floating-point load instruction count */
|
||||||
|
<0x0 0x120 0xffffffff 0xffffffff 0x78>, /* Floating-point store instruction count */
|
||||||
|
<0x0 0x130 0xffffffff 0xffffffff 0x78>, /* Floating-point addition/subtraction instruction count */
|
||||||
|
<0x0 0x140 0xffffffff 0xffffffff 0x78>, /* Floating-point multiplication instruction count */
|
||||||
|
<0x0 0x150 0xffffffff 0xffffffff 0x78>, /* Floating-point fused multiply-add instruction count */
|
||||||
|
<0x0 0x160 0xffffffff 0xffffffff 0x78>, /* Floating-point division or square-root instruction count */
|
||||||
|
<0x0 0x170 0xffffffff 0xffffffff 0x78>, /* Other floating-point instruction count */
|
||||||
|
<0x0 0x180 0xffffffff 0xffffffff 0x78>, /* Integer multiplication and add/sub instruction count */
|
||||||
|
<0x0 0x190 0xffffffff 0xffffffff 0x78>, /* Retired operation count */
|
||||||
|
<0x0 0x01 0xffffffff 0xffffffff 0x78>, /* ILM access */
|
||||||
|
<0x0 0x11 0xffffffff 0xffffffff 0x78>, /* DLM access */
|
||||||
|
<0x0 0x21 0xffffffff 0xffffffff 0x78>, /* I-Cache access */
|
||||||
|
<0x0 0x31 0xffffffff 0xffffffff 0x78>, /* I-Cache miss */
|
||||||
|
<0x0 0x41 0xffffffff 0xffffffff 0x78>, /* D-Cache access */
|
||||||
|
<0x0 0x51 0xffffffff 0xffffffff 0x78>, /* D-Cache miss */
|
||||||
|
<0x0 0x61 0xffffffff 0xffffffff 0x78>, /* D-Cache load access */
|
||||||
|
<0x0 0x71 0xffffffff 0xffffffff 0x78>, /* D-Cache load miss */
|
||||||
|
<0x0 0x81 0xffffffff 0xffffffff 0x78>, /* D-Cache store access */
|
||||||
|
<0x0 0x91 0xffffffff 0xffffffff 0x78>, /* D-Cache store miss */
|
||||||
|
<0x0 0xA1 0xffffffff 0xffffffff 0x78>, /* D-Cache writeback */
|
||||||
|
<0x0 0xB1 0xffffffff 0xffffffff 0x78>, /* Cycles waiting for I-Cache fill data */
|
||||||
|
<0x0 0xC1 0xffffffff 0xffffffff 0x78>, /* Cycles waiting for D-Cache fill data */
|
||||||
|
<0x0 0xD1 0xffffffff 0xffffffff 0x78>, /* Uncached fetch data access from bus */
|
||||||
|
<0x0 0xE1 0xffffffff 0xffffffff 0x78>, /* Uncached load data access from bus */
|
||||||
|
<0x0 0xF1 0xffffffff 0xffffffff 0x78>, /* Cycles waiting for uncached fetch data from bus */
|
||||||
|
<0x0 0x101 0xffffffff 0xffffffff 0x78>, /* Cycles waiting for uncached load data from bus */
|
||||||
|
<0x0 0x111 0xffffffff 0xffffffff 0x78>, /* Main ITLB access */
|
||||||
|
<0x0 0x121 0xffffffff 0xffffffff 0x78>, /* Main ITLB miss */
|
||||||
|
<0x0 0x131 0xffffffff 0xffffffff 0x78>, /* Main DTLB access */
|
||||||
|
<0x0 0x141 0xffffffff 0xffffffff 0x78>, /* Main DTLB miss */
|
||||||
|
<0x0 0x151 0xffffffff 0xffffffff 0x78>, /* Cycles waiting for Main ITLB fill data */
|
||||||
|
<0x0 0x161 0xffffffff 0xffffffff 0x78>, /* Pipeline stall cycles caused by Main DTLB miss */
|
||||||
|
<0x0 0x171 0xffffffff 0xffffffff 0x78>, /* Hardware prefetch bus access */
|
||||||
|
<0x0 0x02 0xffffffff 0xffffffff 0x78>, /* Misprediction of conditional branches */
|
||||||
|
<0x0 0x12 0xffffffff 0xffffffff 0x78>, /* Misprediction of taken conditional branches */
|
||||||
|
<0x0 0x22 0xffffffff 0xffffffff 0x78>; /* Misprediction of targets of Return instructions */
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
BIN
docs/riscv_opensbi_logo_final_color.png
Normal file
BIN
docs/riscv_opensbi_logo_final_color.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.6 KiB |
BIN
docs/riscv_opensbi_logo_final_grey.png
Normal file
BIN
docs/riscv_opensbi_logo_final_grey.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.9 KiB |
1
firmware/Kconfig
Normal file
1
firmware/Kconfig
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
@@ -79,43 +79,19 @@ _try_lottery:
|
|||||||
lla t0, __rel_dyn_start
|
lla t0, __rel_dyn_start
|
||||||
lla t1, __rel_dyn_end
|
lla t1, __rel_dyn_end
|
||||||
beq t0, t1, _relocate_done
|
beq t0, t1, _relocate_done
|
||||||
j 5f
|
|
||||||
2:
|
2:
|
||||||
REG_L t5, -(REGBYTES*2)(t0) /* t5 <-- relocation info:type */
|
REG_L t5, REGBYTES(t0) /* t5 <-- relocation info:type */
|
||||||
li t3, R_RISCV_RELATIVE /* reloc type R_RISCV_RELATIVE */
|
li t3, R_RISCV_RELATIVE /* reloc type R_RISCV_RELATIVE */
|
||||||
bne t5, t3, 3f
|
bne t5, t3, 3f
|
||||||
REG_L t3, -(REGBYTES*3)(t0)
|
REG_L t3, 0(t0)
|
||||||
REG_L t5, -(REGBYTES)(t0) /* t5 <-- addend */
|
REG_L t5, (REGBYTES * 2)(t0) /* t5 <-- addend */
|
||||||
add t5, t5, t2
|
add t5, t5, t2
|
||||||
add t3, t3, t2
|
add t3, t3, t2
|
||||||
REG_S t5, 0(t3) /* store runtime address to the GOT entry */
|
REG_S t5, 0(t3) /* store runtime address to the GOT entry */
|
||||||
j 5f
|
|
||||||
|
|
||||||
3:
|
3:
|
||||||
lla t4, __dyn_sym_start
|
addi t0, t0, (REGBYTES * 3)
|
||||||
|
blt t0, t1, 2b
|
||||||
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
|
j _relocate_done
|
||||||
_wait_relocate_copy_done:
|
_wait_relocate_copy_done:
|
||||||
j _wait_for_boot_hart
|
j _wait_for_boot_hart
|
||||||
@@ -128,9 +104,9 @@ _relocate:
|
|||||||
REG_L t1, 0(t1)
|
REG_L t1, 0(t1)
|
||||||
lla t2, _load_start
|
lla t2, _load_start
|
||||||
REG_L t2, 0(t2)
|
REG_L t2, 0(t2)
|
||||||
|
beq t0, t2, _relocate_done
|
||||||
sub t3, t1, t0
|
sub t3, t1, t0
|
||||||
add t3, t3, t2
|
add t3, t3, t2
|
||||||
beq t0, t2, _relocate_done
|
|
||||||
lla t4, _relocate_done
|
lla t4, _relocate_done
|
||||||
sub t4, t4, t2
|
sub t4, t4, t2
|
||||||
add t4, t4, t0
|
add t4, t4, t0
|
||||||
@@ -257,20 +233,28 @@ _bss_zero:
|
|||||||
/* Preload HART details
|
/* Preload HART details
|
||||||
* s7 -> HART Count
|
* s7 -> HART Count
|
||||||
* s8 -> HART Stack Size
|
* s8 -> HART Stack Size
|
||||||
|
* s9 -> Heap Size
|
||||||
|
* s10 -> Heap Offset
|
||||||
*/
|
*/
|
||||||
lla a4, platform
|
lla a4, platform
|
||||||
#if __riscv_xlen > 32
|
#if __riscv_xlen > 32
|
||||||
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
|
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
|
||||||
lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
|
lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
|
||||||
|
lwu s9, SBI_PLATFORM_HEAP_SIZE_OFFSET(a4)
|
||||||
#else
|
#else
|
||||||
lw s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
|
lw s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
|
||||||
lw s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
|
lw s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
|
||||||
|
lw s9, SBI_PLATFORM_HEAP_SIZE_OFFSET(a4)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Setup scratch space for all the HARTs*/
|
/* Setup scratch space for all the HARTs*/
|
||||||
lla tp, _fw_end
|
lla tp, _fw_end
|
||||||
mul a5, s7, s8
|
mul a5, s7, s8
|
||||||
add tp, tp, a5
|
add tp, tp, a5
|
||||||
|
/* Setup heap base address */
|
||||||
|
lla s10, _fw_start
|
||||||
|
sub s10, tp, s10
|
||||||
|
add tp, tp, s9
|
||||||
/* Keep a copy of tp */
|
/* Keep a copy of tp */
|
||||||
add t3, tp, zero
|
add t3, tp, zero
|
||||||
/* Counter */
|
/* Counter */
|
||||||
@@ -285,8 +269,11 @@ _scratch_init:
|
|||||||
* t3 -> the firmware end address
|
* t3 -> the firmware end address
|
||||||
* s7 -> HART count
|
* s7 -> HART count
|
||||||
* s8 -> HART stack size
|
* s8 -> HART stack size
|
||||||
|
* s9 -> Heap Size
|
||||||
|
* s10 -> Heap Offset
|
||||||
*/
|
*/
|
||||||
add tp, t3, zero
|
add tp, t3, zero
|
||||||
|
sub tp, tp, s9
|
||||||
mul a5, s8, t1
|
mul a5, s8, t1
|
||||||
sub tp, tp, a5
|
sub tp, tp, a5
|
||||||
li a5, SBI_SCRATCH_SIZE
|
li a5, SBI_SCRATCH_SIZE
|
||||||
@@ -298,6 +285,16 @@ _scratch_init:
|
|||||||
sub a5, t3, a4
|
sub a5, t3, a4
|
||||||
REG_S a4, SBI_SCRATCH_FW_START_OFFSET(tp)
|
REG_S a4, SBI_SCRATCH_FW_START_OFFSET(tp)
|
||||||
REG_S a5, SBI_SCRATCH_FW_SIZE_OFFSET(tp)
|
REG_S a5, SBI_SCRATCH_FW_SIZE_OFFSET(tp)
|
||||||
|
|
||||||
|
/* Store R/W section's offset in scratch space */
|
||||||
|
lla a5, _fw_rw_start
|
||||||
|
sub a5, a5, a4
|
||||||
|
REG_S a5, SBI_SCRATCH_FW_RW_OFFSET(tp)
|
||||||
|
|
||||||
|
/* Store fw_heap_offset and fw_heap_size in scratch space */
|
||||||
|
REG_S s10, SBI_SCRATCH_FW_HEAP_OFFSET(tp)
|
||||||
|
REG_S s9, SBI_SCRATCH_FW_HEAP_SIZE_OFFSET(tp)
|
||||||
|
|
||||||
/* Store next arg1 in scratch space */
|
/* Store next arg1 in scratch space */
|
||||||
MOV_3R s0, a0, s1, a1, s2, a2
|
MOV_3R s0, a0, s1, a1, s2, a2
|
||||||
call fw_next_arg1
|
call fw_next_arg1
|
||||||
@@ -402,8 +399,8 @@ _fdt_reloc_done:
|
|||||||
/* mark boot hart done */
|
/* mark boot hart done */
|
||||||
li t0, BOOT_STATUS_BOOT_HART_DONE
|
li t0, BOOT_STATUS_BOOT_HART_DONE
|
||||||
lla t1, _boot_status
|
lla t1, _boot_status
|
||||||
REG_S t0, 0(t1)
|
|
||||||
fence rw, rw
|
fence rw, rw
|
||||||
|
REG_S t0, 0(t1)
|
||||||
j _start_warm
|
j _start_warm
|
||||||
|
|
||||||
/* waiting for boot hart to be done (_boot_status == 2) */
|
/* waiting for boot hart to be done (_boot_status == 2) */
|
||||||
@@ -412,9 +409,9 @@ _wait_for_boot_hart:
|
|||||||
lla t1, _boot_status
|
lla t1, _boot_status
|
||||||
REG_L t1, 0(t1)
|
REG_L t1, 0(t1)
|
||||||
/* Reduce the bus traffic so that boot hart may proceed faster */
|
/* Reduce the bus traffic so that boot hart may proceed faster */
|
||||||
nop
|
div t2, t2, zero
|
||||||
nop
|
div t2, t2, zero
|
||||||
nop
|
div t2, t2, zero
|
||||||
bne t0, t1, _wait_for_boot_hart
|
bne t0, t1, _wait_for_boot_hart
|
||||||
|
|
||||||
_start_warm:
|
_start_warm:
|
||||||
@@ -422,9 +419,8 @@ _start_warm:
|
|||||||
li ra, 0
|
li ra, 0
|
||||||
call _reset_regs
|
call _reset_regs
|
||||||
|
|
||||||
/* Disable and clear all interrupts */
|
/* Disable all interrupts */
|
||||||
csrw CSR_MIE, zero
|
csrw CSR_MIE, zero
|
||||||
csrw CSR_MIP, zero
|
|
||||||
|
|
||||||
/* Find HART count and HART stack size */
|
/* Find HART count and HART stack size */
|
||||||
lla a4, platform
|
lla a4, platform
|
||||||
@@ -453,7 +449,6 @@ _start_warm:
|
|||||||
add s9, s9, 4
|
add s9, s9, 4
|
||||||
add a4, a4, 1
|
add a4, a4, 1
|
||||||
blt a4, s7, 1b
|
blt a4, s7, 1b
|
||||||
li a4, -1
|
|
||||||
2: add s6, a4, zero
|
2: add s6, a4, zero
|
||||||
3: bge s6, s7, _start_hang
|
3: bge s6, s7, _start_hang
|
||||||
|
|
||||||
|
@@ -24,27 +24,42 @@
|
|||||||
PROVIDE(_text_end = .);
|
PROVIDE(_text_end = .);
|
||||||
}
|
}
|
||||||
|
|
||||||
. = ALIGN(0x1000); /* Ensure next section is page aligned */
|
|
||||||
|
|
||||||
/* End of the code sections */
|
/* End of the code sections */
|
||||||
|
|
||||||
|
. = ALIGN(0x1000); /* Ensure next section is page aligned */
|
||||||
|
|
||||||
/* Beginning of the read-only data sections */
|
/* Beginning of the read-only data sections */
|
||||||
|
|
||||||
. = ALIGN(0x1000); /* Ensure next section is page aligned */
|
PROVIDE(_rodata_start = .);
|
||||||
|
|
||||||
.rodata :
|
.rodata :
|
||||||
{
|
{
|
||||||
PROVIDE(_rodata_start = .);
|
|
||||||
*(.rodata .rodata.*)
|
*(.rodata .rodata.*)
|
||||||
. = ALIGN(8);
|
. = ALIGN(8);
|
||||||
PROVIDE(_rodata_end = .);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
. = ALIGN(0x1000); /* Ensure next section is page aligned */
|
||||||
|
|
||||||
|
.rela.dyn : {
|
||||||
|
PROVIDE(__rel_dyn_start = .);
|
||||||
|
*(.rela*)
|
||||||
|
PROVIDE(__rel_dyn_end = .);
|
||||||
|
}
|
||||||
|
|
||||||
|
PROVIDE(_rodata_end = .);
|
||||||
|
|
||||||
/* End of the read-only data sections */
|
/* End of the read-only data sections */
|
||||||
|
|
||||||
/* Beginning of the read-write data sections */
|
/*
|
||||||
|
* PMP regions must be to be power-of-2. RX/RW will have separate
|
||||||
|
* regions, so ensure that the split is power-of-2.
|
||||||
|
*/
|
||||||
|
. = ALIGN(1 << LOG2CEIL((SIZEOF(.rodata) + SIZEOF(.text)
|
||||||
|
+ SIZEOF(.dynsym) + SIZEOF(.rela.dyn))));
|
||||||
|
|
||||||
. = ALIGN(0x1000); /* Ensure next section is page aligned */
|
PROVIDE(_fw_rw_start = .);
|
||||||
|
|
||||||
|
/* Beginning of the read-write data sections */
|
||||||
|
|
||||||
.data :
|
.data :
|
||||||
{
|
{
|
||||||
@@ -61,19 +76,6 @@
|
|||||||
PROVIDE(_data_end = .);
|
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 */
|
. = ALIGN(0x1000); /* Ensure next section is page aligned */
|
||||||
|
|
||||||
.bss :
|
.bss :
|
||||||
|
@@ -129,7 +129,7 @@ fw_options:
|
|||||||
REG_L a0, (a0)
|
REG_L a0, (a0)
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.section .entry, "ax", %progbits
|
.section .data
|
||||||
.align 3
|
.align 3
|
||||||
_dynamic_next_arg1:
|
_dynamic_next_arg1:
|
||||||
RISCV_PTR 0x0
|
RISCV_PTR 0x0
|
||||||
|
@@ -90,7 +90,7 @@ fw_options:
|
|||||||
#error "Must define FW_JUMP_ADDR"
|
#error "Must define FW_JUMP_ADDR"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
.section .entry, "ax", %progbits
|
.section .rodata
|
||||||
.align 3
|
.align 3
|
||||||
_jump_addr:
|
_jump_addr:
|
||||||
RISCV_PTR FW_JUMP_ADDR
|
RISCV_PTR FW_JUMP_ADDR
|
||||||
|
@@ -33,14 +33,12 @@ SECTIONS
|
|||||||
PROVIDE(_text_end = .);
|
PROVIDE(_text_end = .);
|
||||||
}
|
}
|
||||||
|
|
||||||
. = ALIGN(0x1000); /* Ensure next section is page aligned */
|
|
||||||
|
|
||||||
/* End of the code sections */
|
/* End of the code sections */
|
||||||
|
|
||||||
/* Beginning of the read-only data sections */
|
|
||||||
|
|
||||||
. = ALIGN(0x1000); /* Ensure next section is page aligned */
|
. = ALIGN(0x1000); /* Ensure next section is page aligned */
|
||||||
|
|
||||||
|
/* Beginning of the read-only data sections */
|
||||||
|
|
||||||
.rodata :
|
.rodata :
|
||||||
{
|
{
|
||||||
PROVIDE(_rodata_start = .);
|
PROVIDE(_rodata_start = .);
|
||||||
@@ -51,10 +49,10 @@ SECTIONS
|
|||||||
|
|
||||||
/* End of the read-only data sections */
|
/* End of the read-only data sections */
|
||||||
|
|
||||||
/* Beginning of the read-write data sections */
|
|
||||||
|
|
||||||
. = ALIGN(0x1000); /* Ensure next section is page aligned */
|
. = ALIGN(0x1000); /* Ensure next section is page aligned */
|
||||||
|
|
||||||
|
/* Beginning of the read-write data sections */
|
||||||
|
|
||||||
.data :
|
.data :
|
||||||
{
|
{
|
||||||
PROVIDE(_data_start = .);
|
PROVIDE(_data_start = .);
|
||||||
|
@@ -78,7 +78,7 @@ _start_hang:
|
|||||||
wfi
|
wfi
|
||||||
j _start_hang
|
j _start_hang
|
||||||
|
|
||||||
.section .entry, "ax", %progbits
|
.section .data
|
||||||
.align 3
|
.align 3
|
||||||
_hart_lottery:
|
_hart_lottery:
|
||||||
RISCV_PTR 0
|
RISCV_PTR 0
|
||||||
|
@@ -8,31 +8,42 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sbi/sbi_ecall_interface.h>
|
#include <sbi/sbi_ecall_interface.h>
|
||||||
|
#include <sbi/sbi_string.h>
|
||||||
|
|
||||||
#define SBI_ECALL(__eid, __fid, __a0, __a1, __a2) \
|
struct sbiret {
|
||||||
({ \
|
unsigned long error;
|
||||||
register unsigned long a0 asm("a0") = (unsigned long)(__a0); \
|
unsigned long value;
|
||||||
register unsigned long a1 asm("a1") = (unsigned long)(__a1); \
|
};
|
||||||
register unsigned long a2 asm("a2") = (unsigned long)(__a2); \
|
|
||||||
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"(a6), "r"(a7) \
|
|
||||||
: "memory"); \
|
|
||||||
a0; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define SBI_ECALL_0(__eid, __fid) SBI_ECALL(__eid, __fid, 0, 0, 0)
|
struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
|
||||||
#define SBI_ECALL_1(__eid, __fid, __a0) SBI_ECALL(__eid, __fid, __a0, 0, 0)
|
unsigned long arg1, unsigned long arg2,
|
||||||
#define SBI_ECALL_2(__eid, __fid, __a0, __a1) SBI_ECALL(__eid, __fid, __a0, __a1, 0)
|
unsigned long arg3, unsigned long arg4,
|
||||||
|
unsigned long arg5)
|
||||||
|
{
|
||||||
|
struct sbiret ret;
|
||||||
|
|
||||||
#define sbi_ecall_console_putc(c) SBI_ECALL_1(SBI_EXT_0_1_CONSOLE_PUTCHAR, 0, (c))
|
register unsigned long a0 asm ("a0") = (unsigned long)(arg0);
|
||||||
|
register unsigned long a1 asm ("a1") = (unsigned long)(arg1);
|
||||||
|
register unsigned long a2 asm ("a2") = (unsigned long)(arg2);
|
||||||
|
register unsigned long a3 asm ("a3") = (unsigned long)(arg3);
|
||||||
|
register unsigned long a4 asm ("a4") = (unsigned long)(arg4);
|
||||||
|
register unsigned long a5 asm ("a5") = (unsigned long)(arg5);
|
||||||
|
register unsigned long a6 asm ("a6") = (unsigned long)(fid);
|
||||||
|
register unsigned long a7 asm ("a7") = (unsigned long)(ext);
|
||||||
|
asm volatile ("ecall"
|
||||||
|
: "+r" (a0), "+r" (a1)
|
||||||
|
: "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7)
|
||||||
|
: "memory");
|
||||||
|
ret.error = a0;
|
||||||
|
ret.value = a1;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void sbi_ecall_console_puts(const char *str)
|
static inline void sbi_ecall_console_puts(const char *str)
|
||||||
{
|
{
|
||||||
while (str && *str)
|
sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_WRITE,
|
||||||
sbi_ecall_console_putc(*str++);
|
sbi_strlen(str), (unsigned long)str, 0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define wfi() \
|
#define wfi() \
|
||||||
|
@@ -181,6 +181,12 @@ int misa_xlen(void);
|
|||||||
/* Get RISC-V ISA string representation */
|
/* Get RISC-V ISA string representation */
|
||||||
void misa_string(int xlen, char *out, unsigned int out_sz);
|
void misa_string(int xlen, char *out, unsigned int out_sz);
|
||||||
|
|
||||||
|
/* Disable pmp entry at a given index */
|
||||||
|
int pmp_disable(unsigned int n);
|
||||||
|
|
||||||
|
/* Check if the matching field is set */
|
||||||
|
int is_pmp_entry_mapped(unsigned long entry);
|
||||||
|
|
||||||
int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
|
int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
|
||||||
unsigned long log2len);
|
unsigned long log2len);
|
||||||
|
|
||||||
|
@@ -39,14 +39,14 @@ unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
|
|||||||
unsigned long atomic_raw_xchg_ulong(volatile unsigned long *ptr,
|
unsigned long atomic_raw_xchg_ulong(volatile unsigned long *ptr,
|
||||||
unsigned long newval);
|
unsigned long newval);
|
||||||
/**
|
/**
|
||||||
* Set a bit in an atomic variable and return the new value.
|
* Set a bit in an atomic variable and return the value of bit before modify.
|
||||||
* @nr : Bit to set.
|
* @nr : Bit to set.
|
||||||
* @atom: atomic variable to modify
|
* @atom: atomic variable to modify
|
||||||
*/
|
*/
|
||||||
int atomic_set_bit(int nr, atomic_t *atom);
|
int atomic_set_bit(int nr, atomic_t *atom);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear a bit in an atomic variable and return the new value.
|
* Clear a bit in an atomic variable and return the value of bit before modify.
|
||||||
* @nr : Bit to set.
|
* @nr : Bit to set.
|
||||||
* @atom: atomic variable to modify
|
* @atom: atomic variable to modify
|
||||||
*/
|
*/
|
||||||
@@ -54,14 +54,14 @@ int atomic_set_bit(int nr, atomic_t *atom);
|
|||||||
int atomic_clear_bit(int nr, atomic_t *atom);
|
int atomic_clear_bit(int nr, atomic_t *atom);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a bit in any address and return the new value .
|
* Set a bit in any address and return the value of bit before modify.
|
||||||
* @nr : Bit to set.
|
* @nr : Bit to set.
|
||||||
* @addr: Address to modify
|
* @addr: Address to modify
|
||||||
*/
|
*/
|
||||||
int atomic_raw_set_bit(int nr, volatile unsigned long *addr);
|
int atomic_raw_set_bit(int nr, volatile unsigned long *addr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear a bit in any address and return the new value .
|
* Clear a bit in any address and return the value of bit before modify.
|
||||||
* @nr : Bit to set.
|
* @nr : Bit to set.
|
||||||
* @addr: Address to modify
|
* @addr: Address to modify
|
||||||
*/
|
*/
|
||||||
|
@@ -1,14 +1,6 @@
|
|||||||
#ifndef __RISCV_ELF_H__
|
#ifndef __RISCV_ELF_H__
|
||||||
#define __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 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
|
#endif
|
||||||
|
@@ -38,10 +38,14 @@
|
|||||||
#define MSTATUS_SXL _ULL(0x0000000C00000000)
|
#define MSTATUS_SXL _ULL(0x0000000C00000000)
|
||||||
#define MSTATUS_SBE _ULL(0x0000001000000000)
|
#define MSTATUS_SBE _ULL(0x0000001000000000)
|
||||||
#define MSTATUS_MBE _ULL(0x0000002000000000)
|
#define MSTATUS_MBE _ULL(0x0000002000000000)
|
||||||
|
#define MSTATUS_GVA _ULL(0x0000004000000000)
|
||||||
|
#define MSTATUS_GVA_SHIFT 38
|
||||||
#define MSTATUS_MPV _ULL(0x0000008000000000)
|
#define MSTATUS_MPV _ULL(0x0000008000000000)
|
||||||
#else
|
#else
|
||||||
#define MSTATUSH_SBE _UL(0x00000010)
|
#define MSTATUSH_SBE _UL(0x00000010)
|
||||||
#define MSTATUSH_MBE _UL(0x00000020)
|
#define MSTATUSH_MBE _UL(0x00000020)
|
||||||
|
#define MSTATUSH_GVA _UL(0x00000040)
|
||||||
|
#define MSTATUSH_GVA_SHIFT 6
|
||||||
#define MSTATUSH_MPV _UL(0x00000080)
|
#define MSTATUSH_MPV _UL(0x00000080)
|
||||||
#endif
|
#endif
|
||||||
#define MSTATUS32_SD _UL(0x80000000)
|
#define MSTATUS32_SD _UL(0x80000000)
|
||||||
@@ -203,13 +207,8 @@
|
|||||||
|
|
||||||
#define MHPMEVENT_SSCOF_MASK _ULL(0xFFFF000000000000)
|
#define MHPMEVENT_SSCOF_MASK _ULL(0xFFFF000000000000)
|
||||||
|
|
||||||
#if __riscv_xlen > 32
|
|
||||||
#define ENVCFG_STCE (_ULL(1) << 63)
|
#define ENVCFG_STCE (_ULL(1) << 63)
|
||||||
#define ENVCFG_PBMTE (_ULL(1) << 62)
|
#define ENVCFG_PBMTE (_ULL(1) << 62)
|
||||||
#else
|
|
||||||
#define ENVCFGH_STCE (_UL(1) << 31)
|
|
||||||
#define ENVCFGH_PBMTE (_UL(1) << 30)
|
|
||||||
#endif
|
|
||||||
#define ENVCFG_CBZE (_UL(1) << 7)
|
#define ENVCFG_CBZE (_UL(1) << 7)
|
||||||
#define ENVCFG_CBCFE (_UL(1) << 6)
|
#define ENVCFG_CBCFE (_UL(1) << 6)
|
||||||
#define ENVCFG_CBIE_SHIFT 4
|
#define ENVCFG_CBIE_SHIFT 4
|
||||||
@@ -308,8 +307,6 @@
|
|||||||
|
|
||||||
/* Supervisor Trap Setup */
|
/* Supervisor Trap Setup */
|
||||||
#define CSR_SSTATUS 0x100
|
#define CSR_SSTATUS 0x100
|
||||||
#define CSR_SEDELEG 0x102
|
|
||||||
#define CSR_SIDELEG 0x103
|
|
||||||
#define CSR_SIE 0x104
|
#define CSR_SIE 0x104
|
||||||
#define CSR_STVEC 0x105
|
#define CSR_STVEC 0x105
|
||||||
#define CSR_SCOUNTEREN 0x106
|
#define CSR_SCOUNTEREN 0x106
|
||||||
@@ -428,6 +425,7 @@
|
|||||||
#define CSR_MARCHID 0xf12
|
#define CSR_MARCHID 0xf12
|
||||||
#define CSR_MIMPID 0xf13
|
#define CSR_MIMPID 0xf13
|
||||||
#define CSR_MHARTID 0xf14
|
#define CSR_MHARTID 0xf14
|
||||||
|
#define CSR_MCONFIGPTR 0xf15
|
||||||
|
|
||||||
/* Machine Trap Setup */
|
/* Machine Trap Setup */
|
||||||
#define CSR_MSTATUS 0x300
|
#define CSR_MSTATUS 0x300
|
||||||
@@ -600,6 +598,8 @@
|
|||||||
|
|
||||||
/* Machine Counter Setup */
|
/* Machine Counter Setup */
|
||||||
#define CSR_MCOUNTINHIBIT 0x320
|
#define CSR_MCOUNTINHIBIT 0x320
|
||||||
|
#define CSR_MCYCLECFG 0x321
|
||||||
|
#define CSR_MINSTRETCFG 0x322
|
||||||
#define CSR_MHPMEVENT3 0x323
|
#define CSR_MHPMEVENT3 0x323
|
||||||
#define CSR_MHPMEVENT4 0x324
|
#define CSR_MHPMEVENT4 0x324
|
||||||
#define CSR_MHPMEVENT5 0x325
|
#define CSR_MHPMEVENT5 0x325
|
||||||
@@ -631,6 +631,8 @@
|
|||||||
#define CSR_MHPMEVENT31 0x33f
|
#define CSR_MHPMEVENT31 0x33f
|
||||||
|
|
||||||
/* For RV32 */
|
/* For RV32 */
|
||||||
|
#define CSR_MCYCLECFGH 0x721
|
||||||
|
#define CSR_MINSTRETCFGH 0x722
|
||||||
#define CSR_MHPMEVENT3H 0x723
|
#define CSR_MHPMEVENT3H 0x723
|
||||||
#define CSR_MHPMEVENT4H 0x724
|
#define CSR_MHPMEVENT4H 0x724
|
||||||
#define CSR_MHPMEVENT5H 0x725
|
#define CSR_MHPMEVENT5H 0x725
|
||||||
@@ -661,6 +663,21 @@
|
|||||||
#define CSR_MHPMEVENT30H 0x73e
|
#define CSR_MHPMEVENT30H 0x73e
|
||||||
#define CSR_MHPMEVENT31H 0x73f
|
#define CSR_MHPMEVENT31H 0x73f
|
||||||
|
|
||||||
|
/* Machine Security Configuration CSR (mseccfg) */
|
||||||
|
#define CSR_MSECCFG 0x747
|
||||||
|
#define CSR_MSECCFGH 0x757
|
||||||
|
|
||||||
|
#define MSECCFG_MML_SHIFT (0)
|
||||||
|
#define MSECCFG_MML (_UL(1) << MSECCFG_MML_SHIFT)
|
||||||
|
#define MSECCFG_MMWP_SHIFT (1)
|
||||||
|
#define MSECCFG_MMWP (_UL(1) << MSECCFG_MMWP_SHIFT)
|
||||||
|
#define MSECCFG_RLB_SHIFT (2)
|
||||||
|
#define MSECCFG_RLB (_UL(1) << MSECCFG_RLB_SHIFT)
|
||||||
|
#define MSECCFG_USEED_SHIFT (8)
|
||||||
|
#define MSECCFG_USEED (_UL(1) << MSECCFG_USEED_SHIFT)
|
||||||
|
#define MSECCFG_SSEED_SHIFT (9)
|
||||||
|
#define MSECCFG_SSEED (_UL(1) << MSECCFG_SSEED_SHIFT)
|
||||||
|
|
||||||
/* Counter Overflow CSR */
|
/* Counter Overflow CSR */
|
||||||
#define CSR_SCOUNTOVF 0xda0
|
#define CSR_SCOUNTOVF 0xda0
|
||||||
|
|
||||||
@@ -734,6 +751,8 @@
|
|||||||
#define SMSTATEEN0_CS (_ULL(1) << SMSTATEEN0_CS_SHIFT)
|
#define SMSTATEEN0_CS (_ULL(1) << SMSTATEEN0_CS_SHIFT)
|
||||||
#define SMSTATEEN0_FCSR_SHIFT 1
|
#define SMSTATEEN0_FCSR_SHIFT 1
|
||||||
#define SMSTATEEN0_FCSR (_ULL(1) << SMSTATEEN0_FCSR_SHIFT)
|
#define SMSTATEEN0_FCSR (_ULL(1) << SMSTATEEN0_FCSR_SHIFT)
|
||||||
|
#define SMSTATEEN0_CONTEXT_SHIFT 57
|
||||||
|
#define SMSTATEEN0_CONTEXT (_ULL(1) << SMSTATEEN0_CONTEXT_SHIFT)
|
||||||
#define SMSTATEEN0_IMSIC_SHIFT 58
|
#define SMSTATEEN0_IMSIC_SHIFT 58
|
||||||
#define SMSTATEEN0_IMSIC (_ULL(1) << SMSTATEEN0_IMSIC_SHIFT)
|
#define SMSTATEEN0_IMSIC (_ULL(1) << SMSTATEEN0_IMSIC_SHIFT)
|
||||||
#define SMSTATEEN0_AIA_SHIFT 59
|
#define SMSTATEEN0_AIA_SHIFT 59
|
||||||
|
@@ -84,7 +84,7 @@
|
|||||||
#define GET_FFLAGS() csr_read(CSR_FFLAGS)
|
#define GET_FFLAGS() csr_read(CSR_FFLAGS)
|
||||||
#define SET_FFLAGS(value) csr_write(CSR_FFLAGS, (value))
|
#define SET_FFLAGS(value) csr_write(CSR_FFLAGS, (value))
|
||||||
|
|
||||||
#define SET_FS_DIRTY() ((void)0)
|
#define SET_FS_DIRTY(regs) (regs->mstatus |= MSTATUS_FS)
|
||||||
|
|
||||||
#define GET_F32_RS1(insn, regs) (GET_F32_REG(insn, 15, regs))
|
#define GET_F32_RS1(insn, regs) (GET_F32_REG(insn, 15, regs))
|
||||||
#define GET_F32_RS2(insn, regs) (GET_F32_REG(insn, 20, regs))
|
#define GET_F32_RS2(insn, regs) (GET_F32_REG(insn, 20, regs))
|
||||||
@@ -93,9 +93,9 @@
|
|||||||
#define GET_F64_RS2(insn, regs) (GET_F64_REG(insn, 20, regs))
|
#define GET_F64_RS2(insn, regs) (GET_F64_REG(insn, 20, regs))
|
||||||
#define GET_F64_RS3(insn, regs) (GET_F64_REG(insn, 27, regs))
|
#define GET_F64_RS3(insn, regs) (GET_F64_REG(insn, 27, regs))
|
||||||
#define SET_F32_RD(insn, regs, val) \
|
#define SET_F32_RD(insn, regs, val) \
|
||||||
(SET_F32_REG(insn, 7, regs, val), SET_FS_DIRTY())
|
(SET_F32_REG(insn, 7, regs, val), SET_FS_DIRTY(regs))
|
||||||
#define SET_F64_RD(insn, regs, val) \
|
#define SET_F64_RD(insn, regs, val) \
|
||||||
(SET_F64_REG(insn, 7, regs, val), SET_FS_DIRTY())
|
(SET_F64_REG(insn, 7, regs, val), SET_FS_DIRTY(regs))
|
||||||
|
|
||||||
#define GET_F32_RS2C(insn, regs) (GET_F32_REG(insn, 2, regs))
|
#define GET_F32_RS2C(insn, regs) (GET_F32_REG(insn, 2, regs))
|
||||||
#define GET_F32_RS2S(insn, regs) (GET_F32_REG(RVC_RS2S(insn), 0, regs))
|
#define GET_F32_RS2S(insn, regs) (GET_F32_REG(RVC_RS2S(insn), 0, regs))
|
||||||
|
@@ -12,13 +12,7 @@
|
|||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
#if __SIZEOF_POINTER__ == 8
|
#define BITS_PER_LONG (8 * __SIZEOF_LONG__)
|
||||||
#define BITS_PER_LONG 64
|
|
||||||
#elif __SIZEOF_POINTER__ == 4
|
|
||||||
#define BITS_PER_LONG 32
|
|
||||||
#else
|
|
||||||
#error "Unexpected __SIZEOF_POINTER__"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define EXTRACT_FIELD(val, which) \
|
#define EXTRACT_FIELD(val, which) \
|
||||||
(((val) & (which)) / ((which) & ~((which)-1)))
|
(((val) & (which)) / ((which) & ~((which)-1)))
|
||||||
@@ -32,6 +26,7 @@
|
|||||||
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
|
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
|
||||||
#define BIT_WORD(bit) ((bit) / BITS_PER_LONG)
|
#define BIT_WORD(bit) ((bit) / BITS_PER_LONG)
|
||||||
#define BIT_WORD_OFFSET(bit) ((bit) & (BITS_PER_LONG - 1))
|
#define BIT_WORD_OFFSET(bit) ((bit) & (BITS_PER_LONG - 1))
|
||||||
|
#define BIT_ALIGN(bit, align) (((bit) + ((align) - 1)) & ~((align) - 1))
|
||||||
|
|
||||||
#define GENMASK(h, l) \
|
#define GENMASK(h, l) \
|
||||||
(((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
|
(((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
|
||||||
@@ -118,6 +113,22 @@ static inline unsigned long sbi_fls(unsigned long word)
|
|||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sbi_popcount - find the number of set bit in a long word
|
||||||
|
* @word: the word to search
|
||||||
|
*/
|
||||||
|
static inline unsigned long sbi_popcount(unsigned long word)
|
||||||
|
{
|
||||||
|
unsigned long count = 0;
|
||||||
|
|
||||||
|
while (word) {
|
||||||
|
word &= word - 1;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
#define for_each_set_bit(bit, addr, size) \
|
#define for_each_set_bit(bit, addr, size) \
|
||||||
for ((bit) = find_first_bit((addr), (size)); \
|
for ((bit) = find_first_bit((addr), (size)); \
|
||||||
(bit) < (size); \
|
(bit) < (size); \
|
||||||
|
61
include/sbi/sbi_byteorder.h
Normal file
61
include/sbi/sbi_byteorder.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Ventana Micro Systems Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SBI_BYTEORDER_H__
|
||||||
|
#define __SBI_BYTEORDER_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
#define BSWAP16(x) ((((x) & 0x00ff) << 8) | \
|
||||||
|
(((x) & 0xff00) >> 8))
|
||||||
|
#define BSWAP32(x) ((((x) & 0x000000ff) << 24) | \
|
||||||
|
(((x) & 0x0000ff00) << 8) | \
|
||||||
|
(((x) & 0x00ff0000) >> 8) | \
|
||||||
|
(((x) & 0xff000000) >> 24))
|
||||||
|
#define BSWAP64(x) ((((x) & 0x00000000000000ffULL) << 56) | \
|
||||||
|
(((x) & 0x000000000000ff00ULL) << 40) | \
|
||||||
|
(((x) & 0x0000000000ff0000ULL) << 24) | \
|
||||||
|
(((x) & 0x00000000ff000000ULL) << 8) | \
|
||||||
|
(((x) & 0x000000ff00000000ULL) >> 8) | \
|
||||||
|
(((x) & 0x0000ff0000000000ULL) >> 24) | \
|
||||||
|
(((x) & 0x00ff000000000000ULL) >> 40) | \
|
||||||
|
(((x) & 0xff00000000000000ULL) >> 56))
|
||||||
|
|
||||||
|
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ /* CPU(little-endian) */
|
||||||
|
#define cpu_to_be16(x) ((uint16_t)BSWAP16(x))
|
||||||
|
#define cpu_to_be32(x) ((uint32_t)BSWAP32(x))
|
||||||
|
#define cpu_to_be64(x) ((uint64_t)BSWAP64(x))
|
||||||
|
|
||||||
|
#define be16_to_cpu(x) ((uint16_t)BSWAP16(x))
|
||||||
|
#define be32_to_cpu(x) ((uint32_t)BSWAP32(x))
|
||||||
|
#define be64_to_cpu(x) ((uint64_t)BSWAP64(x))
|
||||||
|
|
||||||
|
#define cpu_to_le16(x) ((uint16_t)(x))
|
||||||
|
#define cpu_to_le32(x) ((uint32_t)(x))
|
||||||
|
#define cpu_to_le64(x) ((uint64_t)(x))
|
||||||
|
|
||||||
|
#define le16_to_cpu(x) ((uint16_t)(x))
|
||||||
|
#define le32_to_cpu(x) ((uint32_t)(x))
|
||||||
|
#define le64_to_cpu(x) ((uint64_t)(x))
|
||||||
|
#else /* CPU(big-endian) */
|
||||||
|
#define cpu_to_be16(x) ((uint16_t)(x))
|
||||||
|
#define cpu_to_be32(x) ((uint32_t)(x))
|
||||||
|
#define cpu_to_be64(x) ((uint64_t)(x))
|
||||||
|
|
||||||
|
#define be16_to_cpu(x) ((uint16_t)(x))
|
||||||
|
#define be32_to_cpu(x) ((uint32_t)(x))
|
||||||
|
#define be64_to_cpu(x) ((uint64_t)(x))
|
||||||
|
|
||||||
|
#define cpu_to_le16(x) ((uint16_t)BSWAP16(x))
|
||||||
|
#define cpu_to_le32(x) ((uint32_t)BSWAP32(x))
|
||||||
|
#define cpu_to_le64(x) ((uint64_t)BSWAP64(x))
|
||||||
|
|
||||||
|
#define le16_to_cpu(x) ((uint16_t)BSWAP16(x))
|
||||||
|
#define le32_to_cpu(x) ((uint32_t)BSWAP32(x))
|
||||||
|
#define le64_to_cpu(x) ((uint64_t)BSWAP64(x))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __SBI_BYTEORDER_H__ */
|
@@ -19,6 +19,9 @@ struct sbi_console_device {
|
|||||||
/** Write a character to the console output */
|
/** Write a character to the console output */
|
||||||
void (*console_putc)(char ch);
|
void (*console_putc)(char ch);
|
||||||
|
|
||||||
|
/** Write a character string to the console output */
|
||||||
|
unsigned long (*console_puts)(const char *str, unsigned long len);
|
||||||
|
|
||||||
/** Read a character from the console input */
|
/** Read a character from the console input */
|
||||||
int (*console_getc)(void);
|
int (*console_getc)(void);
|
||||||
};
|
};
|
||||||
@@ -33,8 +36,12 @@ void sbi_putc(char ch);
|
|||||||
|
|
||||||
void sbi_puts(const char *str);
|
void sbi_puts(const char *str);
|
||||||
|
|
||||||
|
unsigned long sbi_nputs(const char *str, unsigned long len);
|
||||||
|
|
||||||
void sbi_gets(char *s, int maxwidth, char endchar);
|
void sbi_gets(char *s, int maxwidth, char endchar);
|
||||||
|
|
||||||
|
unsigned long sbi_ngets(char *str, unsigned long len);
|
||||||
|
|
||||||
int __printf(2, 3) sbi_sprintf(char *out, const char *format, ...);
|
int __printf(2, 3) sbi_sprintf(char *out, const char *format, ...);
|
||||||
|
|
||||||
int __printf(3, 4) sbi_snprintf(char *out, u32 out_sz, const char *format, ...);
|
int __printf(3, 4) sbi_snprintf(char *out, u32 out_sz, const char *format, ...);
|
||||||
|
35
include/sbi/sbi_cppc.h
Normal file
35
include/sbi/sbi_cppc.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Ventana Micro Systems Inc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SBI_CPPC_H__
|
||||||
|
#define __SBI_CPPC_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
/** CPPC device */
|
||||||
|
struct sbi_cppc_device {
|
||||||
|
/** Name of the CPPC device */
|
||||||
|
char name[32];
|
||||||
|
|
||||||
|
/** probe - returns register width if implemented, 0 otherwise */
|
||||||
|
int (*cppc_probe)(unsigned long reg);
|
||||||
|
|
||||||
|
/** read the cppc register*/
|
||||||
|
int (*cppc_read)(unsigned long reg, uint64_t *val);
|
||||||
|
|
||||||
|
/** write to the cppc register*/
|
||||||
|
int (*cppc_write)(unsigned long reg, uint64_t val);
|
||||||
|
};
|
||||||
|
|
||||||
|
int sbi_cppc_probe(unsigned long reg);
|
||||||
|
int sbi_cppc_read(unsigned long reg, uint64_t *val);
|
||||||
|
int sbi_cppc_write(unsigned long reg, uint64_t val);
|
||||||
|
|
||||||
|
const struct sbi_cppc_device *sbi_cppc_get_device(void);
|
||||||
|
void sbi_cppc_set_device(const struct sbi_cppc_device *dev);
|
||||||
|
|
||||||
|
#endif
|
@@ -36,11 +36,121 @@ struct sbi_domain_memregion {
|
|||||||
*/
|
*/
|
||||||
unsigned long base;
|
unsigned long base;
|
||||||
/** Flags representing memory region attributes */
|
/** Flags representing memory region attributes */
|
||||||
#define SBI_DOMAIN_MEMREGION_READABLE (1UL << 0)
|
#define SBI_DOMAIN_MEMREGION_M_READABLE (1UL << 0)
|
||||||
#define SBI_DOMAIN_MEMREGION_WRITEABLE (1UL << 1)
|
#define SBI_DOMAIN_MEMREGION_M_WRITABLE (1UL << 1)
|
||||||
#define SBI_DOMAIN_MEMREGION_EXECUTABLE (1UL << 2)
|
#define SBI_DOMAIN_MEMREGION_M_EXECUTABLE (1UL << 2)
|
||||||
#define SBI_DOMAIN_MEMREGION_MMODE (1UL << 3)
|
#define SBI_DOMAIN_MEMREGION_SU_READABLE (1UL << 3)
|
||||||
#define SBI_DOMAIN_MEMREGION_ACCESS_MASK (0xfUL)
|
#define SBI_DOMAIN_MEMREGION_SU_WRITABLE (1UL << 4)
|
||||||
|
#define SBI_DOMAIN_MEMREGION_SU_EXECUTABLE (1UL << 5)
|
||||||
|
|
||||||
|
#define SBI_DOMAIN_MEMREGION_ACCESS_MASK (0x3fUL)
|
||||||
|
#define SBI_DOMAIN_MEMREGION_M_ACCESS_MASK (0x7UL)
|
||||||
|
#define SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK (0x38UL)
|
||||||
|
|
||||||
|
#define SBI_DOMAIN_MEMREGION_SU_ACCESS_SHIFT (3)
|
||||||
|
|
||||||
|
#define SBI_DOMAIN_MEMREGION_SHARED_RDONLY \
|
||||||
|
(SBI_DOMAIN_MEMREGION_M_READABLE | \
|
||||||
|
SBI_DOMAIN_MEMREGION_SU_READABLE)
|
||||||
|
|
||||||
|
#define SBI_DOMAIN_MEMREGION_SHARED_SUX_MRX \
|
||||||
|
(SBI_DOMAIN_MEMREGION_M_READABLE | \
|
||||||
|
SBI_DOMAIN_MEMREGION_M_EXECUTABLE | \
|
||||||
|
SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
|
||||||
|
|
||||||
|
#define SBI_DOMAIN_MEMREGION_SHARED_SUX_MX \
|
||||||
|
(SBI_DOMAIN_MEMREGION_M_EXECUTABLE | \
|
||||||
|
SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
|
||||||
|
|
||||||
|
#define SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW \
|
||||||
|
(SBI_DOMAIN_MEMREGION_M_READABLE | \
|
||||||
|
SBI_DOMAIN_MEMREGION_M_WRITABLE | \
|
||||||
|
SBI_DOMAIN_MEMREGION_SU_READABLE| \
|
||||||
|
SBI_DOMAIN_MEMREGION_SU_WRITABLE)
|
||||||
|
|
||||||
|
#define SBI_DOMAIN_MEMREGION_SHARED_SUR_MRW \
|
||||||
|
(SBI_DOMAIN_MEMREGION_M_READABLE | \
|
||||||
|
SBI_DOMAIN_MEMREGION_M_WRITABLE | \
|
||||||
|
SBI_DOMAIN_MEMREGION_SU_READABLE)
|
||||||
|
|
||||||
|
/* Shared read-only region between M and SU mode */
|
||||||
|
#define SBI_DOMAIN_MEMREGION_IS_SUR_MR(__flags) \
|
||||||
|
((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \
|
||||||
|
SBI_DOMAIN_MEMREGION_SHARED_RDONLY)
|
||||||
|
|
||||||
|
/* Shared region: SU execute-only and M read/execute */
|
||||||
|
#define SBI_DOMAIN_MEMREGION_IS_SUX_MRX(__flags) \
|
||||||
|
((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \
|
||||||
|
SBI_DOMAIN_MEMREGION_SHARED_SUX_MRX)
|
||||||
|
|
||||||
|
/* Shared region: SU and M execute-only */
|
||||||
|
#define SBI_DOMAIN_MEMREGION_IS_SUX_MX(__flags) \
|
||||||
|
((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \
|
||||||
|
SBI_DOMAIN_MEMREGION_SHARED_SUX_MX)
|
||||||
|
|
||||||
|
/* Shared region: SU and M read/write */
|
||||||
|
#define SBI_DOMAIN_MEMREGION_IS_SURW_MRW(__flags) \
|
||||||
|
((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \
|
||||||
|
SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW)
|
||||||
|
|
||||||
|
/* Shared region: SU read-only and M read/write */
|
||||||
|
#define SBI_DOMAIN_MEMREGION_IS_SUR_MRW(__flags) \
|
||||||
|
((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \
|
||||||
|
SBI_DOMAIN_MEMREGION_SHARED_SUR_MRW)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if region flags match with any of the above
|
||||||
|
* mentioned shared region type
|
||||||
|
*/
|
||||||
|
#define SBI_DOMAIN_MEMREGION_IS_SHARED(_flags) \
|
||||||
|
(SBI_DOMAIN_MEMREGION_IS_SUR_MR(_flags) || \
|
||||||
|
SBI_DOMAIN_MEMREGION_IS_SUX_MRX(_flags) || \
|
||||||
|
SBI_DOMAIN_MEMREGION_IS_SUX_MX(_flags) || \
|
||||||
|
SBI_DOMAIN_MEMREGION_IS_SURW_MRW(_flags)|| \
|
||||||
|
SBI_DOMAIN_MEMREGION_IS_SUR_MRW(_flags))
|
||||||
|
|
||||||
|
#define SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(__flags) \
|
||||||
|
((__flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK) && \
|
||||||
|
!(__flags & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK))
|
||||||
|
|
||||||
|
#define SBI_DOMAIN_MEMREGION_SU_ONLY_ACCESS(__flags) \
|
||||||
|
((__flags & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK) && \
|
||||||
|
!(__flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK))
|
||||||
|
|
||||||
|
/** Bit to control if permissions are enforced on all modes */
|
||||||
|
#define SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS (1UL << 6)
|
||||||
|
|
||||||
|
#define SBI_DOMAIN_MEMREGION_M_RWX \
|
||||||
|
(SBI_DOMAIN_MEMREGION_M_READABLE | \
|
||||||
|
SBI_DOMAIN_MEMREGION_M_WRITABLE | \
|
||||||
|
SBI_DOMAIN_MEMREGION_M_EXECUTABLE)
|
||||||
|
|
||||||
|
#define SBI_DOMAIN_MEMREGION_SU_RWX \
|
||||||
|
(SBI_DOMAIN_MEMREGION_SU_READABLE | \
|
||||||
|
SBI_DOMAIN_MEMREGION_SU_WRITABLE | \
|
||||||
|
SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
|
||||||
|
|
||||||
|
/* Unrestricted M-mode accesses but enfoced on SU-mode */
|
||||||
|
#define SBI_DOMAIN_MEMREGION_READABLE \
|
||||||
|
(SBI_DOMAIN_MEMREGION_SU_READABLE | \
|
||||||
|
SBI_DOMAIN_MEMREGION_M_RWX)
|
||||||
|
#define SBI_DOMAIN_MEMREGION_WRITEABLE \
|
||||||
|
(SBI_DOMAIN_MEMREGION_SU_WRITABLE | \
|
||||||
|
SBI_DOMAIN_MEMREGION_M_RWX)
|
||||||
|
#define SBI_DOMAIN_MEMREGION_EXECUTABLE \
|
||||||
|
(SBI_DOMAIN_MEMREGION_SU_EXECUTABLE | \
|
||||||
|
SBI_DOMAIN_MEMREGION_M_RWX)
|
||||||
|
|
||||||
|
/* Enforced accesses across all modes */
|
||||||
|
#define SBI_DOMAIN_MEMREGION_ENF_READABLE \
|
||||||
|
(SBI_DOMAIN_MEMREGION_SU_READABLE | \
|
||||||
|
SBI_DOMAIN_MEMREGION_M_READABLE)
|
||||||
|
#define SBI_DOMAIN_MEMREGION_ENF_WRITABLE \
|
||||||
|
(SBI_DOMAIN_MEMREGION_SU_WRITABLE | \
|
||||||
|
SBI_DOMAIN_MEMREGION_M_WRITABLE)
|
||||||
|
#define SBI_DOMAIN_MEMREGION_ENF_EXECUTABLE \
|
||||||
|
(SBI_DOMAIN_MEMREGION_SU_EXECUTABLE | \
|
||||||
|
SBI_DOMAIN_MEMREGION_M_EXECUTABLE)
|
||||||
|
|
||||||
#define SBI_DOMAIN_MEMREGION_MMIO (1UL << 31)
|
#define SBI_DOMAIN_MEMREGION_MMIO (1UL << 31)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
@@ -78,21 +188,21 @@ struct sbi_domain {
|
|||||||
unsigned long next_mode;
|
unsigned long next_mode;
|
||||||
/** Is domain allowed to reset the system */
|
/** Is domain allowed to reset the system */
|
||||||
bool system_reset_allowed;
|
bool system_reset_allowed;
|
||||||
|
/** Is domain allowed to suspend the system */
|
||||||
|
bool system_suspend_allowed;
|
||||||
|
/** Identifies whether to include the firmware region */
|
||||||
|
bool fw_region_inited;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** The root domain instance */
|
/** The root domain instance */
|
||||||
extern struct sbi_domain root;
|
extern struct sbi_domain root;
|
||||||
|
|
||||||
/** HART id to domain table */
|
/** Get pointer to sbi_domain from HART index */
|
||||||
extern struct sbi_domain *hartid_to_domain_table[];
|
struct sbi_domain *sbi_hartindex_to_domain(u32 hartindex);
|
||||||
|
|
||||||
/** 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 */
|
/** Get pointer to sbi_domain for current HART */
|
||||||
#define sbi_domain_thishart_ptr() \
|
#define sbi_domain_thishart_ptr() \
|
||||||
sbi_hartid_to_domain(current_hartid())
|
sbi_hartindex_to_domain(sbi_hartid_to_hartindex(current_hartid()))
|
||||||
|
|
||||||
/** Index to domain table */
|
/** Index to domain table */
|
||||||
extern struct sbi_domain *domidx_to_domain_table[];
|
extern struct sbi_domain *domidx_to_domain_table[];
|
||||||
@@ -113,7 +223,7 @@ extern struct sbi_domain *domidx_to_domain_table[];
|
|||||||
* Check whether given HART is assigned to specified domain
|
* Check whether given HART is assigned to specified domain
|
||||||
* @param dom pointer to domain
|
* @param dom pointer to domain
|
||||||
* @param hartid the HART ID
|
* @param hartid the HART ID
|
||||||
* @return TRUE if HART is assigned to domain otherwise FALSE
|
* @return true if HART is assigned to domain otherwise false
|
||||||
*/
|
*/
|
||||||
bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid);
|
bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid);
|
||||||
|
|
||||||
@@ -148,12 +258,27 @@ void sbi_domain_memregion_init(unsigned long addr,
|
|||||||
* @param addr the address to be checked
|
* @param addr the address to be checked
|
||||||
* @param mode the privilege mode of access
|
* @param mode the privilege mode of access
|
||||||
* @param access_flags bitmask of domain access types (enum sbi_domain_access)
|
* @param access_flags bitmask of domain access types (enum sbi_domain_access)
|
||||||
* @return TRUE if access allowed otherwise FALSE
|
* @return true if access allowed otherwise false
|
||||||
*/
|
*/
|
||||||
bool sbi_domain_check_addr(const struct sbi_domain *dom,
|
bool sbi_domain_check_addr(const struct sbi_domain *dom,
|
||||||
unsigned long addr, unsigned long mode,
|
unsigned long addr, unsigned long mode,
|
||||||
unsigned long access_flags);
|
unsigned long access_flags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether we can access specified address range for given mode and
|
||||||
|
* memory region flags under a domain
|
||||||
|
* @param dom pointer to domain
|
||||||
|
* @param addr the start of the address range to be checked
|
||||||
|
* @param size the size of the address range 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_range(const struct sbi_domain *dom,
|
||||||
|
unsigned long addr, unsigned long size,
|
||||||
|
unsigned long mode,
|
||||||
|
unsigned long access_flags);
|
||||||
|
|
||||||
/** Dump domain details on the console */
|
/** Dump domain details on the console */
|
||||||
void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix);
|
void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix);
|
||||||
|
|
||||||
@@ -175,11 +300,25 @@ int sbi_domain_register(struct sbi_domain *dom,
|
|||||||
* @param reg pointer to the memory region to be added
|
* @param reg pointer to the memory region to be added
|
||||||
*
|
*
|
||||||
* @return 0 on success
|
* @return 0 on success
|
||||||
* @return SBI_EALREADY if memory region conflicts with existing
|
* @return SBI_EALREADY if memory region conflicts with the existing one
|
||||||
* @return SBI_EINVAL otherwise
|
* @return SBI_EINVAL otherwise
|
||||||
*/
|
*/
|
||||||
int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg);
|
int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a memory range with its flags to the root domain
|
||||||
|
* @param addr start physical address of memory range
|
||||||
|
* @param size physical size of memory range
|
||||||
|
* @param align alignment of memory region
|
||||||
|
* @param region_flags memory range flags
|
||||||
|
*
|
||||||
|
* @return 0 on success
|
||||||
|
* @return SBI_EALREADY if memory region conflicts with the existing one
|
||||||
|
* @return SBI_EINVAL otherwise
|
||||||
|
*/
|
||||||
|
int sbi_domain_root_add_memrange(unsigned long addr, unsigned long size,
|
||||||
|
unsigned long align, unsigned long region_flags);
|
||||||
|
|
||||||
/** Finalize domain tables and startup non-root domains */
|
/** Finalize domain tables and startup non-root domains */
|
||||||
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid);
|
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid);
|
||||||
|
|
||||||
|
@@ -13,33 +13,65 @@
|
|||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
#include <sbi/sbi_list.h>
|
#include <sbi/sbi_list.h>
|
||||||
|
|
||||||
#define SBI_ECALL_VERSION_MAJOR 1
|
#define SBI_ECALL_VERSION_MAJOR 2
|
||||||
#define SBI_ECALL_VERSION_MINOR 0
|
#define SBI_ECALL_VERSION_MINOR 0
|
||||||
#define SBI_OPENSBI_IMPID 1
|
#define SBI_OPENSBI_IMPID 1
|
||||||
|
|
||||||
struct sbi_trap_regs;
|
struct sbi_trap_regs;
|
||||||
struct sbi_trap_info;
|
struct sbi_trap_info;
|
||||||
|
|
||||||
struct sbi_ecall_extension {
|
struct sbi_ecall_return {
|
||||||
struct sbi_dlist head;
|
/* Return flag to skip register update */
|
||||||
unsigned long extid_start;
|
bool skip_regs_update;
|
||||||
unsigned long extid_end;
|
/* Return value */
|
||||||
int (* probe)(unsigned long extid, unsigned long *out_val);
|
unsigned long value;
|
||||||
int (* handle)(unsigned long extid, unsigned long funcid,
|
|
||||||
const struct sbi_trap_regs *regs,
|
|
||||||
unsigned long *out_val,
|
|
||||||
struct sbi_trap_info *out_trap);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct sbi_ecall_extension ecall_base;
|
struct sbi_ecall_extension {
|
||||||
extern struct sbi_ecall_extension ecall_legacy;
|
/* head is used by the extension list */
|
||||||
extern struct sbi_ecall_extension ecall_time;
|
struct sbi_dlist head;
|
||||||
extern struct sbi_ecall_extension ecall_rfence;
|
/*
|
||||||
extern struct sbi_ecall_extension ecall_ipi;
|
* extid_start and extid_end specify the range for this extension. As
|
||||||
extern struct sbi_ecall_extension ecall_vendor;
|
* the initial range may be wider than the valid runtime range, the
|
||||||
extern struct sbi_ecall_extension ecall_hsm;
|
* register_extensions callback is responsible for narrowing the range
|
||||||
extern struct sbi_ecall_extension ecall_srst;
|
* before other callbacks may be invoked.
|
||||||
extern struct sbi_ecall_extension ecall_pmu;
|
*/
|
||||||
|
unsigned long extid_start;
|
||||||
|
unsigned long extid_end;
|
||||||
|
/*
|
||||||
|
* register_extensions
|
||||||
|
*
|
||||||
|
* Calls sbi_ecall_register_extension() one or more times to register
|
||||||
|
* extension ID range(s) which should be handled by this extension.
|
||||||
|
* More than one sbi_ecall_extension struct and
|
||||||
|
* sbi_ecall_register_extension() call is necessary when the supported
|
||||||
|
* extension ID ranges have gaps. Additionally, extension availability
|
||||||
|
* must be checked before registering, which means, when this callback
|
||||||
|
* returns, only valid extension IDs from the initial range, which are
|
||||||
|
* also available, have been registered.
|
||||||
|
*/
|
||||||
|
int (* register_extensions)(void);
|
||||||
|
/*
|
||||||
|
* probe
|
||||||
|
*
|
||||||
|
* Implements the Base extension's probe function for the extension. As
|
||||||
|
* the register_extensions callback ensures that no other extension
|
||||||
|
* callbacks will be invoked when the extension is not available, then
|
||||||
|
* probe can never fail. However, an extension may choose to set
|
||||||
|
* out_val to a nonzero value other than one. In those cases, it should
|
||||||
|
* implement this callback.
|
||||||
|
*/
|
||||||
|
int (* probe)(unsigned long extid, unsigned long *out_val);
|
||||||
|
/*
|
||||||
|
* handle
|
||||||
|
*
|
||||||
|
* This is the extension handler. register_extensions ensures it is
|
||||||
|
* never invoked with an invalid or unavailable extension ID.
|
||||||
|
*/
|
||||||
|
int (* handle)(unsigned long extid, unsigned long funcid,
|
||||||
|
struct sbi_trap_regs *regs,
|
||||||
|
struct sbi_ecall_return *out);
|
||||||
|
};
|
||||||
|
|
||||||
u16 sbi_ecall_version_major(void);
|
u16 sbi_ecall_version_major(void);
|
||||||
|
|
||||||
|
@@ -29,6 +29,9 @@
|
|||||||
#define SBI_EXT_HSM 0x48534D
|
#define SBI_EXT_HSM 0x48534D
|
||||||
#define SBI_EXT_SRST 0x53525354
|
#define SBI_EXT_SRST 0x53525354
|
||||||
#define SBI_EXT_PMU 0x504D55
|
#define SBI_EXT_PMU 0x504D55
|
||||||
|
#define SBI_EXT_DBCN 0x4442434E
|
||||||
|
#define SBI_EXT_SUSP 0x53555350
|
||||||
|
#define SBI_EXT_CPPC 0x43505043
|
||||||
|
|
||||||
/* SBI function IDs for BASE extension*/
|
/* SBI function IDs for BASE extension*/
|
||||||
#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
|
#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
|
||||||
@@ -99,6 +102,8 @@
|
|||||||
#define SBI_EXT_PMU_COUNTER_START 0x3
|
#define SBI_EXT_PMU_COUNTER_START 0x3
|
||||||
#define SBI_EXT_PMU_COUNTER_STOP 0x4
|
#define SBI_EXT_PMU_COUNTER_STOP 0x4
|
||||||
#define SBI_EXT_PMU_COUNTER_FW_READ 0x5
|
#define SBI_EXT_PMU_COUNTER_FW_READ 0x5
|
||||||
|
#define SBI_EXT_PMU_COUNTER_FW_READ_HI 0x6
|
||||||
|
#define SBI_EXT_PMU_SNAPSHOT_SET_SHMEM 0x7
|
||||||
|
|
||||||
/** General pmu event codes specified in SBI PMU extension */
|
/** General pmu event codes specified in SBI PMU extension */
|
||||||
enum sbi_pmu_hw_generic_events_t {
|
enum sbi_pmu_hw_generic_events_t {
|
||||||
@@ -182,6 +187,17 @@ enum sbi_pmu_fw_event_code_id {
|
|||||||
SBI_PMU_FW_HFENCE_VVMA_ASID_SENT = 20,
|
SBI_PMU_FW_HFENCE_VVMA_ASID_SENT = 20,
|
||||||
SBI_PMU_FW_HFENCE_VVMA_ASID_RCVD = 21,
|
SBI_PMU_FW_HFENCE_VVMA_ASID_RCVD = 21,
|
||||||
SBI_PMU_FW_MAX,
|
SBI_PMU_FW_MAX,
|
||||||
|
/*
|
||||||
|
* Event codes 22 to 255 are reserved for future use.
|
||||||
|
* Event codes 256 to 65534 are reserved for SBI implementation
|
||||||
|
* specific custom firmware events.
|
||||||
|
*/
|
||||||
|
SBI_PMU_FW_RESERVED_MAX = 0xFFFE,
|
||||||
|
/*
|
||||||
|
* Event code 0xFFFF is used for platform specific firmware
|
||||||
|
* events where the event data contains any event specific information.
|
||||||
|
*/
|
||||||
|
SBI_PMU_FW_PLATFORM = 0xFFFF,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** SBI PMU event idx type */
|
/** SBI PMU event idx type */
|
||||||
@@ -200,14 +216,20 @@ enum sbi_pmu_ctr_type {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Helper macros to decode event idx */
|
/* 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_MASK 0xFFFFF
|
||||||
|
#define SBI_PMU_EVENT_IDX_TYPE_OFFSET 16
|
||||||
|
#define SBI_PMU_EVENT_IDX_TYPE_MASK (0xF << SBI_PMU_EVENT_IDX_TYPE_OFFSET)
|
||||||
#define SBI_PMU_EVENT_IDX_CODE_MASK 0xFFFF
|
#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_RAW_IDX 0x20000
|
||||||
|
|
||||||
#define SBI_PMU_EVENT_IDX_INVALID 0xFFFFFFFF
|
#define SBI_PMU_EVENT_IDX_INVALID 0xFFFFFFFF
|
||||||
|
|
||||||
|
#define SBI_PMU_EVENT_HW_CACHE_OPS_RESULT 0x1
|
||||||
|
#define SBI_PMU_EVENT_HW_CACHE_OPS_ID_MASK 0x6
|
||||||
|
#define SBI_PMU_EVENT_HW_CACHE_OPS_ID_OFFSET 1
|
||||||
|
#define SBI_PMU_EVENT_HW_CACHE_ID_MASK 0xfff8
|
||||||
|
#define SBI_PMU_EVENT_HW_CACHE_ID_OFFSET 3
|
||||||
|
|
||||||
/* Flags defined for config matching function */
|
/* Flags defined for config matching function */
|
||||||
#define SBI_PMU_CFG_FLAG_SKIP_MATCH (1 << 0)
|
#define SBI_PMU_CFG_FLAG_SKIP_MATCH (1 << 0)
|
||||||
#define SBI_PMU_CFG_FLAG_CLEAR_VALUE (1 << 1)
|
#define SBI_PMU_CFG_FLAG_CLEAR_VALUE (1 << 1)
|
||||||
@@ -220,9 +242,56 @@ enum sbi_pmu_ctr_type {
|
|||||||
|
|
||||||
/* Flags defined for counter start function */
|
/* Flags defined for counter start function */
|
||||||
#define SBI_PMU_START_FLAG_SET_INIT_VALUE (1 << 0)
|
#define SBI_PMU_START_FLAG_SET_INIT_VALUE (1 << 0)
|
||||||
|
#define SBI_PMU_START_FLAG_INIT_FROM_SNAPSHOT (1 << 1)
|
||||||
|
|
||||||
/* Flags defined for counter stop function */
|
/* Flags defined for counter stop function */
|
||||||
#define SBI_PMU_STOP_FLAG_RESET (1 << 0)
|
#define SBI_PMU_STOP_FLAG_RESET (1 << 0)
|
||||||
|
#define SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT (1 << 1)
|
||||||
|
|
||||||
|
/* SBI function IDs for DBCN extension */
|
||||||
|
#define SBI_EXT_DBCN_CONSOLE_WRITE 0x0
|
||||||
|
#define SBI_EXT_DBCN_CONSOLE_READ 0x1
|
||||||
|
#define SBI_EXT_DBCN_CONSOLE_WRITE_BYTE 0x2
|
||||||
|
|
||||||
|
/* SBI function IDs for SUSP extension */
|
||||||
|
#define SBI_EXT_SUSP_SUSPEND 0x0
|
||||||
|
|
||||||
|
#define SBI_SUSP_SLEEP_TYPE_SUSPEND 0x0
|
||||||
|
#define SBI_SUSP_SLEEP_TYPE_LAST SBI_SUSP_SLEEP_TYPE_SUSPEND
|
||||||
|
#define SBI_SUSP_PLATFORM_SLEEP_START 0x80000000
|
||||||
|
|
||||||
|
/* SBI function IDs for CPPC extension */
|
||||||
|
#define SBI_EXT_CPPC_PROBE 0x0
|
||||||
|
#define SBI_EXT_CPPC_READ 0x1
|
||||||
|
#define SBI_EXT_CPPC_READ_HI 0x2
|
||||||
|
#define SBI_EXT_CPPC_WRITE 0x3
|
||||||
|
|
||||||
|
enum sbi_cppc_reg_id {
|
||||||
|
SBI_CPPC_HIGHEST_PERF = 0x00000000,
|
||||||
|
SBI_CPPC_NOMINAL_PERF = 0x00000001,
|
||||||
|
SBI_CPPC_LOW_NON_LINEAR_PERF = 0x00000002,
|
||||||
|
SBI_CPPC_LOWEST_PERF = 0x00000003,
|
||||||
|
SBI_CPPC_GUARANTEED_PERF = 0x00000004,
|
||||||
|
SBI_CPPC_DESIRED_PERF = 0x00000005,
|
||||||
|
SBI_CPPC_MIN_PERF = 0x00000006,
|
||||||
|
SBI_CPPC_MAX_PERF = 0x00000007,
|
||||||
|
SBI_CPPC_PERF_REDUC_TOLERANCE = 0x00000008,
|
||||||
|
SBI_CPPC_TIME_WINDOW = 0x00000009,
|
||||||
|
SBI_CPPC_CTR_WRAP_TIME = 0x0000000A,
|
||||||
|
SBI_CPPC_REFERENCE_CTR = 0x0000000B,
|
||||||
|
SBI_CPPC_DELIVERED_CTR = 0x0000000C,
|
||||||
|
SBI_CPPC_PERF_LIMITED = 0x0000000D,
|
||||||
|
SBI_CPPC_ENABLE = 0x0000000E,
|
||||||
|
SBI_CPPC_AUTO_SEL_ENABLE = 0x0000000F,
|
||||||
|
SBI_CPPC_AUTO_ACT_WINDOW = 0x00000010,
|
||||||
|
SBI_CPPC_ENERGY_PERF_PREFERENCE = 0x00000011,
|
||||||
|
SBI_CPPC_REFERENCE_PERF = 0x00000012,
|
||||||
|
SBI_CPPC_LOWEST_FREQ = 0x00000013,
|
||||||
|
SBI_CPPC_NOMINAL_FREQ = 0x00000014,
|
||||||
|
SBI_CPPC_ACPI_LAST = SBI_CPPC_NOMINAL_FREQ,
|
||||||
|
SBI_CPPC_TRANSITION_LATENCY = 0x80000000,
|
||||||
|
SBI_CPPC_NON_ACPI_LAST = SBI_CPPC_TRANSITION_LATENCY,
|
||||||
|
};
|
||||||
|
|
||||||
/* SBI base specification related macros */
|
/* SBI base specification related macros */
|
||||||
#define SBI_SPEC_VERSION_MAJOR_OFFSET 24
|
#define SBI_SPEC_VERSION_MAJOR_OFFSET 24
|
||||||
@@ -243,8 +312,9 @@ enum sbi_pmu_ctr_type {
|
|||||||
#define SBI_ERR_ALREADY_AVAILABLE -6
|
#define SBI_ERR_ALREADY_AVAILABLE -6
|
||||||
#define SBI_ERR_ALREADY_STARTED -7
|
#define SBI_ERR_ALREADY_STARTED -7
|
||||||
#define SBI_ERR_ALREADY_STOPPED -8
|
#define SBI_ERR_ALREADY_STOPPED -8
|
||||||
|
#define SBI_ERR_NO_SHMEM -9
|
||||||
|
|
||||||
#define SBI_LAST_ERR SBI_ERR_ALREADY_STOPPED
|
#define SBI_LAST_ERR SBI_ERR_NO_SHMEM
|
||||||
|
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
|
@@ -23,6 +23,7 @@
|
|||||||
#define SBI_EALREADY SBI_ERR_ALREADY_AVAILABLE
|
#define SBI_EALREADY SBI_ERR_ALREADY_AVAILABLE
|
||||||
#define SBI_EALREADY_STARTED SBI_ERR_ALREADY_STARTED
|
#define SBI_EALREADY_STARTED SBI_ERR_ALREADY_STARTED
|
||||||
#define SBI_EALREADY_STOPPED SBI_ERR_ALREADY_STOPPED
|
#define SBI_EALREADY_STOPPED SBI_ERR_ALREADY_STOPPED
|
||||||
|
#define SBI_ENO_SHMEM SBI_ERR_NO_SHMEM
|
||||||
|
|
||||||
#define SBI_ENODEV -1000
|
#define SBI_ENODEV -1000
|
||||||
#define SBI_ENOSYS -1001
|
#define SBI_ENOSYS -1001
|
||||||
@@ -31,9 +32,8 @@
|
|||||||
#define SBI_EILL -1004
|
#define SBI_EILL -1004
|
||||||
#define SBI_ENOSPC -1005
|
#define SBI_ENOSPC -1005
|
||||||
#define SBI_ENOMEM -1006
|
#define SBI_ENOMEM -1006
|
||||||
#define SBI_ETRAP -1007
|
#define SBI_EUNKNOWN -1007
|
||||||
#define SBI_EUNKNOWN -1008
|
#define SBI_ENOENT -1008
|
||||||
#define SBI_ENOENT -1009
|
|
||||||
|
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
#define __SBI_HART_H__
|
#define __SBI_HART_H__
|
||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
#include <sbi/sbi_bitops.h>
|
||||||
|
|
||||||
/** Possible privileged specification versions of a hart */
|
/** Possible privileged specification versions of a hart */
|
||||||
enum sbi_hart_priv_versions {
|
enum sbi_hart_priv_versions {
|
||||||
@@ -26,21 +27,70 @@ enum sbi_hart_priv_versions {
|
|||||||
|
|
||||||
/** Possible ISA extensions of a hart */
|
/** Possible ISA extensions of a hart */
|
||||||
enum sbi_hart_extensions {
|
enum sbi_hart_extensions {
|
||||||
/** Hart has Sscofpmt extension */
|
/** HART has AIA M-mode CSRs */
|
||||||
SBI_HART_EXT_SSCOFPMF = 0,
|
SBI_HART_EXT_SMAIA = 0,
|
||||||
/** HART has HW time CSR (extension name not available) */
|
/** HART has Smepmp */
|
||||||
SBI_HART_EXT_TIME,
|
SBI_HART_EXT_SMEPMP,
|
||||||
/** HART has AIA CSRs (extension name not available) */
|
|
||||||
SBI_HART_EXT_AIA,
|
|
||||||
/** HART has Smstateen CSR **/
|
/** HART has Smstateen CSR **/
|
||||||
SBI_HART_EXT_SMSTATEEN,
|
SBI_HART_EXT_SMSTATEEN,
|
||||||
|
/** Hart has Sscofpmt extension */
|
||||||
|
SBI_HART_EXT_SSCOFPMF,
|
||||||
/** HART has Sstc extension */
|
/** HART has Sstc extension */
|
||||||
SBI_HART_EXT_SSTC,
|
SBI_HART_EXT_SSTC,
|
||||||
|
/** HART has Zicntr extension (i.e. HW cycle, time & instret CSRs) */
|
||||||
|
SBI_HART_EXT_ZICNTR,
|
||||||
|
/** HART has Zihpm extension */
|
||||||
|
SBI_HART_EXT_ZIHPM,
|
||||||
|
/** HART has Zkr extension */
|
||||||
|
SBI_HART_EXT_ZKR,
|
||||||
|
/** Hart has Smcntrpmf extension */
|
||||||
|
SBI_HART_EXT_SMCNTRPMF,
|
||||||
|
/** Hart has Xandespmu extension */
|
||||||
|
SBI_HART_EXT_XANDESPMU,
|
||||||
|
/** Hart has Zicboz extension */
|
||||||
|
SBI_HART_EXT_ZICBOZ,
|
||||||
|
/** Hart has Zicbom extension */
|
||||||
|
SBI_HART_EXT_ZICBOM,
|
||||||
|
/** Hart has Svpbmt extension */
|
||||||
|
SBI_HART_EXT_SVPBMT,
|
||||||
|
|
||||||
/** Maximum index of Hart extension */
|
/** Maximum index of Hart extension */
|
||||||
SBI_HART_EXT_MAX,
|
SBI_HART_EXT_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct sbi_hart_ext_data {
|
||||||
|
const unsigned int id;
|
||||||
|
const char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct sbi_hart_ext_data sbi_hart_ext[];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Smepmp enforces access boundaries between M-mode and
|
||||||
|
* S/U-mode. When it is enabled, the PMPs are programmed
|
||||||
|
* such that M-mode doesn't have access to S/U-mode memory.
|
||||||
|
*
|
||||||
|
* To give M-mode R/W access to the shared memory between M and
|
||||||
|
* S/U-mode, first entry is reserved. It is disabled at boot.
|
||||||
|
* When shared memory access is required, the physical address
|
||||||
|
* should be programmed into the first PMP entry with R/W
|
||||||
|
* permissions to the M-mode. Once the work is done, it should be
|
||||||
|
* unmapped. sbi_hart_map_saddr/sbi_hart_unmap_saddr function
|
||||||
|
* pair should be used to map/unmap the shared memory.
|
||||||
|
*/
|
||||||
|
#define SBI_SMEPMP_RESV_ENTRY 0
|
||||||
|
|
||||||
|
struct sbi_hart_features {
|
||||||
|
bool detected;
|
||||||
|
int priv_version;
|
||||||
|
unsigned long extensions[BITS_TO_LONGS(SBI_HART_EXT_MAX)];
|
||||||
|
unsigned int pmp_count;
|
||||||
|
unsigned int pmp_addr_bits;
|
||||||
|
unsigned int pmp_log2gran;
|
||||||
|
unsigned int mhpm_mask;
|
||||||
|
unsigned int mhpm_bits;
|
||||||
|
};
|
||||||
|
|
||||||
struct sbi_scratch;
|
struct sbi_scratch;
|
||||||
|
|
||||||
int sbi_hart_reinit(struct sbi_scratch *scratch);
|
int sbi_hart_reinit(struct sbi_scratch *scratch);
|
||||||
@@ -52,14 +102,16 @@ static inline ulong sbi_hart_expected_trap_addr(void)
|
|||||||
return (ulong)sbi_hart_expected_trap;
|
return (ulong)sbi_hart_expected_trap;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int sbi_hart_mhpm_count(struct sbi_scratch *scratch);
|
unsigned int sbi_hart_mhpm_mask(struct sbi_scratch *scratch);
|
||||||
void sbi_hart_delegation_dump(struct sbi_scratch *scratch,
|
void sbi_hart_delegation_dump(struct sbi_scratch *scratch,
|
||||||
const char *prefix, const char *suffix);
|
const char *prefix, const char *suffix);
|
||||||
unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch);
|
unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch);
|
||||||
unsigned long sbi_hart_pmp_granularity(struct sbi_scratch *scratch);
|
unsigned int sbi_hart_pmp_log2gran(struct sbi_scratch *scratch);
|
||||||
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch);
|
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch);
|
||||||
unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch);
|
unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch);
|
||||||
int sbi_hart_pmp_configure(struct sbi_scratch *scratch);
|
int sbi_hart_pmp_configure(struct sbi_scratch *scratch);
|
||||||
|
int sbi_hart_map_saddr(unsigned long base, unsigned long size);
|
||||||
|
int sbi_hart_unmap_saddr(void);
|
||||||
int sbi_hart_priv_version(struct sbi_scratch *scratch);
|
int sbi_hart_priv_version(struct sbi_scratch *scratch);
|
||||||
void sbi_hart_get_priv_version_str(struct sbi_scratch *scratch,
|
void sbi_hart_get_priv_version_str(struct sbi_scratch *scratch,
|
||||||
char *version_str, int nvstr);
|
char *version_str, int nvstr);
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
#define __SBI_HARTMASK_H__
|
#define __SBI_HARTMASK_H__
|
||||||
|
|
||||||
#include <sbi/sbi_bitmap.h>
|
#include <sbi/sbi_bitmap.h>
|
||||||
|
#include <sbi/sbi_scratch.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum number of bits in a hartmask
|
* Maximum number of bits in a hartmask
|
||||||
@@ -32,7 +33,10 @@ struct sbi_hartmask {
|
|||||||
|
|
||||||
/** Initialize hartmask to zero except a particular HART id */
|
/** Initialize hartmask to zero except a particular HART id */
|
||||||
#define SBI_HARTMASK_INIT_EXCEPT(__m, __h) \
|
#define SBI_HARTMASK_INIT_EXCEPT(__m, __h) \
|
||||||
bitmap_zero_except(((__m)->bits), (__h), SBI_HARTMASK_MAX_BITS)
|
do { \
|
||||||
|
u32 __i = sbi_hartid_to_hartindex(__h); \
|
||||||
|
bitmap_zero_except(((__m)->bits), __i, SBI_HARTMASK_MAX_BITS); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get underlying bitmap of hartmask
|
* Get underlying bitmap of hartmask
|
||||||
@@ -41,37 +45,68 @@ struct sbi_hartmask {
|
|||||||
#define sbi_hartmask_bits(__m) ((__m)->bits)
|
#define sbi_hartmask_bits(__m) ((__m)->bits)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a HART in hartmask
|
* Set a HART index in hartmask
|
||||||
|
* @param i HART index to set
|
||||||
|
* @param m the hartmask pointer
|
||||||
|
*/
|
||||||
|
static inline void sbi_hartmask_set_hartindex(u32 i, struct sbi_hartmask *m)
|
||||||
|
{
|
||||||
|
if (i < SBI_HARTMASK_MAX_BITS)
|
||||||
|
__set_bit(i, m->bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a HART id in hartmask
|
||||||
* @param h HART id to set
|
* @param h HART id to set
|
||||||
* @param m the hartmask pointer
|
* @param m the hartmask pointer
|
||||||
*/
|
*/
|
||||||
static inline void sbi_hartmask_set_hart(u32 h, struct sbi_hartmask *m)
|
static inline void sbi_hartmask_set_hartid(u32 h, struct sbi_hartmask *m)
|
||||||
{
|
{
|
||||||
if (h < SBI_HARTMASK_MAX_BITS)
|
sbi_hartmask_set_hartindex(sbi_hartid_to_hartindex(h), m);
|
||||||
__set_bit(h, m->bits);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear a HART in hartmask
|
* Clear a HART index in hartmask
|
||||||
|
* @param i HART index to clear
|
||||||
|
* @param m the hartmask pointer
|
||||||
|
*/
|
||||||
|
static inline void sbi_hartmask_clear_hartindex(u32 i, struct sbi_hartmask *m)
|
||||||
|
{
|
||||||
|
if (i < SBI_HARTMASK_MAX_BITS)
|
||||||
|
__clear_bit(i, m->bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear a HART id in hartmask
|
||||||
* @param h HART id to clear
|
* @param h HART id to clear
|
||||||
* @param m the hartmask pointer
|
* @param m the hartmask pointer
|
||||||
*/
|
*/
|
||||||
static inline void sbi_hartmask_clear_hart(u32 h, struct sbi_hartmask *m)
|
static inline void sbi_hartmask_clear_hartid(u32 h, struct sbi_hartmask *m)
|
||||||
{
|
{
|
||||||
if (h < SBI_HARTMASK_MAX_BITS)
|
sbi_hartmask_clear_hartindex(sbi_hartid_to_hartindex(h), m);
|
||||||
__clear_bit(h, m->bits);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test a HART in hartmask
|
* Test a HART index in hartmask
|
||||||
|
* @param i HART index to test
|
||||||
|
* @param m the hartmask pointer
|
||||||
|
*/
|
||||||
|
static inline int sbi_hartmask_test_hartindex(u32 i,
|
||||||
|
const struct sbi_hartmask *m)
|
||||||
|
{
|
||||||
|
if (i < SBI_HARTMASK_MAX_BITS)
|
||||||
|
return __test_bit(i, m->bits);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test a HART id in hartmask
|
||||||
* @param h HART id to test
|
* @param h HART id to test
|
||||||
* @param m the hartmask pointer
|
* @param m the hartmask pointer
|
||||||
*/
|
*/
|
||||||
static inline int sbi_hartmask_test_hart(u32 h, const struct sbi_hartmask *m)
|
static inline int sbi_hartmask_test_hartid(u32 h, const struct sbi_hartmask *m)
|
||||||
{
|
{
|
||||||
if (h < SBI_HARTMASK_MAX_BITS)
|
return sbi_hartmask_test_hartindex(sbi_hartid_to_hartindex(h), m);
|
||||||
return __test_bit(h, m->bits);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -134,8 +169,14 @@ static inline void sbi_hartmask_xor(struct sbi_hartmask *dstp,
|
|||||||
sbi_hartmask_bits(src2p), SBI_HARTMASK_MAX_BITS);
|
sbi_hartmask_bits(src2p), SBI_HARTMASK_MAX_BITS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Iterate over each HART in hartmask */
|
/**
|
||||||
#define sbi_hartmask_for_each_hart(__h, __m) \
|
* Iterate over each HART index in hartmask
|
||||||
for_each_set_bit(__h, (__m)->bits, SBI_HARTMASK_MAX_BITS)
|
* __i hart index
|
||||||
|
* __m hartmask
|
||||||
|
*/
|
||||||
|
#define sbi_hartmask_for_each_hartindex(__i, __m) \
|
||||||
|
for((__i) = find_first_bit((__m)->bits, SBI_HARTMASK_MAX_BITS); \
|
||||||
|
(__i) < SBI_HARTMASK_MAX_BITS; \
|
||||||
|
(__i) = find_next_bit((__m)->bits, SBI_HARTMASK_MAX_BITS, (__i) + 1))
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
47
include/sbi/sbi_heap.h
Normal file
47
include/sbi/sbi_heap.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Ventana Micro Systems Inc.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel<apatel@ventanamicro.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SBI_HEAP_H__
|
||||||
|
#define __SBI_HEAP_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
/* Alignment of heap base address and size */
|
||||||
|
#define HEAP_BASE_ALIGN 1024
|
||||||
|
|
||||||
|
struct sbi_scratch;
|
||||||
|
|
||||||
|
/** Allocate from heap area */
|
||||||
|
void *sbi_malloc(size_t size);
|
||||||
|
|
||||||
|
/** Zero allocate from heap area */
|
||||||
|
void *sbi_zalloc(size_t size);
|
||||||
|
|
||||||
|
/** Allocate array from heap area */
|
||||||
|
static inline void *sbi_calloc(size_t nitems, size_t size)
|
||||||
|
{
|
||||||
|
return sbi_zalloc(nitems * size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Free-up to heap area */
|
||||||
|
void sbi_free(void *ptr);
|
||||||
|
|
||||||
|
/** Amount (in bytes) of free space in the heap area */
|
||||||
|
unsigned long sbi_heap_free_space(void);
|
||||||
|
|
||||||
|
/** Amount (in bytes) of used space in the heap area */
|
||||||
|
unsigned long sbi_heap_used_space(void);
|
||||||
|
|
||||||
|
/** Amount (in bytes) of reserved space in the heap area */
|
||||||
|
unsigned long sbi_heap_reserved_space(void);
|
||||||
|
|
||||||
|
/** Initialize heap area */
|
||||||
|
int sbi_heap_init(struct sbi_scratch *scratch);
|
||||||
|
|
||||||
|
#endif
|
@@ -21,8 +21,12 @@ struct sbi_hsm_device {
|
|||||||
int (*hart_start)(u32 hartid, ulong saddr);
|
int (*hart_start)(u32 hartid, ulong saddr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop (or power-down) the current hart from running. This call
|
* Stop (or power-down) the current hart from running.
|
||||||
* doesn't expect to return if success.
|
*
|
||||||
|
* Return SBI_ENOTSUPP if the hart does not support platform-specific
|
||||||
|
* stop actions.
|
||||||
|
*
|
||||||
|
* For successful stop, the call won't return.
|
||||||
*/
|
*/
|
||||||
int (*hart_stop)(void);
|
int (*hart_stop)(void);
|
||||||
|
|
||||||
@@ -59,15 +63,21 @@ void __noreturn sbi_hsm_exit(struct sbi_scratch *scratch);
|
|||||||
|
|
||||||
int sbi_hsm_hart_start(struct sbi_scratch *scratch,
|
int sbi_hsm_hart_start(struct sbi_scratch *scratch,
|
||||||
const struct sbi_domain *dom,
|
const struct sbi_domain *dom,
|
||||||
u32 hartid, ulong saddr, ulong smode, ulong priv);
|
u32 hartid, ulong saddr, ulong smode, ulong arg1);
|
||||||
int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow);
|
int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow);
|
||||||
void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch);
|
void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch);
|
||||||
void sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch);
|
void __noreturn sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch,
|
||||||
|
u32 hartid);
|
||||||
int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type,
|
int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type,
|
||||||
ulong raddr, ulong rmode, ulong priv);
|
ulong raddr, ulong rmode, ulong arg1);
|
||||||
|
bool sbi_hsm_hart_change_state(struct sbi_scratch *scratch, long oldstate,
|
||||||
|
long newstate);
|
||||||
|
int __sbi_hsm_hart_get_state(u32 hartid);
|
||||||
int sbi_hsm_hart_get_state(const struct sbi_domain *dom, u32 hartid);
|
int sbi_hsm_hart_get_state(const struct sbi_domain *dom, u32 hartid);
|
||||||
int sbi_hsm_hart_interruptible_mask(const struct sbi_domain *dom,
|
int sbi_hsm_hart_interruptible_mask(const struct sbi_domain *dom,
|
||||||
ulong hbase, ulong *out_hmask);
|
ulong hbase, ulong *out_hmask);
|
||||||
void sbi_hsm_prepare_next_jump(struct sbi_scratch *scratch, u32 hartid);
|
void __sbi_hsm_suspend_non_ret_save(struct sbi_scratch *scratch);
|
||||||
|
void __noreturn sbi_hsm_hart_start_finish(struct sbi_scratch *scratch,
|
||||||
|
u32 hartid);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -16,6 +16,8 @@ struct sbi_scratch;
|
|||||||
|
|
||||||
void __noreturn sbi_init(struct sbi_scratch *scratch);
|
void __noreturn sbi_init(struct sbi_scratch *scratch);
|
||||||
|
|
||||||
|
unsigned long sbi_entry_count(u32 hartid);
|
||||||
|
|
||||||
unsigned long sbi_init_count(u32 hartid);
|
unsigned long sbi_init_count(u32 hartid);
|
||||||
|
|
||||||
void __noreturn sbi_exit(struct sbi_scratch *scratch);
|
void __noreturn sbi_exit(struct sbi_scratch *scratch);
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
|
|
||||||
#define SBI_IPI_EVENT_MAX __riscv_xlen
|
#define SBI_IPI_EVENT_MAX (8 * __SIZEOF_LONG__)
|
||||||
|
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
@@ -23,11 +23,17 @@ struct sbi_ipi_device {
|
|||||||
/** Name of the IPI device */
|
/** Name of the IPI device */
|
||||||
char name[32];
|
char name[32];
|
||||||
|
|
||||||
/** Send IPI to a target HART */
|
/** Send IPI to a target HART index */
|
||||||
void (*ipi_send)(u32 target_hart);
|
void (*ipi_send)(u32 hart_index);
|
||||||
|
|
||||||
/** Clear IPI for a target HART */
|
/** Clear IPI for a target HART index */
|
||||||
void (*ipi_clear)(u32 target_hart);
|
void (*ipi_clear)(u32 hart_index);
|
||||||
|
};
|
||||||
|
|
||||||
|
enum sbi_ipi_update_type {
|
||||||
|
SBI_IPI_UPDATE_SUCCESS,
|
||||||
|
SBI_IPI_UPDATE_BREAK,
|
||||||
|
SBI_IPI_UPDATE_RETRY,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sbi_scratch;
|
struct sbi_scratch;
|
||||||
@@ -41,10 +47,14 @@ struct sbi_ipi_event_ops {
|
|||||||
* Update callback to save/enqueue data for remote HART
|
* Update callback to save/enqueue data for remote HART
|
||||||
* Note: This is an optional callback and it is called just before
|
* Note: This is an optional callback and it is called just before
|
||||||
* triggering IPI to remote HART.
|
* triggering IPI to remote HART.
|
||||||
|
* @return < 0, error or failure
|
||||||
|
* @return SBI_IPI_UPDATE_SUCCESS, success
|
||||||
|
* @return SBI_IPI_UPDATE_BREAK, break IPI, done on local hart
|
||||||
|
* @return SBI_IPI_UPDATE_RETRY, need retry
|
||||||
*/
|
*/
|
||||||
int (* update)(struct sbi_scratch *scratch,
|
int (* update)(struct sbi_scratch *scratch,
|
||||||
struct sbi_scratch *remote_scratch,
|
struct sbi_scratch *remote_scratch,
|
||||||
u32 remote_hartid, void *data);
|
u32 remote_hartindex, void *data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sync callback to wait for remote HART
|
* Sync callback to wait for remote HART
|
||||||
@@ -75,7 +85,9 @@ int sbi_ipi_send_halt(ulong hmask, ulong hbase);
|
|||||||
|
|
||||||
void sbi_ipi_process(void);
|
void sbi_ipi_process(void);
|
||||||
|
|
||||||
void sbi_ipi_raw_send(u32 target_hart);
|
int sbi_ipi_raw_send(u32 hartindex);
|
||||||
|
|
||||||
|
void sbi_ipi_raw_clear(u32 hartindex);
|
||||||
|
|
||||||
const struct sbi_ipi_device *sbi_ipi_get_device(void);
|
const struct sbi_ipi_device *sbi_ipi_get_device(void);
|
||||||
|
|
||||||
|
@@ -31,7 +31,7 @@ struct sbi_dlist _lname = SBI_LIST_HEAD_INIT(_lname)
|
|||||||
#define SBI_INIT_LIST_HEAD(ptr) \
|
#define SBI_INIT_LIST_HEAD(ptr) \
|
||||||
do { \
|
do { \
|
||||||
(ptr)->next = ptr; (ptr)->prev = ptr; \
|
(ptr)->next = ptr; (ptr)->prev = ptr; \
|
||||||
} while (0);
|
} while (0)
|
||||||
|
|
||||||
static inline void __sbi_list_add(struct sbi_dlist *new,
|
static inline void __sbi_list_add(struct sbi_dlist *new,
|
||||||
struct sbi_dlist *prev,
|
struct sbi_dlist *prev,
|
||||||
@@ -47,7 +47,7 @@ static inline void __sbi_list_add(struct sbi_dlist *new,
|
|||||||
* Checks if the list is empty or not.
|
* Checks if the list is empty or not.
|
||||||
* @param head List head
|
* @param head List head
|
||||||
*
|
*
|
||||||
* Retruns TRUE if list is empty, FALSE otherwise.
|
* Returns true if list is empty, false otherwise.
|
||||||
*/
|
*/
|
||||||
static inline bool sbi_list_empty(struct sbi_dlist *head)
|
static inline bool sbi_list_empty(struct sbi_dlist *head)
|
||||||
{
|
{
|
||||||
|
@@ -29,12 +29,16 @@
|
|||||||
#define SBI_PLATFORM_HART_COUNT_OFFSET (0x50)
|
#define SBI_PLATFORM_HART_COUNT_OFFSET (0x50)
|
||||||
/** Offset of hart_stack_size in struct sbi_platform */
|
/** Offset of hart_stack_size in struct sbi_platform */
|
||||||
#define SBI_PLATFORM_HART_STACK_SIZE_OFFSET (0x54)
|
#define SBI_PLATFORM_HART_STACK_SIZE_OFFSET (0x54)
|
||||||
|
/** Offset of heap_size in struct sbi_platform */
|
||||||
|
#define SBI_PLATFORM_HEAP_SIZE_OFFSET (0x58)
|
||||||
|
/** Offset of reserved in struct sbi_platform */
|
||||||
|
#define SBI_PLATFORM_RESERVED_OFFSET (0x5c)
|
||||||
/** Offset of platform_ops_addr in struct sbi_platform */
|
/** Offset of platform_ops_addr in struct sbi_platform */
|
||||||
#define SBI_PLATFORM_OPS_OFFSET (0x58)
|
#define SBI_PLATFORM_OPS_OFFSET (0x60)
|
||||||
/** Offset of firmware_context in struct sbi_platform */
|
/** Offset of firmware_context in struct sbi_platform */
|
||||||
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x58 + __SIZEOF_POINTER__)
|
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x60 + __SIZEOF_POINTER__)
|
||||||
/** Offset of hart_index2id in struct sbi_platform */
|
/** Offset of hart_index2id in struct sbi_platform */
|
||||||
#define SBI_PLATFORM_HART_INDEX2ID_OFFSET (0x58 + (__SIZEOF_POINTER__ * 2))
|
#define SBI_PLATFORM_HART_INDEX2ID_OFFSET (0x60 + (__SIZEOF_POINTER__ * 2))
|
||||||
|
|
||||||
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT (1UL << 12)
|
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT (1UL << 12)
|
||||||
|
|
||||||
@@ -46,8 +50,9 @@
|
|||||||
#include <sbi/sbi_version.h>
|
#include <sbi/sbi_version.h>
|
||||||
|
|
||||||
struct sbi_domain_memregion;
|
struct sbi_domain_memregion;
|
||||||
struct sbi_trap_info;
|
struct sbi_ecall_return;
|
||||||
struct sbi_trap_regs;
|
struct sbi_trap_regs;
|
||||||
|
struct sbi_hart_features;
|
||||||
|
|
||||||
/** Possible feature flags of a platform */
|
/** Possible feature flags of a platform */
|
||||||
enum sbi_platform_features {
|
enum sbi_platform_features {
|
||||||
@@ -64,6 +69,9 @@ enum sbi_platform_features {
|
|||||||
|
|
||||||
/** Platform functions */
|
/** Platform functions */
|
||||||
struct sbi_platform_operations {
|
struct sbi_platform_operations {
|
||||||
|
/* Check if specified HART is allowed to do cold boot */
|
||||||
|
bool (*cold_boot_allowed)(u32 hartid);
|
||||||
|
|
||||||
/* Platform nascent initialization */
|
/* Platform nascent initialization */
|
||||||
int (*nascent_init)(void);
|
int (*nascent_init)(void);
|
||||||
|
|
||||||
@@ -90,7 +98,7 @@ struct sbi_platform_operations {
|
|||||||
int (*misa_get_xlen)(void);
|
int (*misa_get_xlen)(void);
|
||||||
|
|
||||||
/** Initialize (or populate) HART extensions for the platform */
|
/** Initialize (or populate) HART extensions for the platform */
|
||||||
int (*extensions_init)(void);
|
int (*extensions_init)(struct sbi_hart_features *hfeatures);
|
||||||
|
|
||||||
/** Initialize (or populate) domains for the platform */
|
/** Initialize (or populate) domains for the platform */
|
||||||
int (*domains_init)(void);
|
int (*domains_init)(void);
|
||||||
@@ -117,23 +125,29 @@ struct sbi_platform_operations {
|
|||||||
/** Get tlb flush limit value **/
|
/** Get tlb flush limit value **/
|
||||||
u64 (*get_tlbr_flush_limit)(void);
|
u64 (*get_tlbr_flush_limit)(void);
|
||||||
|
|
||||||
|
/** Get tlb fifo num entries*/
|
||||||
|
u32 (*get_tlb_num_entries)(void);
|
||||||
|
|
||||||
/** Initialize platform timer for current HART */
|
/** Initialize platform timer for current HART */
|
||||||
int (*timer_init)(bool cold_boot);
|
int (*timer_init)(bool cold_boot);
|
||||||
/** Exit platform timer for current HART */
|
/** Exit platform timer for current HART */
|
||||||
void (*timer_exit)(void);
|
void (*timer_exit)(void);
|
||||||
|
|
||||||
/** platform specific SBI extension implementation probe function */
|
/** Check if SBI vendor extension is implemented or not */
|
||||||
int (*vendor_ext_check)(long extid);
|
bool (*vendor_ext_check)(void);
|
||||||
/** platform specific SBI extension implementation provider */
|
/** platform specific SBI extension implementation provider */
|
||||||
int (*vendor_ext_provider)(long extid, long funcid,
|
int (*vendor_ext_provider)(long funcid,
|
||||||
const struct sbi_trap_regs *regs,
|
struct sbi_trap_regs *regs,
|
||||||
unsigned long *out_value,
|
struct sbi_ecall_return *out);
|
||||||
struct sbi_trap_info *out_trap);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Platform default per-HART stack size for exception/interrupt handling */
|
/** Platform default per-HART stack size for exception/interrupt handling */
|
||||||
#define SBI_PLATFORM_DEFAULT_HART_STACK_SIZE 8192
|
#define SBI_PLATFORM_DEFAULT_HART_STACK_SIZE 8192
|
||||||
|
|
||||||
|
/** Platform default heap size */
|
||||||
|
#define SBI_PLATFORM_DEFAULT_HEAP_SIZE(__num_hart) \
|
||||||
|
(0x8000 + 0x800 * (__num_hart))
|
||||||
|
|
||||||
/** Representation of a platform */
|
/** Representation of a platform */
|
||||||
struct sbi_platform {
|
struct sbi_platform {
|
||||||
/**
|
/**
|
||||||
@@ -156,6 +170,10 @@ struct sbi_platform {
|
|||||||
u32 hart_count;
|
u32 hart_count;
|
||||||
/** Per-HART stack size for exception/interrupt handling */
|
/** Per-HART stack size for exception/interrupt handling */
|
||||||
u32 hart_stack_size;
|
u32 hart_stack_size;
|
||||||
|
/** Size of heap shared by all HARTs */
|
||||||
|
u32 heap_size;
|
||||||
|
/** Reserved for future use */
|
||||||
|
u32 reserved;
|
||||||
/** Pointer to sbi platform operations */
|
/** Pointer to sbi platform operations */
|
||||||
unsigned long platform_ops_addr;
|
unsigned long platform_ops_addr;
|
||||||
/** Pointer to system firmware specific context */
|
/** Pointer to system firmware specific context */
|
||||||
@@ -242,16 +260,6 @@ _Static_assert(
|
|||||||
#define sbi_platform_has_mfaults_delegation(__p) \
|
#define sbi_platform_has_mfaults_delegation(__p) \
|
||||||
((__p)->features & SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
|
((__p)->features & SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
|
||||||
|
|
||||||
/**
|
|
||||||
* Get HART index for the given HART
|
|
||||||
*
|
|
||||||
* @param plat pointer to struct sbi_platform
|
|
||||||
* @param hartid HART ID
|
|
||||||
*
|
|
||||||
* @return 0 <= value < hart_count for valid HART otherwise -1U
|
|
||||||
*/
|
|
||||||
u32 sbi_platform_hart_index(const struct sbi_platform *plat, u32 hartid);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the platform features in string format
|
* Get the platform features in string format
|
||||||
*
|
*
|
||||||
@@ -309,6 +317,20 @@ static inline u64 sbi_platform_tlbr_flush_limit(const struct sbi_platform *plat)
|
|||||||
return SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT;
|
return SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get platform specific tlb fifo num entries.
|
||||||
|
*
|
||||||
|
* @param plat pointer to struct sbi_platform
|
||||||
|
*
|
||||||
|
* @return number of tlb fifo entries
|
||||||
|
*/
|
||||||
|
static inline u32 sbi_platform_tlb_fifo_num_entries(const struct sbi_platform *plat)
|
||||||
|
{
|
||||||
|
if (plat && sbi_platform_ops(plat)->get_tlb_num_entries)
|
||||||
|
return sbi_platform_ops(plat)->get_tlb_num_entries();
|
||||||
|
return sbi_scratch_last_hartindex() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get total number of HARTs supported by the platform
|
* Get total number of HARTs supported by the platform
|
||||||
*
|
*
|
||||||
@@ -338,21 +360,20 @@ static inline u32 sbi_platform_hart_stack_size(const struct sbi_platform *plat)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether given HART is invalid
|
* Check whether given HART is allowed to do cold boot
|
||||||
*
|
*
|
||||||
* @param plat pointer to struct sbi_platform
|
* @param plat pointer to struct sbi_platform
|
||||||
* @param hartid HART ID
|
* @param hartid HART ID
|
||||||
*
|
*
|
||||||
* @return TRUE if HART is invalid and FALSE otherwise
|
* @return true if HART is allowed to do cold boot and false otherwise
|
||||||
*/
|
*/
|
||||||
static inline bool sbi_platform_hart_invalid(const struct sbi_platform *plat,
|
static inline bool sbi_platform_cold_boot_allowed(
|
||||||
u32 hartid)
|
const struct sbi_platform *plat,
|
||||||
|
u32 hartid)
|
||||||
{
|
{
|
||||||
if (!plat)
|
if (plat && sbi_platform_ops(plat)->cold_boot_allowed)
|
||||||
return TRUE;
|
return sbi_platform_ops(plat)->cold_boot_allowed(hartid);
|
||||||
if (plat->hart_count <= sbi_platform_hart_index(plat, hartid))
|
return true;
|
||||||
return TRUE;
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -376,7 +397,7 @@ static inline int sbi_platform_nascent_init(const struct sbi_platform *plat)
|
|||||||
* Early initialization for current HART
|
* Early initialization for current HART
|
||||||
*
|
*
|
||||||
* @param plat pointer to struct sbi_platform
|
* @param plat pointer to struct sbi_platform
|
||||||
* @param cold_boot whether cold boot (TRUE) or warm_boot (FALSE)
|
* @param cold_boot whether cold boot (true) or warm_boot (false)
|
||||||
*
|
*
|
||||||
* @return 0 on success and negative error code on failure
|
* @return 0 on success and negative error code on failure
|
||||||
*/
|
*/
|
||||||
@@ -392,7 +413,7 @@ static inline int sbi_platform_early_init(const struct sbi_platform *plat,
|
|||||||
* Final initialization for current HART
|
* Final initialization for current HART
|
||||||
*
|
*
|
||||||
* @param plat pointer to struct sbi_platform
|
* @param plat pointer to struct sbi_platform
|
||||||
* @param cold_boot whether cold boot (TRUE) or warm_boot (FALSE)
|
* @param cold_boot whether cold boot (true) or warm_boot (false)
|
||||||
*
|
*
|
||||||
* @return 0 on success and negative error code on failure
|
* @return 0 on success and negative error code on failure
|
||||||
*/
|
*/
|
||||||
@@ -464,10 +485,11 @@ static inline int sbi_platform_misa_xlen(const struct sbi_platform *plat)
|
|||||||
* @return 0 on success and negative error code on failure
|
* @return 0 on success and negative error code on failure
|
||||||
*/
|
*/
|
||||||
static inline int sbi_platform_extensions_init(
|
static inline int sbi_platform_extensions_init(
|
||||||
const struct sbi_platform *plat)
|
const struct sbi_platform *plat,
|
||||||
|
struct sbi_hart_features *hfeatures)
|
||||||
{
|
{
|
||||||
if (plat && sbi_platform_ops(plat)->extensions_init)
|
if (plat && sbi_platform_ops(plat)->extensions_init)
|
||||||
return sbi_platform_ops(plat)->extensions_init();
|
return sbi_platform_ops(plat)->extensions_init(hfeatures);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -536,7 +558,7 @@ static inline int sbi_platform_console_init(const struct sbi_platform *plat)
|
|||||||
* Initialize the platform interrupt controller for current HART
|
* Initialize the platform interrupt controller for current HART
|
||||||
*
|
*
|
||||||
* @param plat pointer to struct sbi_platform
|
* @param plat pointer to struct sbi_platform
|
||||||
* @param cold_boot whether cold boot (TRUE) or warm_boot (FALSE)
|
* @param cold_boot whether cold boot (true) or warm_boot (false)
|
||||||
*
|
*
|
||||||
* @return 0 on success and negative error code on failure
|
* @return 0 on success and negative error code on failure
|
||||||
*/
|
*/
|
||||||
@@ -563,7 +585,7 @@ static inline void sbi_platform_irqchip_exit(const struct sbi_platform *plat)
|
|||||||
* Initialize the platform IPI support for current HART
|
* Initialize the platform IPI support for current HART
|
||||||
*
|
*
|
||||||
* @param plat pointer to struct sbi_platform
|
* @param plat pointer to struct sbi_platform
|
||||||
* @param cold_boot whether cold boot (TRUE) or warm_boot (FALSE)
|
* @param cold_boot whether cold boot (true) or warm_boot (false)
|
||||||
*
|
*
|
||||||
* @return 0 on success and negative error code on failure
|
* @return 0 on success and negative error code on failure
|
||||||
*/
|
*/
|
||||||
@@ -590,7 +612,7 @@ static inline void sbi_platform_ipi_exit(const struct sbi_platform *plat)
|
|||||||
* Initialize the platform timer for current HART
|
* Initialize the platform timer for current HART
|
||||||
*
|
*
|
||||||
* @param plat pointer to struct sbi_platform
|
* @param plat pointer to struct sbi_platform
|
||||||
* @param cold_boot whether cold boot (TRUE) or warm_boot (FALSE)
|
* @param cold_boot whether cold boot (true) or warm_boot (false)
|
||||||
*
|
*
|
||||||
* @return 0 on success and negative error code on failure
|
* @return 0 on success and negative error code on failure
|
||||||
*/
|
*/
|
||||||
@@ -614,27 +636,25 @@ static inline void sbi_platform_timer_exit(const struct sbi_platform *plat)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a vendor extension is implemented or not.
|
* Check if SBI vendor extension is implemented or not.
|
||||||
*
|
*
|
||||||
* @param plat pointer to struct sbi_platform
|
* @param plat pointer to struct sbi_platform
|
||||||
* @param extid vendor SBI extension id
|
|
||||||
*
|
*
|
||||||
* @return 0 if extid is not implemented and 1 if implemented
|
* @return false if not implemented and true if implemented
|
||||||
*/
|
*/
|
||||||
static inline int sbi_platform_vendor_ext_check(const struct sbi_platform *plat,
|
static inline bool sbi_platform_vendor_ext_check(
|
||||||
long extid)
|
const struct sbi_platform *plat)
|
||||||
{
|
{
|
||||||
if (plat && sbi_platform_ops(plat)->vendor_ext_check)
|
if (plat && sbi_platform_ops(plat)->vendor_ext_check)
|
||||||
return sbi_platform_ops(plat)->vendor_ext_check(extid);
|
return sbi_platform_ops(plat)->vendor_ext_check();
|
||||||
|
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoke platform specific vendor SBI extension implementation.
|
* Invoke platform specific vendor SBI extension implementation.
|
||||||
*
|
*
|
||||||
* @param plat pointer to struct sbi_platform
|
* @param plat pointer to struct sbi_platform
|
||||||
* @param extid vendor SBI extension id
|
|
||||||
* @param funcid SBI function id within the extension id
|
* @param funcid SBI function id within the extension id
|
||||||
* @param regs pointer to trap registers 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_value output value that can be filled by the callee
|
||||||
@@ -644,17 +664,13 @@ static inline int sbi_platform_vendor_ext_check(const struct sbi_platform *plat,
|
|||||||
*/
|
*/
|
||||||
static inline int sbi_platform_vendor_ext_provider(
|
static inline int sbi_platform_vendor_ext_provider(
|
||||||
const struct sbi_platform *plat,
|
const struct sbi_platform *plat,
|
||||||
long extid, long funcid,
|
long funcid,
|
||||||
const struct sbi_trap_regs *regs,
|
struct sbi_trap_regs *regs,
|
||||||
unsigned long *out_value,
|
struct sbi_ecall_return *out)
|
||||||
struct sbi_trap_info *out_trap)
|
|
||||||
{
|
{
|
||||||
if (plat && sbi_platform_ops(plat)->vendor_ext_provider) {
|
if (plat && sbi_platform_ops(plat)->vendor_ext_provider)
|
||||||
return sbi_platform_ops(plat)->vendor_ext_provider(extid,
|
return sbi_platform_ops(plat)->vendor_ext_provider(funcid,
|
||||||
funcid, regs,
|
regs, out);
|
||||||
out_value,
|
|
||||||
out_trap);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SBI_ENOTSUPP;
|
return SBI_ENOTSUPP;
|
||||||
}
|
}
|
||||||
|
@@ -11,22 +11,98 @@
|
|||||||
#define __SBI_PMU_H__
|
#define __SBI_PMU_H__
|
||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
#include <sbi/sbi_hartmask.h>
|
|
||||||
#include <sbi/sbi_scratch.h>
|
struct sbi_scratch;
|
||||||
#include <sbi/sbi_ecall_interface.h>
|
|
||||||
|
|
||||||
/* Event related macros */
|
/* Event related macros */
|
||||||
/* Maximum number of hardware events that can mapped by OpenSBI */
|
/* Maximum number of hardware events that can mapped by OpenSBI */
|
||||||
#define SBI_PMU_HW_EVENT_MAX 256
|
#define SBI_PMU_HW_EVENT_MAX 256
|
||||||
|
|
||||||
/* Maximum number of firmware events that can mapped by OpenSBI */
|
|
||||||
#define SBI_PMU_FW_EVENT_MAX 32
|
|
||||||
|
|
||||||
/* Counter related macros */
|
/* Counter related macros */
|
||||||
#define SBI_PMU_FW_CTR_MAX 16
|
#define SBI_PMU_FW_CTR_MAX 16
|
||||||
#define SBI_PMU_HW_CTR_MAX 32
|
#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_CTR_MAX (SBI_PMU_HW_CTR_MAX + SBI_PMU_FW_CTR_MAX)
|
||||||
#define SBI_PMU_FIXED_CTR_MASK 0x07
|
#define SBI_PMU_FIXED_CTR_MASK 0x07
|
||||||
|
#define SBI_PMU_CY_IR_MASK 0x05
|
||||||
|
|
||||||
|
struct sbi_pmu_device {
|
||||||
|
/** Name of the PMU platform device */
|
||||||
|
char name[32];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate event code of custom firmware event
|
||||||
|
*/
|
||||||
|
int (*fw_event_validate_encoding)(uint32_t hartid, uint64_t event_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Match custom firmware counter with custom firmware event
|
||||||
|
* Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX
|
||||||
|
*/
|
||||||
|
bool (*fw_counter_match_encoding)(uint32_t hartid,
|
||||||
|
uint32_t counter_index,
|
||||||
|
uint64_t event_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the max width of this counter in number of bits.
|
||||||
|
*/
|
||||||
|
int (*fw_counter_width)(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read value of custom firmware counter
|
||||||
|
* Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX
|
||||||
|
*/
|
||||||
|
uint64_t (*fw_counter_read_value)(uint32_t hartid,
|
||||||
|
uint32_t counter_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write value to custom firmware counter
|
||||||
|
* Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX
|
||||||
|
*/
|
||||||
|
void (*fw_counter_write_value)(uint32_t hartid, uint32_t counter_index,
|
||||||
|
uint64_t value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start custom firmware counter
|
||||||
|
* Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX
|
||||||
|
*/
|
||||||
|
int (*fw_counter_start)(uint32_t hartid, uint32_t counter_index,
|
||||||
|
uint64_t event_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop custom firmware counter
|
||||||
|
* Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX
|
||||||
|
*/
|
||||||
|
int (*fw_counter_stop)(uint32_t hartid, uint32_t counter_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom enable irq for hardware counter
|
||||||
|
* Note: 0 <= counter_index < SBI_PMU_HW_CTR_MAX
|
||||||
|
*/
|
||||||
|
void (*hw_counter_enable_irq)(uint32_t counter_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom disable irq for hardware counter
|
||||||
|
* Note: 0 <= counter_index < SBI_PMU_HW_CTR_MAX
|
||||||
|
*/
|
||||||
|
void (*hw_counter_disable_irq)(uint32_t counter_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom function returning the machine-specific irq-bit.
|
||||||
|
*/
|
||||||
|
int (*hw_counter_irq_bit)(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom function to inhibit counting of events while in
|
||||||
|
* specified mode.
|
||||||
|
*/
|
||||||
|
void (*hw_counter_filter_mode)(unsigned long flags, int counter_index);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Get the PMU platform device */
|
||||||
|
const struct sbi_pmu_device *sbi_pmu_get_device(void);
|
||||||
|
|
||||||
|
/** Set the PMU platform device */
|
||||||
|
void sbi_pmu_set_device(const struct sbi_pmu_device *dev);
|
||||||
|
|
||||||
/** Initialize PMU */
|
/** Initialize PMU */
|
||||||
int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot);
|
int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||||
@@ -34,6 +110,9 @@ int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot);
|
|||||||
/** Reset PMU during hart exit */
|
/** Reset PMU during hart exit */
|
||||||
void sbi_pmu_exit(struct sbi_scratch *scratch);
|
void sbi_pmu_exit(struct sbi_scratch *scratch);
|
||||||
|
|
||||||
|
/** Return the pmu irq bit depending on extension existence */
|
||||||
|
int sbi_pmu_irq_bit(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the hardware event to counter mapping information. This should be called
|
* Add the hardware event to counter mapping information. This should be called
|
||||||
* from the platform code to update the mapping table.
|
* from the platform code to update the mapping table.
|
||||||
@@ -53,7 +132,7 @@ int sbi_pmu_add_hw_event_counter_map(u32 eidx_start, u32 eidx_end, u32 cmap);
|
|||||||
|
|
||||||
int sbi_pmu_add_raw_event_counter_map(uint64_t select, uint64_t select_mask, u32 cmap);
|
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_fw_read(uint32_t cidx, uint64_t *cval);
|
||||||
|
|
||||||
int sbi_pmu_ctr_stop(unsigned long cidx_base, unsigned long cidx_mask,
|
int sbi_pmu_ctr_stop(unsigned long cidx_base, unsigned long cidx_mask,
|
||||||
unsigned long flag);
|
unsigned long flag);
|
||||||
|
@@ -18,26 +18,32 @@
|
|||||||
#define SBI_SCRATCH_FW_START_OFFSET (0 * __SIZEOF_POINTER__)
|
#define SBI_SCRATCH_FW_START_OFFSET (0 * __SIZEOF_POINTER__)
|
||||||
/** Offset of fw_size member in sbi_scratch */
|
/** Offset of fw_size member in sbi_scratch */
|
||||||
#define SBI_SCRATCH_FW_SIZE_OFFSET (1 * __SIZEOF_POINTER__)
|
#define SBI_SCRATCH_FW_SIZE_OFFSET (1 * __SIZEOF_POINTER__)
|
||||||
|
/** Offset (in sbi_scratch) of the R/W Offset */
|
||||||
|
#define SBI_SCRATCH_FW_RW_OFFSET (2 * __SIZEOF_POINTER__)
|
||||||
|
/** Offset of fw_heap_offset member in sbi_scratch */
|
||||||
|
#define SBI_SCRATCH_FW_HEAP_OFFSET (3 * __SIZEOF_POINTER__)
|
||||||
|
/** Offset of fw_heap_size_offset member in sbi_scratch */
|
||||||
|
#define SBI_SCRATCH_FW_HEAP_SIZE_OFFSET (4 * __SIZEOF_POINTER__)
|
||||||
/** Offset of next_arg1 member in sbi_scratch */
|
/** Offset of next_arg1 member in sbi_scratch */
|
||||||
#define SBI_SCRATCH_NEXT_ARG1_OFFSET (2 * __SIZEOF_POINTER__)
|
#define SBI_SCRATCH_NEXT_ARG1_OFFSET (5 * __SIZEOF_POINTER__)
|
||||||
/** Offset of next_addr member in sbi_scratch */
|
/** Offset of next_addr member in sbi_scratch */
|
||||||
#define SBI_SCRATCH_NEXT_ADDR_OFFSET (3 * __SIZEOF_POINTER__)
|
#define SBI_SCRATCH_NEXT_ADDR_OFFSET (6 * __SIZEOF_POINTER__)
|
||||||
/** Offset of next_mode member in sbi_scratch */
|
/** Offset of next_mode member in sbi_scratch */
|
||||||
#define SBI_SCRATCH_NEXT_MODE_OFFSET (4 * __SIZEOF_POINTER__)
|
#define SBI_SCRATCH_NEXT_MODE_OFFSET (7 * __SIZEOF_POINTER__)
|
||||||
/** Offset of warmboot_addr member in sbi_scratch */
|
/** Offset of warmboot_addr member in sbi_scratch */
|
||||||
#define SBI_SCRATCH_WARMBOOT_ADDR_OFFSET (5 * __SIZEOF_POINTER__)
|
#define SBI_SCRATCH_WARMBOOT_ADDR_OFFSET (8 * __SIZEOF_POINTER__)
|
||||||
/** Offset of platform_addr member in sbi_scratch */
|
/** Offset of platform_addr member in sbi_scratch */
|
||||||
#define SBI_SCRATCH_PLATFORM_ADDR_OFFSET (6 * __SIZEOF_POINTER__)
|
#define SBI_SCRATCH_PLATFORM_ADDR_OFFSET (9 * __SIZEOF_POINTER__)
|
||||||
/** Offset of hartid_to_scratch member in sbi_scratch */
|
/** Offset of hartid_to_scratch member in sbi_scratch */
|
||||||
#define SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET (7 * __SIZEOF_POINTER__)
|
#define SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET (10 * __SIZEOF_POINTER__)
|
||||||
/** Offset of trap_exit member in sbi_scratch */
|
/** Offset of trap_exit member in sbi_scratch */
|
||||||
#define SBI_SCRATCH_TRAP_EXIT_OFFSET (8 * __SIZEOF_POINTER__)
|
#define SBI_SCRATCH_TRAP_EXIT_OFFSET (11 * __SIZEOF_POINTER__)
|
||||||
/** Offset of tmp0 member in sbi_scratch */
|
/** Offset of tmp0 member in sbi_scratch */
|
||||||
#define SBI_SCRATCH_TMP0_OFFSET (9 * __SIZEOF_POINTER__)
|
#define SBI_SCRATCH_TMP0_OFFSET (12 * __SIZEOF_POINTER__)
|
||||||
/** Offset of options member in sbi_scratch */
|
/** Offset of options member in sbi_scratch */
|
||||||
#define SBI_SCRATCH_OPTIONS_OFFSET (10 * __SIZEOF_POINTER__)
|
#define SBI_SCRATCH_OPTIONS_OFFSET (13 * __SIZEOF_POINTER__)
|
||||||
/** Offset of extra space in sbi_scratch */
|
/** Offset of extra space in sbi_scratch */
|
||||||
#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (11 * __SIZEOF_POINTER__)
|
#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (14 * __SIZEOF_POINTER__)
|
||||||
/** Maximum size of sbi_scratch (4KB) */
|
/** Maximum size of sbi_scratch (4KB) */
|
||||||
#define SBI_SCRATCH_SIZE (0x1000)
|
#define SBI_SCRATCH_SIZE (0x1000)
|
||||||
|
|
||||||
@@ -53,11 +59,17 @@ struct sbi_scratch {
|
|||||||
unsigned long fw_start;
|
unsigned long fw_start;
|
||||||
/** Size (in bytes) of firmware linked to OpenSBI library */
|
/** Size (in bytes) of firmware linked to OpenSBI library */
|
||||||
unsigned long fw_size;
|
unsigned long fw_size;
|
||||||
|
/** Offset (in bytes) of the R/W section */
|
||||||
|
unsigned long fw_rw_offset;
|
||||||
|
/** Offset (in bytes) of the heap area */
|
||||||
|
unsigned long fw_heap_offset;
|
||||||
|
/** Size (in bytes) of the heap area */
|
||||||
|
unsigned long fw_heap_size;
|
||||||
/** Arg1 (or 'a1' register) of next booting stage for this HART */
|
/** Arg1 (or 'a1' register) of next booting stage for this HART */
|
||||||
unsigned long next_arg1;
|
unsigned long next_arg1;
|
||||||
/** Address of next booting stage for this HART */
|
/** Address of next booting stage for this HART */
|
||||||
unsigned long next_addr;
|
unsigned long next_addr;
|
||||||
/** Priviledge mode of next booting stage for this HART */
|
/** Privilege mode of next booting stage for this HART */
|
||||||
unsigned long next_mode;
|
unsigned long next_mode;
|
||||||
/** Warm boot entry point address for this HART */
|
/** Warm boot entry point address for this HART */
|
||||||
unsigned long warmboot_addr;
|
unsigned long warmboot_addr;
|
||||||
@@ -163,6 +175,9 @@ unsigned long sbi_scratch_alloc_offset(unsigned long size);
|
|||||||
/** Free-up extra space in sbi_scratch */
|
/** Free-up extra space in sbi_scratch */
|
||||||
void sbi_scratch_free_offset(unsigned long offset);
|
void sbi_scratch_free_offset(unsigned long offset);
|
||||||
|
|
||||||
|
/** Amount (in bytes) of used space in in sbi_scratch */
|
||||||
|
unsigned long sbi_scratch_used_space(void);
|
||||||
|
|
||||||
/** Get pointer from offset in sbi_scratch */
|
/** Get pointer from offset in sbi_scratch */
|
||||||
#define sbi_scratch_offset_ptr(scratch, offset) (void *)((char *)(scratch) + (offset))
|
#define sbi_scratch_offset_ptr(scratch, offset) (void *)((char *)(scratch) + (offset))
|
||||||
|
|
||||||
@@ -170,18 +185,68 @@ void sbi_scratch_free_offset(unsigned long offset);
|
|||||||
#define sbi_scratch_thishart_offset_ptr(offset) \
|
#define sbi_scratch_thishart_offset_ptr(offset) \
|
||||||
(void *)((char *)sbi_scratch_thishart_ptr() + (offset))
|
(void *)((char *)sbi_scratch_thishart_ptr() + (offset))
|
||||||
|
|
||||||
/** HART id to scratch table */
|
/** Allocate offset for a data type in sbi_scratch */
|
||||||
extern struct sbi_scratch *hartid_to_scratch_table[];
|
#define sbi_scratch_alloc_type_offset(__type) \
|
||||||
|
sbi_scratch_alloc_offset(sizeof(__type))
|
||||||
|
|
||||||
|
/** Read a data type from sbi_scratch at given offset */
|
||||||
|
#define sbi_scratch_read_type(__scratch, __type, __offset) \
|
||||||
|
({ \
|
||||||
|
*((__type *)sbi_scratch_offset_ptr((__scratch), (__offset))); \
|
||||||
|
})
|
||||||
|
|
||||||
|
/** Write a data type to sbi_scratch at given offset */
|
||||||
|
#define sbi_scratch_write_type(__scratch, __type, __offset, __ptr) \
|
||||||
|
do { \
|
||||||
|
*((__type *)sbi_scratch_offset_ptr((__scratch), (__offset))) \
|
||||||
|
= (__type)(__ptr); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/** Last HART index having a sbi_scratch pointer */
|
||||||
|
extern u32 last_hartindex_having_scratch;
|
||||||
|
|
||||||
|
/** Get last HART index having a sbi_scratch pointer */
|
||||||
|
#define sbi_scratch_last_hartindex() last_hartindex_having_scratch
|
||||||
|
|
||||||
|
/** Check whether a particular HART index is valid or not */
|
||||||
|
#define sbi_hartindex_valid(__hartindex) \
|
||||||
|
(((__hartindex) <= sbi_scratch_last_hartindex()) ? true : false)
|
||||||
|
|
||||||
|
/** HART index to HART id table */
|
||||||
|
extern u32 hartindex_to_hartid_table[];
|
||||||
|
|
||||||
|
/** Get sbi_scratch from HART index */
|
||||||
|
#define sbi_hartindex_to_hartid(__hartindex) \
|
||||||
|
({ \
|
||||||
|
((__hartindex) <= sbi_scratch_last_hartindex()) ?\
|
||||||
|
hartindex_to_hartid_table[__hartindex] : -1U; \
|
||||||
|
})
|
||||||
|
|
||||||
|
/** HART index to scratch table */
|
||||||
|
extern struct sbi_scratch *hartindex_to_scratch_table[];
|
||||||
|
|
||||||
|
/** Get sbi_scratch from HART index */
|
||||||
|
#define sbi_hartindex_to_scratch(__hartindex) \
|
||||||
|
({ \
|
||||||
|
((__hartindex) <= sbi_scratch_last_hartindex()) ?\
|
||||||
|
hartindex_to_scratch_table[__hartindex] : NULL;\
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get logical index for given HART id
|
||||||
|
* @param hartid physical HART id
|
||||||
|
* @returns value between 0 to SBI_HARTMASK_MAX_BITS upon success and
|
||||||
|
* SBI_HARTMASK_MAX_BITS upon failure.
|
||||||
|
*/
|
||||||
|
u32 sbi_hartid_to_hartindex(u32 hartid);
|
||||||
|
|
||||||
/** Get sbi_scratch from HART id */
|
/** Get sbi_scratch from HART id */
|
||||||
#define sbi_hartid_to_scratch(__hartid) \
|
#define sbi_hartid_to_scratch(__hartid) \
|
||||||
hartid_to_scratch_table[__hartid]
|
sbi_hartindex_to_scratch(sbi_hartid_to_hartindex(__hartid))
|
||||||
|
|
||||||
/** Last HART id having a sbi_scratch pointer */
|
/** Check whether particular HART id is valid or not */
|
||||||
extern u32 last_hartid_having_scratch;
|
#define sbi_hartid_valid(__hartid) \
|
||||||
|
sbi_hartindex_valid(sbi_hartid_to_hartindex(__hartid))
|
||||||
/** Get last HART id having a sbi_scratch pointer */
|
|
||||||
#define sbi_scratch_last_hartid() last_hartid_having_scratch
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -43,4 +43,38 @@ bool sbi_system_reset_supported(u32 reset_type, u32 reset_reason);
|
|||||||
|
|
||||||
void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason);
|
void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason);
|
||||||
|
|
||||||
|
/** System suspend device */
|
||||||
|
struct sbi_system_suspend_device {
|
||||||
|
/** Name of the system suspend device */
|
||||||
|
char name[32];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether sleep type is supported by the device
|
||||||
|
*
|
||||||
|
* Returns 0 when @sleep_type supported, SBI_ERR_INVALID_PARAM
|
||||||
|
* when @sleep_type is reserved, or SBI_ERR_NOT_SUPPORTED when
|
||||||
|
* @sleep_type is not reserved and is implemented, but the
|
||||||
|
* platform doesn't support it due to missing dependencies.
|
||||||
|
*/
|
||||||
|
int (*system_suspend_check)(u32 sleep_type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Suspend the system
|
||||||
|
*
|
||||||
|
* @sleep_type: The sleep type identifier passed to the SBI call.
|
||||||
|
* @mmode_resume_addr:
|
||||||
|
* This is the same as sbi_scratch.warmboot_addr. Some platforms
|
||||||
|
* may not be able to return from system_suspend(), so they will
|
||||||
|
* jump directly to this address instead. Platforms which can
|
||||||
|
* return from system_suspend() may ignore this parameter.
|
||||||
|
*/
|
||||||
|
int (*system_suspend)(u32 sleep_type, unsigned long mmode_resume_addr);
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct sbi_system_suspend_device *sbi_system_suspend_get_device(void);
|
||||||
|
void sbi_system_suspend_set_device(struct sbi_system_suspend_device *dev);
|
||||||
|
void sbi_system_suspend_test_enable(void);
|
||||||
|
bool sbi_system_suspend_supported(u32 sleep_type);
|
||||||
|
int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -48,6 +48,24 @@ static inline void sbi_timer_udelay(ulong usecs)
|
|||||||
sbi_timer_delay_loop(usecs, 1000000, NULL, NULL);
|
sbi_timer_delay_loop(usecs, 1000000, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A blocking function that will wait until @p predicate returns true or
|
||||||
|
* @p timeout_ms milliseconds elapsed. @p arg will be passed as argument to
|
||||||
|
* @p predicate function.
|
||||||
|
*
|
||||||
|
* @param predicate Pointer to a function that returns true if certain
|
||||||
|
* condition is met. It shouldn't block the code execution.
|
||||||
|
* @param arg Argument to pass to @p predicate.
|
||||||
|
* @param timeout_ms Timeout value in milliseconds. The function will return
|
||||||
|
* false if @p timeout_ms time period elapsed but still @p predicate doesn't
|
||||||
|
* return true.
|
||||||
|
*
|
||||||
|
* @return true if @p predicate returns true within @p timeout_ms, false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
bool sbi_timer_waitms_until(bool (*predicate)(void *), void *arg,
|
||||||
|
uint64_t timeout_ms);
|
||||||
|
|
||||||
/** Get timer value for current HART */
|
/** Get timer value for current HART */
|
||||||
u64 sbi_timer_value(void);
|
u64 sbi_timer_value(void);
|
||||||
|
|
||||||
|
@@ -20,34 +20,35 @@
|
|||||||
|
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
#define SBI_TLB_FIFO_NUM_ENTRIES 8
|
|
||||||
|
|
||||||
struct sbi_scratch;
|
struct sbi_scratch;
|
||||||
|
|
||||||
|
enum sbi_tlb_type {
|
||||||
|
SBI_TLB_FENCE_I = 0,
|
||||||
|
SBI_TLB_SFENCE_VMA,
|
||||||
|
SBI_TLB_SFENCE_VMA_ASID,
|
||||||
|
SBI_TLB_HFENCE_GVMA_VMID,
|
||||||
|
SBI_TLB_HFENCE_GVMA,
|
||||||
|
SBI_TLB_HFENCE_VVMA_ASID,
|
||||||
|
SBI_TLB_HFENCE_VVMA,
|
||||||
|
SBI_TLB_TYPE_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
struct sbi_tlb_info {
|
struct sbi_tlb_info {
|
||||||
unsigned long start;
|
unsigned long start;
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
unsigned long asid;
|
uint16_t asid;
|
||||||
unsigned long vmid;
|
uint16_t vmid;
|
||||||
void (*local_fn)(struct sbi_tlb_info *tinfo);
|
enum sbi_tlb_type type;
|
||||||
struct sbi_hartmask smask;
|
struct sbi_hartmask smask;
|
||||||
};
|
};
|
||||||
|
|
||||||
void sbi_tlb_local_hfence_vvma(struct sbi_tlb_info *tinfo);
|
#define SBI_TLB_INFO_INIT(__p, __start, __size, __asid, __vmid, __type, __src) \
|
||||||
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 { \
|
do { \
|
||||||
(__p)->start = (__start); \
|
(__p)->start = (__start); \
|
||||||
(__p)->size = (__size); \
|
(__p)->size = (__size); \
|
||||||
(__p)->asid = (__asid); \
|
(__p)->asid = (__asid); \
|
||||||
(__p)->vmid = (__vmid); \
|
(__p)->vmid = (__vmid); \
|
||||||
(__p)->local_fn = (__lfn); \
|
(__p)->type = (__type); \
|
||||||
SBI_HARTMASK_INIT_EXCEPT(&(__p)->smask, (__src)); \
|
SBI_HARTMASK_INIT_EXCEPT(&(__p)->smask, (__src)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
@@ -10,6 +10,8 @@
|
|||||||
#ifndef __SBI_TRAP_H__
|
#ifndef __SBI_TRAP_H__
|
||||||
#define __SBI_TRAP_H__
|
#define __SBI_TRAP_H__
|
||||||
|
|
||||||
|
#include <sbi/riscv_encoding.h>
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
|
|
||||||
/** Index of zero member in sbi_trap_regs */
|
/** Index of zero member in sbi_trap_regs */
|
||||||
@@ -95,8 +97,10 @@
|
|||||||
#define SBI_TRAP_INFO_tval2 3
|
#define SBI_TRAP_INFO_tval2 3
|
||||||
/** Index of tinst member in sbi_trap_info */
|
/** Index of tinst member in sbi_trap_info */
|
||||||
#define SBI_TRAP_INFO_tinst 4
|
#define SBI_TRAP_INFO_tinst 4
|
||||||
|
/** Index of gva member in sbi_trap_info */
|
||||||
|
#define SBI_TRAP_INFO_gva 5
|
||||||
/** Last member index in sbi_trap_info */
|
/** Last member index in sbi_trap_info */
|
||||||
#define SBI_TRAP_INFO_last 5
|
#define SBI_TRAP_INFO_last 6
|
||||||
|
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
@@ -200,8 +204,26 @@ struct sbi_trap_info {
|
|||||||
unsigned long tval2;
|
unsigned long tval2;
|
||||||
/** tinst Trap instruction */
|
/** tinst Trap instruction */
|
||||||
unsigned long tinst;
|
unsigned long tinst;
|
||||||
|
/** gva Guest virtual address in tval flag */
|
||||||
|
unsigned long gva;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline unsigned long sbi_regs_gva(const struct sbi_trap_regs *regs)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If the hypervisor extension is not implemented, mstatus[h].GVA is a
|
||||||
|
* WPRI field, which is guaranteed to read as zero. In addition, in this
|
||||||
|
* case we don't read mstatush and instead pretend it is zero, which
|
||||||
|
* handles privileged spec version < 1.12.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if __riscv_xlen == 32
|
||||||
|
return (regs->mstatusH & MSTATUSH_GVA) ? 1 : 0;
|
||||||
|
#else
|
||||||
|
return (regs->mstatus & MSTATUS_GVA) ? 1 : 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
int sbi_trap_redirect(struct sbi_trap_regs *regs,
|
int sbi_trap_redirect(struct sbi_trap_regs *regs,
|
||||||
struct sbi_trap_info *trap);
|
struct sbi_trap_info *trap);
|
||||||
|
|
||||||
|
@@ -54,16 +54,22 @@ typedef unsigned long virtual_size_t;
|
|||||||
typedef unsigned long physical_addr_t;
|
typedef unsigned long physical_addr_t;
|
||||||
typedef unsigned long physical_size_t;
|
typedef unsigned long physical_size_t;
|
||||||
|
|
||||||
#define TRUE 1
|
typedef uint16_t le16_t;
|
||||||
#define FALSE 0
|
typedef uint16_t be16_t;
|
||||||
#define true TRUE
|
typedef uint32_t le32_t;
|
||||||
#define false FALSE
|
typedef uint32_t be32_t;
|
||||||
|
typedef uint64_t le64_t;
|
||||||
|
typedef uint64_t be64_t;
|
||||||
|
|
||||||
|
#define true 1
|
||||||
|
#define false 0
|
||||||
|
|
||||||
#define NULL ((void *)0)
|
#define NULL ((void *)0)
|
||||||
|
|
||||||
#define __packed __attribute__((packed))
|
#define __packed __attribute__((packed))
|
||||||
#define __noreturn __attribute__((noreturn))
|
#define __noreturn __attribute__((noreturn))
|
||||||
#define __aligned(x) __attribute__((aligned(x)))
|
#define __aligned(x) __attribute__((aligned(x)))
|
||||||
|
#define __always_inline inline __attribute__((always_inline))
|
||||||
|
|
||||||
#define likely(x) __builtin_expect((x), 1)
|
#define likely(x) __builtin_expect((x), 1)
|
||||||
#define unlikely(x) __builtin_expect((x), 0)
|
#define unlikely(x) __builtin_expect((x), 0)
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
#define __SBI_VERSION_H__
|
#define __SBI_VERSION_H__
|
||||||
|
|
||||||
#define OPENSBI_VERSION_MAJOR 1
|
#define OPENSBI_VERSION_MAJOR 1
|
||||||
#define OPENSBI_VERSION_MINOR 1
|
#define OPENSBI_VERSION_MINOR 4
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OpenSBI 32-bit version with:
|
* OpenSBI 32-bit version with:
|
||||||
|
@@ -13,6 +13,8 @@
|
|||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_FDT_DOMAIN
|
||||||
|
|
||||||
struct sbi_domain;
|
struct sbi_domain;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,4 +72,11 @@ void fdt_domain_fixup(void *fdt);
|
|||||||
*/
|
*/
|
||||||
int fdt_domains_populate(void *fdt);
|
int fdt_domains_populate(void *fdt);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline void fdt_domain_fixup(void *fdt) { }
|
||||||
|
static inline int fdt_domains_populate(void *fdt) { return 0; }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __FDT_DOMAIN_H__ */
|
#endif /* __FDT_DOMAIN_H__ */
|
||||||
|
@@ -9,6 +9,29 @@
|
|||||||
#ifndef __FDT_FIXUP_H__
|
#ifndef __FDT_FIXUP_H__
|
||||||
#define __FDT_FIXUP_H__
|
#define __FDT_FIXUP_H__
|
||||||
|
|
||||||
|
struct sbi_cpu_idle_state {
|
||||||
|
const char *name;
|
||||||
|
uint32_t suspend_param;
|
||||||
|
bool local_timer_stop;
|
||||||
|
uint32_t entry_latency_us;
|
||||||
|
uint32_t exit_latency_us;
|
||||||
|
uint32_t min_residency_us;
|
||||||
|
uint32_t wakeup_latency_us;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add CPU idle states to cpu nodes in the DT
|
||||||
|
*
|
||||||
|
* Add information about CPU idle states to the devicetree. This function
|
||||||
|
* assumes that CPU idle states are not already present in the devicetree, and
|
||||||
|
* that all CPU states are equally applicable to all CPUs.
|
||||||
|
*
|
||||||
|
* @param fdt: device tree blob
|
||||||
|
* @param states: array of idle state descriptions, ending with empty element
|
||||||
|
* @return zero on success and -ve on failure
|
||||||
|
*/
|
||||||
|
int fdt_add_cpu_idle_states(void *dtb, const struct sbi_cpu_idle_state *state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fix up the CPU node in the device tree
|
* Fix up the CPU node in the device tree
|
||||||
*
|
*
|
||||||
@@ -70,20 +93,6 @@ void fdt_plic_fixup(void *fdt);
|
|||||||
*/
|
*/
|
||||||
int fdt_reserved_memory_fixup(void *fdt);
|
int fdt_reserved_memory_fixup(void *fdt);
|
||||||
|
|
||||||
/**
|
|
||||||
* Fix up the reserved memory subnodes in the device tree
|
|
||||||
*
|
|
||||||
* This routine adds the no-map property to the reserved memory subnodes so
|
|
||||||
* that the OS does not map those PMP protected memory regions.
|
|
||||||
*
|
|
||||||
* Platform codes must call this helper in their final_init() after fdt_fixups()
|
|
||||||
* if the OS should not map the PMP protected reserved regions.
|
|
||||||
*
|
|
||||||
* @param fdt: device tree blob
|
|
||||||
* @return zero on success and -ve on failure
|
|
||||||
*/
|
|
||||||
int fdt_reserved_memory_nomap_fixup(void *fdt);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* General device tree fix-up
|
* General device tree fix-up
|
||||||
*
|
*
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
#define __FDT_HELPER_H__
|
#define __FDT_HELPER_H__
|
||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
#include <sbi/sbi_scratch.h>
|
#include <sbi/sbi_domain.h>
|
||||||
|
|
||||||
struct fdt_match {
|
struct fdt_match {
|
||||||
const char *compatible;
|
const char *compatible;
|
||||||
@@ -48,6 +48,9 @@ int fdt_parse_phandle_with_args(void *fdt, int nodeoff,
|
|||||||
int fdt_get_node_addr_size(void *fdt, int node, int index,
|
int fdt_get_node_addr_size(void *fdt, int node, int index,
|
||||||
uint64_t *addr, uint64_t *size);
|
uint64_t *addr, uint64_t *size);
|
||||||
|
|
||||||
|
int fdt_get_node_addr_size_by_name(void *fdt, int node, const char *name,
|
||||||
|
uint64_t *addr, uint64_t *size);
|
||||||
|
|
||||||
bool fdt_node_is_enabled(void *fdt, int nodeoff);
|
bool fdt_node_is_enabled(void *fdt, int nodeoff);
|
||||||
|
|
||||||
int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid);
|
int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid);
|
||||||
@@ -56,17 +59,23 @@ int fdt_parse_max_enabled_hart_id(void *fdt, u32 *max_hartid);
|
|||||||
|
|
||||||
int fdt_parse_timebase_frequency(void *fdt, unsigned long *freq);
|
int fdt_parse_timebase_frequency(void *fdt, unsigned long *freq);
|
||||||
|
|
||||||
|
int fdt_parse_isa_extensions(void *fdt, unsigned int hard_id,
|
||||||
|
unsigned long *extensions);
|
||||||
|
|
||||||
int fdt_parse_gaisler_uart_node(void *fdt, int nodeoffset,
|
int fdt_parse_gaisler_uart_node(void *fdt, int nodeoffset,
|
||||||
struct platform_uart_data *uart);
|
struct platform_uart_data *uart);
|
||||||
|
|
||||||
|
int fdt_parse_renesas_scif_node(void *fdt, int nodeoffset,
|
||||||
|
struct platform_uart_data *uart);
|
||||||
|
|
||||||
int fdt_parse_shakti_uart_node(void *fdt, int nodeoffset,
|
int fdt_parse_shakti_uart_node(void *fdt, int nodeoffset,
|
||||||
struct platform_uart_data *uart);
|
struct platform_uart_data *uart);
|
||||||
|
|
||||||
int fdt_parse_sifive_uart_node(void *fdt, int nodeoffset,
|
int fdt_parse_sifive_uart_node(void *fdt, int nodeoffset,
|
||||||
struct platform_uart_data *uart);
|
struct platform_uart_data *uart);
|
||||||
|
|
||||||
int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
|
int fdt_parse_uart_node(void *fdt, int nodeoffset,
|
||||||
struct platform_uart_data *uart);
|
struct platform_uart_data *uart);
|
||||||
|
|
||||||
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
|
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
|
||||||
const char *compatible);
|
const char *compatible);
|
||||||
@@ -90,17 +99,24 @@ 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);
|
int fdt_parse_plic(void *fdt, struct plic_data *plic, const char *compat);
|
||||||
|
|
||||||
int fdt_parse_aclint_node(void *fdt, int nodeoffset, bool for_timer,
|
int fdt_parse_aclint_node(void *fdt, int nodeoffset,
|
||||||
|
bool for_timer, bool allow_regname,
|
||||||
unsigned long *out_addr1, unsigned long *out_size1,
|
unsigned long *out_addr1, unsigned long *out_size1,
|
||||||
unsigned long *out_addr2, unsigned long *out_size2,
|
unsigned long *out_addr2, unsigned long *out_size2,
|
||||||
u32 *out_first_hartid, u32 *out_hart_count);
|
u32 *out_first_hartid, u32 *out_hart_count);
|
||||||
|
|
||||||
|
int fdt_parse_plmt_node(void *fdt, int nodeoffset, unsigned long *plmt_base,
|
||||||
|
unsigned long *plmt_size, u32 *hart_count);
|
||||||
|
|
||||||
|
int fdt_parse_plicsw_node(void *fdt, int nodeoffset, unsigned long *plicsw_base,
|
||||||
|
unsigned long *size, u32 *hart_count);
|
||||||
|
|
||||||
int fdt_parse_compat_addr(void *fdt, uint64_t *addr,
|
int fdt_parse_compat_addr(void *fdt, uint64_t *addr,
|
||||||
const char *compatible);
|
const char *compatible);
|
||||||
|
|
||||||
static inline void *fdt_get_address(void)
|
static inline void *fdt_get_address(void)
|
||||||
{
|
{
|
||||||
return sbi_scratch_thishart_arg1_ptr();
|
return (void *)root.next_arg1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* __FDT_HELPER_H__ */
|
#endif /* __FDT_HELPER_H__ */
|
||||||
|
@@ -13,6 +13,25 @@
|
|||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
struct fdt_pmu_hw_event_select_map {
|
||||||
|
uint32_t eidx;
|
||||||
|
uint64_t select;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fdt_pmu_hw_event_counter_map {
|
||||||
|
uint32_t eidx_start;
|
||||||
|
uint32_t eidx_end;
|
||||||
|
uint32_t ctr_map;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fdt_pmu_raw_event_counter_map {
|
||||||
|
uint64_t select;
|
||||||
|
uint64_t select_mask;
|
||||||
|
uint32_t ctr_map;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_FDT_PMU
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fix up the PMU node in the device tree
|
* Fix up the PMU node in the device tree
|
||||||
*
|
*
|
||||||
@@ -24,7 +43,7 @@
|
|||||||
*
|
*
|
||||||
* @param fdt device tree blob
|
* @param fdt device tree blob
|
||||||
*/
|
*/
|
||||||
void fdt_pmu_fixup(void *fdt);
|
int fdt_pmu_fixup(void *fdt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup PMU data from device tree
|
* Setup PMU data from device tree
|
||||||
@@ -43,4 +62,17 @@ int fdt_pmu_setup(void *fdt);
|
|||||||
*/
|
*/
|
||||||
uint64_t fdt_pmu_get_select_value(uint32_t event_idx);
|
uint64_t fdt_pmu_get_select_value(uint32_t event_idx);
|
||||||
|
|
||||||
|
/** The event index to selector value table instance */
|
||||||
|
extern struct fdt_pmu_hw_event_select_map fdt_pmu_evt_select[];
|
||||||
|
/** The number of valid entries in fdt_pmu_evt_select[] */
|
||||||
|
extern uint32_t hw_event_count;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline void fdt_pmu_fixup(void *fdt) { }
|
||||||
|
static inline int fdt_pmu_setup(void *fdt) { return 0; }
|
||||||
|
static inline uint64_t fdt_pmu_get_select_value(uint32_t event_idx) { return 0; }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
21
include/sbi_utils/i2c/dw_i2c.h
Normal file
21
include/sbi_utils/i2c/dw_i2c.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 StarFive Technology Co., Ltd.
|
||||||
|
*
|
||||||
|
* Author: Minda Chen <minda.chen@starfivetech.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DW_I2C_H__
|
||||||
|
#define __DW_I2C_H__
|
||||||
|
|
||||||
|
#include <sbi_utils/i2c/i2c.h>
|
||||||
|
|
||||||
|
int dw_i2c_init(struct i2c_adapter *, int nodeoff);
|
||||||
|
|
||||||
|
struct dw_i2c_adapter {
|
||||||
|
unsigned long addr;
|
||||||
|
struct i2c_adapter adapter;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@@ -15,9 +15,6 @@
|
|||||||
|
|
||||||
/** Representation of a I2C adapter */
|
/** Representation of a I2C adapter */
|
||||||
struct 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 */
|
/** Unique ID of the I2C adapter assigned by the driver */
|
||||||
int id;
|
int id;
|
||||||
|
|
||||||
|
39
include/sbi_utils/ipi/andes_plicsw.h
Normal file
39
include/sbi_utils/ipi/andes_plicsw.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Andes Technology Corporation
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Zong Li <zong@andestech.com>
|
||||||
|
* Nylon Chen <nylon7@andestech.com>
|
||||||
|
* Leo Yu-Chi Liang <ycliang@andestech.com>
|
||||||
|
* Yu Chien Peter Lin <peterlin@andestech.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _IPI_ANDES_PLICSW_H_
|
||||||
|
#define _IPI_ANDES_PLICSW_H_
|
||||||
|
|
||||||
|
#define PLICSW_PRIORITY_BASE 0x4
|
||||||
|
|
||||||
|
#define PLICSW_PENDING_BASE 0x1000
|
||||||
|
|
||||||
|
#define PLICSW_ENABLE_BASE 0x2000
|
||||||
|
#define PLICSW_ENABLE_STRIDE 0x80
|
||||||
|
|
||||||
|
#define PLICSW_CONTEXT_BASE 0x200000
|
||||||
|
#define PLICSW_CONTEXT_STRIDE 0x1000
|
||||||
|
#define PLICSW_CONTEXT_CLAIM 0x4
|
||||||
|
|
||||||
|
#define PLICSW_REGION_ALIGN 0x1000
|
||||||
|
|
||||||
|
struct plicsw_data {
|
||||||
|
unsigned long addr;
|
||||||
|
unsigned long size;
|
||||||
|
uint32_t hart_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
int plicsw_warm_ipi_init(void);
|
||||||
|
|
||||||
|
int plicsw_cold_ipi_init(struct plicsw_data *plicsw);
|
||||||
|
|
||||||
|
#endif /* _IPI_ANDES_PLICSW_H_ */
|
@@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_FDT_IPI
|
||||||
|
|
||||||
struct fdt_ipi {
|
struct fdt_ipi {
|
||||||
const struct fdt_match *match_table;
|
const struct fdt_match *match_table;
|
||||||
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||||
@@ -23,4 +25,11 @@ void fdt_ipi_exit(void);
|
|||||||
|
|
||||||
int fdt_ipi_init(bool cold_boot);
|
int fdt_ipi_init(bool cold_boot);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline void fdt_ipi_exit(void) { }
|
||||||
|
static inline int fdt_ipi_init(bool cold_boot) { return 0; }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_FDT_IRQCHIP
|
||||||
|
|
||||||
struct fdt_irqchip {
|
struct fdt_irqchip {
|
||||||
const struct fdt_match *match_table;
|
const struct fdt_match *match_table;
|
||||||
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||||
@@ -23,4 +25,12 @@ void fdt_irqchip_exit(void);
|
|||||||
|
|
||||||
int fdt_irqchip_init(bool cold_boot);
|
int fdt_irqchip_init(bool cold_boot);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline void fdt_irqchip_exit(void) { }
|
||||||
|
|
||||||
|
static inline int fdt_irqchip_init(bool cold_boot) { return 0; }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -9,13 +9,24 @@
|
|||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
void fdt_plic_priority_save(u8 *priority);
|
/**
|
||||||
|
* Save the PLIC priority state
|
||||||
|
* @param priority pointer to the memory region for the saved priority
|
||||||
|
* @param num size of the memory region including interrupt source 0
|
||||||
|
*/
|
||||||
|
void fdt_plic_priority_save(u8 *priority, u32 num);
|
||||||
|
|
||||||
void fdt_plic_priority_restore(const u8 *priority);
|
/**
|
||||||
|
* Restore the PLIC priority state
|
||||||
|
* @param priority pointer to the memory region for the saved priority
|
||||||
|
* @param num size of the memory region including interrupt source 0
|
||||||
|
*/
|
||||||
|
void fdt_plic_priority_restore(const u8 *priority, u32 num);
|
||||||
|
|
||||||
void fdt_plic_context_save(bool smode, u32 *enable, u32 *threshold);
|
void fdt_plic_context_save(bool smode, u32 *enable, u32 *threshold, u32 num);
|
||||||
|
|
||||||
void fdt_plic_context_restore(bool smode, const u32 *enable, u32 threshold);
|
void fdt_plic_context_restore(bool smode, const u32 *enable, u32 threshold,
|
||||||
|
u32 num);
|
||||||
|
|
||||||
void thead_plic_restore(void);
|
void thead_plic_restore(void);
|
||||||
|
|
||||||
|
@@ -33,6 +33,8 @@ struct imsic_data {
|
|||||||
struct imsic_regs regs[IMSIC_MAX_REGS];
|
struct imsic_regs regs[IMSIC_MAX_REGS];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_IRQCHIP_IMSIC
|
||||||
|
|
||||||
int imsic_map_hartid_to_data(u32 hartid, struct imsic_data *imsic, int file);
|
int imsic_map_hartid_to_data(u32 hartid, struct imsic_data *imsic, int file);
|
||||||
|
|
||||||
struct imsic_data *imsic_get_data(u32 hartid);
|
struct imsic_data *imsic_get_data(u32 hartid);
|
||||||
@@ -47,4 +49,12 @@ int imsic_data_check(struct imsic_data *imsic);
|
|||||||
|
|
||||||
int imsic_cold_irqchip_init(struct imsic_data *imsic);
|
int imsic_cold_irqchip_init(struct imsic_data *imsic);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline void imsic_local_irqchip_init(void) { }
|
||||||
|
|
||||||
|
static inline int imsic_data_check(struct imsic_data *imsic) { return 0; }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -14,19 +14,21 @@
|
|||||||
|
|
||||||
struct plic_data {
|
struct plic_data {
|
||||||
unsigned long addr;
|
unsigned long addr;
|
||||||
|
unsigned long size;
|
||||||
unsigned long num_src;
|
unsigned long num_src;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* So far, priorities on all consumers of these functions fit in 8 bits. */
|
/* So far, priorities on all consumers of these functions fit in 8 bits. */
|
||||||
void plic_priority_save(const struct plic_data *plic, u8 *priority);
|
void plic_priority_save(const struct plic_data *plic, u8 *priority, u32 num);
|
||||||
|
|
||||||
void plic_priority_restore(const struct plic_data *plic, const u8 *priority);
|
void plic_priority_restore(const struct plic_data *plic, const u8 *priority,
|
||||||
|
u32 num);
|
||||||
|
|
||||||
void plic_context_save(const struct plic_data *plic, int context_id,
|
void plic_context_save(const struct plic_data *plic, int context_id,
|
||||||
u32 *enable, u32 *threshold);
|
u32 *enable, u32 *threshold, u32 num);
|
||||||
|
|
||||||
void plic_context_restore(const struct plic_data *plic, int context_id,
|
void plic_context_restore(const struct plic_data *plic, int context_id,
|
||||||
const u32 *enable, u32 threshold);
|
const u32 *enable, u32 threshold, u32 num);
|
||||||
|
|
||||||
int plic_context_init(const struct plic_data *plic, int context_id,
|
int plic_context_init(const struct plic_data *plic, int context_id,
|
||||||
bool enable, u32 threshold);
|
bool enable, u32 threshold);
|
||||||
|
31
include/sbi_utils/regmap/fdt_regmap.h
Normal file
31
include/sbi_utils/regmap/fdt_regmap.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Ventana Micro Systems Inc.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <apatel@ventanamicro.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FDT_REGMAP_H__
|
||||||
|
#define __FDT_REGMAP_H__
|
||||||
|
|
||||||
|
#include <sbi_utils/regmap/regmap.h>
|
||||||
|
|
||||||
|
struct fdt_phandle_args;
|
||||||
|
|
||||||
|
/** FDT based regmap driver */
|
||||||
|
struct fdt_regmap {
|
||||||
|
const struct fdt_match *match_table;
|
||||||
|
int (*init)(void *fdt, int nodeoff, u32 phandle,
|
||||||
|
const struct fdt_match *match);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Get regmap instance based on phandle */
|
||||||
|
int fdt_regmap_get_by_phandle(void *fdt, u32 phandle,
|
||||||
|
struct regmap **out_rmap);
|
||||||
|
|
||||||
|
/** Get regmap instance based on "regmap' property of the specified DT node */
|
||||||
|
int fdt_regmap_get(void *fdt, int nodeoff, struct regmap **out_rmap);
|
||||||
|
|
||||||
|
#endif
|
67
include/sbi_utils/regmap/regmap.h
Normal file
67
include/sbi_utils/regmap/regmap.h
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Ventana Micro Systems Inc.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <apatel@ventanamicro.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __REGMAP_H__
|
||||||
|
#define __REGMAP_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
#include <sbi/sbi_list.h>
|
||||||
|
|
||||||
|
/** Representation of a regmap instance */
|
||||||
|
struct regmap {
|
||||||
|
/** Uniquie ID of the regmap instance assigned by the driver */
|
||||||
|
unsigned int id;
|
||||||
|
|
||||||
|
/** Configuration of regmap registers */
|
||||||
|
int reg_shift;
|
||||||
|
int reg_stride;
|
||||||
|
unsigned int reg_base;
|
||||||
|
unsigned int reg_max;
|
||||||
|
|
||||||
|
/** Read a regmap register */
|
||||||
|
int (*reg_read)(struct regmap *rmap, unsigned int reg,
|
||||||
|
unsigned int *val);
|
||||||
|
|
||||||
|
/** Write a regmap register */
|
||||||
|
int (*reg_write)(struct regmap *rmap, unsigned int reg,
|
||||||
|
unsigned int val);
|
||||||
|
|
||||||
|
/** Read-modify-write a regmap register */
|
||||||
|
int (*reg_update_bits)(struct regmap *rmap, unsigned int reg,
|
||||||
|
unsigned int mask, unsigned int val);
|
||||||
|
|
||||||
|
/** List */
|
||||||
|
struct sbi_dlist node;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct regmap *to_regmap(struct sbi_dlist *node)
|
||||||
|
{
|
||||||
|
return container_of(node, struct regmap, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Find a registered regmap instance */
|
||||||
|
struct regmap *regmap_find(unsigned int id);
|
||||||
|
|
||||||
|
/** Register a regmap instance */
|
||||||
|
int regmap_add(struct regmap *rmap);
|
||||||
|
|
||||||
|
/** Un-register a regmap instance */
|
||||||
|
void regmap_remove(struct regmap *rmap);
|
||||||
|
|
||||||
|
/** Read a register in a regmap instance */
|
||||||
|
int regmap_read(struct regmap *rmap, unsigned int reg, unsigned int *val);
|
||||||
|
|
||||||
|
/** Write a register in a regmap instance */
|
||||||
|
int regmap_write(struct regmap *rmap, unsigned int reg, unsigned int val);
|
||||||
|
|
||||||
|
/** Read-modify-write a register in a regmap instance */
|
||||||
|
int regmap_update_bits(struct regmap *rmap, unsigned int reg,
|
||||||
|
unsigned int mask, unsigned int val);
|
||||||
|
|
||||||
|
#endif
|
@@ -17,6 +17,8 @@ struct fdt_reset {
|
|||||||
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_FDT_RESET
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fdt_reset_driver_init() - initialize reset driver based on the device-tree
|
* fdt_reset_driver_init() - initialize reset driver based on the device-tree
|
||||||
*/
|
*/
|
||||||
@@ -29,4 +31,14 @@ int fdt_reset_driver_init(void *fdt, struct fdt_reset *drv);
|
|||||||
*/
|
*/
|
||||||
void fdt_reset_init(void);
|
void fdt_reset_init(void);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline int fdt_reset_driver_init(void *fdt, struct fdt_reset *drv)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static inline void fdt_reset_init(void) { }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
16
include/sbi_utils/serial/cadence-uart.h
Normal file
16
include/sbi_utils/serial/cadence-uart.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 StarFive Technology Co., Ltd.
|
||||||
|
*
|
||||||
|
* Author: Jun Liang Tan <junliang.tan@linux.starfivetech.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SERIAL_CADENCE_UART_H__
|
||||||
|
#define __SERIAL_CADENCE_UART_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
int cadence_uart_init(unsigned long base, u32 in_freq, u32 baudrate);
|
||||||
|
|
||||||
|
#endif
|
@@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_FDT_SERIAL
|
||||||
|
|
||||||
struct fdt_serial {
|
struct fdt_serial {
|
||||||
const struct fdt_match *match_table;
|
const struct fdt_match *match_table;
|
||||||
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||||
@@ -19,4 +21,10 @@ struct fdt_serial {
|
|||||||
|
|
||||||
int fdt_serial_init(void);
|
int fdt_serial_init(void);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline int fdt_serial_init(void) { return 0; }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
11
include/sbi_utils/serial/renesas-scif.h
Normal file
11
include/sbi_utils/serial/renesas-scif.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Renesas Electronics Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SERIAL_RENESAS_SCIF_H__
|
||||||
|
#define __SERIAL_RENESAS_SCIF_H__
|
||||||
|
|
||||||
|
int renesas_scif_init(unsigned long base, u32 in_freq, u32 baudrate);
|
||||||
|
|
||||||
|
#endif /* __SERIAL_RENESAS_SCIF_H__ */
|
47
include/sbi_utils/serial/semihosting.h
Normal file
47
include/sbi_utils/serial/semihosting.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Ventana Micro Systems Inc.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <apatel@ventanamicro.com>
|
||||||
|
* Kautuk Consul <kconsul@ventanamicro.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SERIAL_SEMIHOSTING_H__
|
||||||
|
#define __SERIAL_SEMIHOSTING_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enum semihosting_open_mode - Numeric file modes for use with semihosting_open()
|
||||||
|
* MODE_READ: 'r'
|
||||||
|
* MODE_BINARY: 'b'
|
||||||
|
* MODE_PLUS: '+'
|
||||||
|
* MODE_WRITE: 'w'
|
||||||
|
* MODE_APPEND: 'a'
|
||||||
|
*
|
||||||
|
* These modes represent the mode string used by fopen(3) in a form which can
|
||||||
|
* be passed to semihosting_open(). These do NOT correspond directly to %O_RDONLY,
|
||||||
|
* %O_CREAT, etc; see fopen(3) for details. In particular, @MODE_PLUS
|
||||||
|
* effectively results in adding %O_RDWR, and @MODE_WRITE will add %O_TRUNC.
|
||||||
|
* For compatibility, @MODE_BINARY should be added when opening non-text files
|
||||||
|
* (such as images).
|
||||||
|
*/
|
||||||
|
enum semihosting_open_mode {
|
||||||
|
MODE_READ = 0x0,
|
||||||
|
MODE_BINARY = 0x1,
|
||||||
|
MODE_PLUS = 0x2,
|
||||||
|
MODE_WRITE = 0x4,
|
||||||
|
MODE_APPEND = 0x8,
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_SEMIHOSTING
|
||||||
|
int semihosting_init(void);
|
||||||
|
int semihosting_enabled(void);
|
||||||
|
#else
|
||||||
|
static inline int semihosting_init(void) { return SBI_ENODEV; }
|
||||||
|
static inline int semihosting_enabled(void) { return 0; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
59
include/sbi_utils/sys/atcsmu.h
Normal file
59
include/sbi_utils/sys/atcsmu.h
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Andes Technology Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SYS_ATCSMU_H
|
||||||
|
#define _SYS_ATCSMU_H
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
/* clang-format off */
|
||||||
|
|
||||||
|
#define PCS0_WE_OFFSET 0x90
|
||||||
|
#define PCSm_WE_OFFSET(i) ((i + 3) * 0x20 + PCS0_WE_OFFSET)
|
||||||
|
|
||||||
|
#define PCS0_CTL_OFFSET 0x94
|
||||||
|
#define PCSm_CTL_OFFSET(i) ((i + 3) * 0x20 + PCS0_CTL_OFFSET)
|
||||||
|
#define PCS_CTL_CMD_SHIFT 0
|
||||||
|
#define PCS_CTL_PARAM_SHIFT 3
|
||||||
|
#define SLEEP_CMD 0x3
|
||||||
|
#define WAKEUP_CMD (0x0 | (1 << PCS_CTL_PARAM_SHIFT))
|
||||||
|
#define LIGHTSLEEP_MODE 0
|
||||||
|
#define DEEPSLEEP_MODE 1
|
||||||
|
#define LIGHT_SLEEP_CMD (SLEEP_CMD | (LIGHTSLEEP_MODE << PCS_CTL_PARAM_SHIFT))
|
||||||
|
#define DEEP_SLEEP_CMD (SLEEP_CMD | (DEEPSLEEP_MODE << PCS_CTL_PARAM_SHIFT))
|
||||||
|
|
||||||
|
#define PCS0_CFG_OFFSET 0x80
|
||||||
|
#define PCSm_CFG_OFFSET(i) ((i + 3) * 0x20 + PCS0_CFG_OFFSET)
|
||||||
|
#define PCS_CFG_LIGHT_SLEEP_SHIFT 2
|
||||||
|
#define PCS_CFG_LIGHT_SLEEP (1 << PCS_CFG_LIGHT_SLEEP_SHIFT)
|
||||||
|
#define PCS_CFG_DEEP_SLEEP_SHIFT 3
|
||||||
|
#define PCS_CFG_DEEP_SLEEP (1 << PCS_CFG_DEEP_SLEEP_SHIFT)
|
||||||
|
|
||||||
|
#define RESET_VEC_LO_OFFSET 0x50
|
||||||
|
#define RESET_VEC_HI_OFFSET 0x60
|
||||||
|
#define RESET_VEC_8CORE_OFFSET 0x1a0
|
||||||
|
#define HARTn_RESET_VEC_LO(n) (RESET_VEC_LO_OFFSET + \
|
||||||
|
((n) < 4 ? 0 : RESET_VEC_8CORE_OFFSET) + \
|
||||||
|
((n) * 0x4))
|
||||||
|
#define HARTn_RESET_VEC_HI(n) (RESET_VEC_HI_OFFSET + \
|
||||||
|
((n) < 4 ? 0 : RESET_VEC_8CORE_OFFSET) + \
|
||||||
|
((n) * 0x4))
|
||||||
|
|
||||||
|
#define PCS_MAX_NR 8
|
||||||
|
#define FLASH_BASE 0x80000000ULL
|
||||||
|
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
|
struct smu_data {
|
||||||
|
unsigned long addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
int smu_set_wakeup_events(struct smu_data *smu, u32 events, u32 hartid);
|
||||||
|
bool smu_support_sleep_mode(struct smu_data *smu, u32 sleep_mode, u32 hartid);
|
||||||
|
int smu_set_command(struct smu_data *smu, u32 pcs_ctl, u32 hartid);
|
||||||
|
int smu_set_reset_vector(struct smu_data *smu, ulong wakeup_addr, u32 hartid);
|
||||||
|
|
||||||
|
#endif /* _SYS_ATCSMU_H */
|
@@ -1,17 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* Anup Patel <anup.patel@wdc.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __SYS_SIFIVE_TEST_H__
|
|
||||||
#define __SYS_SIFIVE_TEST_H__
|
|
||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
|
||||||
|
|
||||||
int sifive_test_init(unsigned long base);
|
|
||||||
|
|
||||||
#endif
|
|
@@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
#define CLINT_MTIMER_OFFSET 0x4000
|
#define CLINT_MTIMER_OFFSET 0x4000
|
||||||
|
|
||||||
|
#define MTIMER_REGION_ALIGN 0x1000
|
||||||
|
|
||||||
struct aclint_mtimer_data {
|
struct aclint_mtimer_data {
|
||||||
/* Public details */
|
/* Public details */
|
||||||
unsigned long mtime_freq;
|
unsigned long mtime_freq;
|
||||||
|
29
include/sbi_utils/timer/andes_plmt.h
Normal file
29
include/sbi_utils/timer/andes_plmt.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Andes Technology Corporation
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Zong Li <zong@andestech.com>
|
||||||
|
* Nylon Chen <nylon7@andestech.com>
|
||||||
|
* Yu Chien Peter Lin <peterlin@andestech.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TIMER_ANDES_PLMT_H__
|
||||||
|
#define __TIMER_ANDES_PLMT_H__
|
||||||
|
|
||||||
|
#define DEFAULT_AE350_PLMT_FREQ 60000000
|
||||||
|
#define PLMT_REGION_ALIGN 0x1000
|
||||||
|
|
||||||
|
struct plmt_data {
|
||||||
|
u32 hart_count;
|
||||||
|
unsigned long size;
|
||||||
|
unsigned long timer_freq;
|
||||||
|
volatile u64 *time_val;
|
||||||
|
volatile u64 *time_cmp;
|
||||||
|
};
|
||||||
|
|
||||||
|
int plmt_cold_timer_init(struct plmt_data *plmt);
|
||||||
|
int plmt_warm_timer_init(void);
|
||||||
|
|
||||||
|
#endif /* __TIMER_ANDES_PLMT_H__ */
|
@@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_FDT_TIMER
|
||||||
|
|
||||||
struct fdt_timer {
|
struct fdt_timer {
|
||||||
const struct fdt_match *match_table;
|
const struct fdt_match *match_table;
|
||||||
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||||
@@ -23,4 +25,11 @@ void fdt_timer_exit(void);
|
|||||||
|
|
||||||
int fdt_timer_init(bool cold_boot);
|
int fdt_timer_init(bool cold_boot);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline void fdt_timer_exit(void) { }
|
||||||
|
static inline int fdt_timer_init(bool cold_boot) { return 0; }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
49
lib/sbi/Kconfig
Normal file
49
lib/sbi/Kconfig
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
menu "SBI Extension Support"
|
||||||
|
|
||||||
|
config SBI_ECALL_TIME
|
||||||
|
bool "Timer extension"
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SBI_ECALL_RFENCE
|
||||||
|
bool "RFENCE extension"
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SBI_ECALL_IPI
|
||||||
|
bool "IPI extension"
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SBI_ECALL_HSM
|
||||||
|
bool "Hart State Management extension"
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SBI_ECALL_SRST
|
||||||
|
bool "System Reset extension"
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SBI_ECALL_SUSP
|
||||||
|
bool "System Suspend extension"
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SBI_ECALL_PMU
|
||||||
|
bool "Performance Monitoring Unit extension"
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SBI_ECALL_DBCN
|
||||||
|
bool "Debug Console extension"
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SBI_ECALL_CPPC
|
||||||
|
bool "CPPC extension"
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SBI_ECALL_LEGACY
|
||||||
|
bool "SBI v0.1 legacy extensions"
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SBI_ECALL_VENDOR
|
||||||
|
bool "Platform-defined vendor extensions"
|
||||||
|
default y
|
||||||
|
|
||||||
|
endmenu
|
@@ -12,20 +12,54 @@ libsbi-objs-y += riscv_atomic.o
|
|||||||
libsbi-objs-y += riscv_hardfp.o
|
libsbi-objs-y += riscv_hardfp.o
|
||||||
libsbi-objs-y += riscv_locks.o
|
libsbi-objs-y += riscv_locks.o
|
||||||
|
|
||||||
|
libsbi-objs-y += sbi_ecall.o
|
||||||
|
libsbi-objs-y += sbi_ecall_exts.o
|
||||||
|
|
||||||
|
# The order of below extensions is performance optimized
|
||||||
|
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_TIME) += ecall_time
|
||||||
|
libsbi-objs-$(CONFIG_SBI_ECALL_TIME) += sbi_ecall_time.o
|
||||||
|
|
||||||
|
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_RFENCE) += ecall_rfence
|
||||||
|
libsbi-objs-$(CONFIG_SBI_ECALL_RFENCE) += sbi_ecall_rfence.o
|
||||||
|
|
||||||
|
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_IPI) += ecall_ipi
|
||||||
|
libsbi-objs-$(CONFIG_SBI_ECALL_IPI) += sbi_ecall_ipi.o
|
||||||
|
|
||||||
|
carray-sbi_ecall_exts-y += ecall_base
|
||||||
|
libsbi-objs-y += sbi_ecall_base.o
|
||||||
|
|
||||||
|
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_HSM) += ecall_hsm
|
||||||
|
libsbi-objs-$(CONFIG_SBI_ECALL_HSM) += sbi_ecall_hsm.o
|
||||||
|
|
||||||
|
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_SRST) += ecall_srst
|
||||||
|
libsbi-objs-$(CONFIG_SBI_ECALL_SRST) += sbi_ecall_srst.o
|
||||||
|
|
||||||
|
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_SUSP) += ecall_susp
|
||||||
|
libsbi-objs-$(CONFIG_SBI_ECALL_SUSP) += sbi_ecall_susp.o
|
||||||
|
|
||||||
|
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_PMU) += ecall_pmu
|
||||||
|
libsbi-objs-$(CONFIG_SBI_ECALL_PMU) += sbi_ecall_pmu.o
|
||||||
|
|
||||||
|
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_DBCN) += ecall_dbcn
|
||||||
|
libsbi-objs-$(CONFIG_SBI_ECALL_DBCN) += sbi_ecall_dbcn.o
|
||||||
|
|
||||||
|
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_CPPC) += ecall_cppc
|
||||||
|
libsbi-objs-$(CONFIG_SBI_ECALL_CPPC) += sbi_ecall_cppc.o
|
||||||
|
|
||||||
|
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_LEGACY) += ecall_legacy
|
||||||
|
libsbi-objs-$(CONFIG_SBI_ECALL_LEGACY) += sbi_ecall_legacy.o
|
||||||
|
|
||||||
|
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_VENDOR) += ecall_vendor
|
||||||
|
libsbi-objs-$(CONFIG_SBI_ECALL_VENDOR) += sbi_ecall_vendor.o
|
||||||
|
|
||||||
libsbi-objs-y += sbi_bitmap.o
|
libsbi-objs-y += sbi_bitmap.o
|
||||||
libsbi-objs-y += sbi_bitops.o
|
libsbi-objs-y += sbi_bitops.o
|
||||||
libsbi-objs-y += sbi_console.o
|
libsbi-objs-y += sbi_console.o
|
||||||
libsbi-objs-y += sbi_domain.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
|
libsbi-objs-y += sbi_emulate_csr.o
|
||||||
libsbi-objs-y += sbi_fifo.o
|
libsbi-objs-y += sbi_fifo.o
|
||||||
libsbi-objs-y += sbi_hart.o
|
libsbi-objs-y += sbi_hart.o
|
||||||
|
libsbi-objs-y += sbi_heap.o
|
||||||
libsbi-objs-y += sbi_math.o
|
libsbi-objs-y += sbi_math.o
|
||||||
libsbi-objs-y += sbi_hfence.o
|
libsbi-objs-y += sbi_hfence.o
|
||||||
libsbi-objs-y += sbi_hsm.o
|
libsbi-objs-y += sbi_hsm.o
|
||||||
@@ -44,3 +78,4 @@ libsbi-objs-y += sbi_tlb.o
|
|||||||
libsbi-objs-y += sbi_trap.o
|
libsbi-objs-y += sbi_trap.o
|
||||||
libsbi-objs-y += sbi_unpriv.o
|
libsbi-objs-y += sbi_unpriv.o
|
||||||
libsbi-objs-y += sbi_expected_trap.o
|
libsbi-objs-y += sbi_expected_trap.o
|
||||||
|
libsbi-objs-y += sbi_cppc.o
|
||||||
|
@@ -128,6 +128,8 @@ unsigned long csr_read_num(int csr_num)
|
|||||||
switchcase_csr_read_8(CSR_MHPMCOUNTER8, ret)
|
switchcase_csr_read_8(CSR_MHPMCOUNTER8, ret)
|
||||||
switchcase_csr_read_16(CSR_MHPMCOUNTER16, ret)
|
switchcase_csr_read_16(CSR_MHPMCOUNTER16, ret)
|
||||||
switchcase_csr_read(CSR_MCOUNTINHIBIT, ret)
|
switchcase_csr_read(CSR_MCOUNTINHIBIT, ret)
|
||||||
|
switchcase_csr_read(CSR_MCYCLECFG, ret)
|
||||||
|
switchcase_csr_read(CSR_MINSTRETCFG, ret)
|
||||||
switchcase_csr_read(CSR_MHPMEVENT3, ret)
|
switchcase_csr_read(CSR_MHPMEVENT3, ret)
|
||||||
switchcase_csr_read_4(CSR_MHPMEVENT4, ret)
|
switchcase_csr_read_4(CSR_MHPMEVENT4, ret)
|
||||||
switchcase_csr_read_8(CSR_MHPMEVENT8, ret)
|
switchcase_csr_read_8(CSR_MHPMEVENT8, ret)
|
||||||
@@ -139,6 +141,12 @@ unsigned long csr_read_num(int csr_num)
|
|||||||
switchcase_csr_read_4(CSR_MHPMCOUNTER4H, ret)
|
switchcase_csr_read_4(CSR_MHPMCOUNTER4H, ret)
|
||||||
switchcase_csr_read_8(CSR_MHPMCOUNTER8H, ret)
|
switchcase_csr_read_8(CSR_MHPMCOUNTER8H, ret)
|
||||||
switchcase_csr_read_16(CSR_MHPMCOUNTER16H, ret)
|
switchcase_csr_read_16(CSR_MHPMCOUNTER16H, ret)
|
||||||
|
/**
|
||||||
|
* The CSR range M[CYCLE, INSTRET]CFGH are available only if smcntrpmf
|
||||||
|
* extension is present. The caller must ensure that.
|
||||||
|
*/
|
||||||
|
switchcase_csr_read(CSR_MCYCLECFGH, ret)
|
||||||
|
switchcase_csr_read(CSR_MINSTRETCFGH, ret)
|
||||||
/**
|
/**
|
||||||
* The CSR range MHPMEVENT[3-16]H are available only if sscofpmf
|
* The CSR range MHPMEVENT[3-16]H are available only if sscofpmf
|
||||||
* extension is present. The caller must ensure that.
|
* extension is present. The caller must ensure that.
|
||||||
@@ -152,7 +160,7 @@ unsigned long csr_read_num(int csr_num)
|
|||||||
default:
|
default:
|
||||||
sbi_panic("%s: Unknown CSR %#x", __func__, csr_num);
|
sbi_panic("%s: Unknown CSR %#x", __func__, csr_num);
|
||||||
break;
|
break;
|
||||||
};
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -206,12 +214,16 @@ void csr_write_num(int csr_num, unsigned long val)
|
|||||||
switchcase_csr_write_4(CSR_MHPMCOUNTER4H, val)
|
switchcase_csr_write_4(CSR_MHPMCOUNTER4H, val)
|
||||||
switchcase_csr_write_8(CSR_MHPMCOUNTER8H, val)
|
switchcase_csr_write_8(CSR_MHPMCOUNTER8H, val)
|
||||||
switchcase_csr_write_16(CSR_MHPMCOUNTER16H, val)
|
switchcase_csr_write_16(CSR_MHPMCOUNTER16H, val)
|
||||||
|
switchcase_csr_write(CSR_MCYCLECFGH, val)
|
||||||
|
switchcase_csr_write(CSR_MINSTRETCFGH, val)
|
||||||
switchcase_csr_write(CSR_MHPMEVENT3H, val)
|
switchcase_csr_write(CSR_MHPMEVENT3H, val)
|
||||||
switchcase_csr_write_4(CSR_MHPMEVENT4H, val)
|
switchcase_csr_write_4(CSR_MHPMEVENT4H, val)
|
||||||
switchcase_csr_write_8(CSR_MHPMEVENT8H, val)
|
switchcase_csr_write_8(CSR_MHPMEVENT8H, val)
|
||||||
switchcase_csr_write_16(CSR_MHPMEVENT16H, val)
|
switchcase_csr_write_16(CSR_MHPMEVENT16H, val)
|
||||||
#endif
|
#endif
|
||||||
switchcase_csr_write(CSR_MCOUNTINHIBIT, val)
|
switchcase_csr_write(CSR_MCOUNTINHIBIT, val)
|
||||||
|
switchcase_csr_write(CSR_MCYCLECFG, val)
|
||||||
|
switchcase_csr_write(CSR_MINSTRETCFG, val)
|
||||||
switchcase_csr_write(CSR_MHPMEVENT3, val)
|
switchcase_csr_write(CSR_MHPMEVENT3, val)
|
||||||
switchcase_csr_write_4(CSR_MHPMEVENT4, val)
|
switchcase_csr_write_4(CSR_MHPMEVENT4, val)
|
||||||
switchcase_csr_write_8(CSR_MHPMEVENT8, val)
|
switchcase_csr_write_8(CSR_MHPMEVENT8, val)
|
||||||
@@ -220,7 +232,7 @@ void csr_write_num(int csr_num, unsigned long val)
|
|||||||
default:
|
default:
|
||||||
sbi_panic("%s: Unknown CSR %#x", __func__, csr_num);
|
sbi_panic("%s: Unknown CSR %#x", __func__, csr_num);
|
||||||
break;
|
break;
|
||||||
};
|
}
|
||||||
|
|
||||||
#undef switchcase_csr_write_64
|
#undef switchcase_csr_write_64
|
||||||
#undef switchcase_csr_write_32
|
#undef switchcase_csr_write_32
|
||||||
@@ -246,6 +258,48 @@ static unsigned long ctz(unsigned long x)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int pmp_disable(unsigned int n)
|
||||||
|
{
|
||||||
|
int pmpcfg_csr, pmpcfg_shift;
|
||||||
|
unsigned long cfgmask, pmpcfg;
|
||||||
|
|
||||||
|
if (n >= PMP_COUNT)
|
||||||
|
return SBI_EINVAL;
|
||||||
|
|
||||||
|
#if __riscv_xlen == 32
|
||||||
|
pmpcfg_csr = CSR_PMPCFG0 + (n >> 2);
|
||||||
|
pmpcfg_shift = (n & 3) << 3;
|
||||||
|
#elif __riscv_xlen == 64
|
||||||
|
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
|
||||||
|
pmpcfg_shift = (n & 7) << 3;
|
||||||
|
#else
|
||||||
|
# error "Unexpected __riscv_xlen"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Clear the address matching bits to disable the pmp entry */
|
||||||
|
cfgmask = ~(0xffUL << pmpcfg_shift);
|
||||||
|
pmpcfg = (csr_read_num(pmpcfg_csr) & cfgmask);
|
||||||
|
|
||||||
|
csr_write_num(pmpcfg_csr, pmpcfg);
|
||||||
|
|
||||||
|
return SBI_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_pmp_entry_mapped(unsigned long entry)
|
||||||
|
{
|
||||||
|
unsigned long prot;
|
||||||
|
unsigned long addr;
|
||||||
|
unsigned long log2len;
|
||||||
|
|
||||||
|
pmp_get(entry, &prot, &addr, &log2len);
|
||||||
|
|
||||||
|
/* If address matching bits are non-zero, the entry is enable */
|
||||||
|
if (prot & PMP_A)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
|
int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
|
||||||
unsigned long log2len)
|
unsigned long log2len)
|
||||||
{
|
{
|
||||||
|
@@ -12,6 +12,10 @@
|
|||||||
#include <sbi/riscv_atomic.h>
|
#include <sbi/riscv_atomic.h>
|
||||||
#include <sbi/riscv_barrier.h>
|
#include <sbi/riscv_barrier.h>
|
||||||
|
|
||||||
|
#ifndef __riscv_atomic
|
||||||
|
#error "opensbi strongly relies on the A extension of RISC-V"
|
||||||
|
#endif
|
||||||
|
|
||||||
long atomic_read(atomic_t *atom)
|
long atomic_read(atomic_t *atom)
|
||||||
{
|
{
|
||||||
long ret = atom->counter;
|
long ret = atom->counter;
|
||||||
@@ -79,175 +83,51 @@ long atomic_sub_return(atomic_t *atom, long value)
|
|||||||
(__typeof__(*(ptr))) __axchg((ptr), _x_, sizeof(*(ptr))); \
|
(__typeof__(*(ptr))) __axchg((ptr), _x_, sizeof(*(ptr))); \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
#define __xchg(ptr, new, size) \
|
|
||||||
({ \
|
|
||||||
__typeof__(ptr) __ptr = (ptr); \
|
|
||||||
__typeof__(*(ptr)) __new = (new); \
|
|
||||||
__typeof__(*(ptr)) __ret; \
|
|
||||||
register unsigned int __rc; \
|
|
||||||
switch (size) { \
|
|
||||||
case 4: \
|
|
||||||
__asm__ __volatile__("0: lr.w %0, %2\n" \
|
|
||||||
" sc.w.rl %1, %z3, %2\n" \
|
|
||||||
" bnez %1, 0b\n" \
|
|
||||||
" fence rw, rw\n" \
|
|
||||||
: "=&r"(__ret), "=&r"(__rc), \
|
|
||||||
"+A"(*__ptr) \
|
|
||||||
: "rJ"(__new) \
|
|
||||||
: "memory"); \
|
|
||||||
break; \
|
|
||||||
case 8: \
|
|
||||||
__asm__ __volatile__("0: lr.d %0, %2\n" \
|
|
||||||
" sc.d.rl %1, %z3, %2\n" \
|
|
||||||
" bnez %1, 0b\n" \
|
|
||||||
" fence rw, rw\n" \
|
|
||||||
: "=&r"(__ret), "=&r"(__rc), \
|
|
||||||
"+A"(*__ptr) \
|
|
||||||
: "rJ"(__new) \
|
|
||||||
: "memory"); \
|
|
||||||
break; \
|
|
||||||
default: \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
__ret; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define xchg(ptr, n) \
|
|
||||||
({ \
|
|
||||||
__typeof__(*(ptr)) _n_ = (n); \
|
|
||||||
(__typeof__(*(ptr))) __xchg((ptr), _n_, sizeof(*(ptr))); \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define __cmpxchg(ptr, old, new, size) \
|
|
||||||
({ \
|
|
||||||
__typeof__(ptr) __ptr = (ptr); \
|
|
||||||
__typeof__(*(ptr)) __old = (old); \
|
|
||||||
__typeof__(*(ptr)) __new = (new); \
|
|
||||||
__typeof__(*(ptr)) __ret; \
|
|
||||||
register unsigned int __rc; \
|
|
||||||
switch (size) { \
|
|
||||||
case 4: \
|
|
||||||
__asm__ __volatile__("0: lr.w %0, %2\n" \
|
|
||||||
" bne %0, %z3, 1f\n" \
|
|
||||||
" sc.w.rl %1, %z4, %2\n" \
|
|
||||||
" bnez %1, 0b\n" \
|
|
||||||
" fence rw, rw\n" \
|
|
||||||
"1:\n" \
|
|
||||||
: "=&r"(__ret), "=&r"(__rc), \
|
|
||||||
"+A"(*__ptr) \
|
|
||||||
: "rJ"(__old), "rJ"(__new) \
|
|
||||||
: "memory"); \
|
|
||||||
break; \
|
|
||||||
case 8: \
|
|
||||||
__asm__ __volatile__("0: lr.d %0, %2\n" \
|
|
||||||
" bne %0, %z3, 1f\n" \
|
|
||||||
" sc.d.rl %1, %z4, %2\n" \
|
|
||||||
" bnez %1, 0b\n" \
|
|
||||||
" fence rw, rw\n" \
|
|
||||||
"1:\n" \
|
|
||||||
: "=&r"(__ret), "=&r"(__rc), \
|
|
||||||
"+A"(*__ptr) \
|
|
||||||
: "rJ"(__old), "rJ"(__new) \
|
|
||||||
: "memory"); \
|
|
||||||
break; \
|
|
||||||
default: \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
__ret; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define cmpxchg(ptr, o, n) \
|
|
||||||
({ \
|
|
||||||
__typeof__(*(ptr)) _o_ = (o); \
|
|
||||||
__typeof__(*(ptr)) _n_ = (n); \
|
|
||||||
(__typeof__(*(ptr))) \
|
|
||||||
__cmpxchg((ptr), _o_, _n_, sizeof(*(ptr))); \
|
|
||||||
})
|
|
||||||
|
|
||||||
long atomic_cmpxchg(atomic_t *atom, long oldval, long newval)
|
long atomic_cmpxchg(atomic_t *atom, long oldval, long newval)
|
||||||
{
|
{
|
||||||
#ifdef __riscv_atomic
|
|
||||||
return __sync_val_compare_and_swap(&atom->counter, oldval, newval);
|
return __sync_val_compare_and_swap(&atom->counter, oldval, newval);
|
||||||
#else
|
|
||||||
return cmpxchg(&atom->counter, oldval, newval);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long atomic_xchg(atomic_t *atom, long newval)
|
long atomic_xchg(atomic_t *atom, long newval)
|
||||||
{
|
{
|
||||||
/* Atomically set new value and return old value. */
|
/* Atomically set new value and return old value. */
|
||||||
#ifdef __riscv_atomic
|
|
||||||
return axchg(&atom->counter, newval);
|
return axchg(&atom->counter, newval);
|
||||||
#else
|
|
||||||
return xchg(&atom->counter, newval);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
|
unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
|
||||||
unsigned int newval)
|
unsigned int newval)
|
||||||
{
|
{
|
||||||
/* Atomically set new value and return old value. */
|
/* Atomically set new value and return old value. */
|
||||||
#ifdef __riscv_atomic
|
|
||||||
return axchg(ptr, newval);
|
return axchg(ptr, newval);
|
||||||
#else
|
|
||||||
return xchg(ptr, newval);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long atomic_raw_xchg_ulong(volatile unsigned long *ptr,
|
unsigned long atomic_raw_xchg_ulong(volatile unsigned long *ptr,
|
||||||
unsigned long newval)
|
unsigned long newval)
|
||||||
{
|
{
|
||||||
/* Atomically set new value and return old value. */
|
/* Atomically set new value and return old value. */
|
||||||
#ifdef __riscv_atomic
|
|
||||||
return axchg(ptr, newval);
|
return axchg(ptr, newval);
|
||||||
#else
|
|
||||||
return xchg(ptr, newval);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (__SIZEOF_POINTER__ == 8)
|
int atomic_raw_set_bit(int nr, volatile unsigned long *addr)
|
||||||
#define __AMO(op) "amo" #op ".d"
|
|
||||||
#elif (__SIZEOF_POINTER__ == 4)
|
|
||||||
#define __AMO(op) "amo" #op ".w"
|
|
||||||
#else
|
|
||||||
#error "Unexpected __SIZEOF_POINTER__"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define __atomic_op_bit_ord(op, mod, nr, addr, ord) \
|
|
||||||
({ \
|
|
||||||
unsigned long __res, __mask; \
|
|
||||||
__mask = BIT_MASK(nr); \
|
|
||||||
__asm__ __volatile__(__AMO(op) #ord " %0, %2, %1" \
|
|
||||||
: "=r"(__res), "+A"(addr[BIT_WORD(nr)]) \
|
|
||||||
: "r"(mod(__mask)) \
|
|
||||||
: "memory"); \
|
|
||||||
__res; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define __atomic_op_bit(op, mod, nr, addr) \
|
|
||||||
__atomic_op_bit_ord(op, mod, nr, addr, .aqrl)
|
|
||||||
|
|
||||||
/* Bitmask modifiers */
|
|
||||||
#define __NOP(x) (x)
|
|
||||||
#define __NOT(x) (~(x))
|
|
||||||
|
|
||||||
inline int atomic_raw_set_bit(int nr, volatile unsigned long *addr)
|
|
||||||
{
|
{
|
||||||
return __atomic_op_bit(or, __NOP, nr, addr);
|
unsigned long res, mask = BIT_MASK(nr);
|
||||||
|
res = __atomic_fetch_or(&addr[BIT_WORD(nr)], mask, __ATOMIC_RELAXED);
|
||||||
|
return res & mask ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int atomic_raw_clear_bit(int nr, volatile unsigned long *addr)
|
int atomic_raw_clear_bit(int nr, volatile unsigned long *addr)
|
||||||
{
|
{
|
||||||
return __atomic_op_bit(and, __NOT, nr, addr);
|
unsigned long res, mask = BIT_MASK(nr);
|
||||||
|
res = __atomic_fetch_and(&addr[BIT_WORD(nr)], ~mask, __ATOMIC_RELAXED);
|
||||||
|
return res & mask ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int atomic_set_bit(int nr, atomic_t *atom)
|
int atomic_set_bit(int nr, atomic_t *atom)
|
||||||
{
|
{
|
||||||
return atomic_raw_set_bit(nr, (unsigned long *)&atom->counter);
|
return atomic_raw_set_bit(nr, (unsigned long *)&atom->counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int atomic_clear_bit(int nr, atomic_t *atom)
|
int atomic_clear_bit(int nr, atomic_t *atom)
|
||||||
{
|
{
|
||||||
return atomic_raw_clear_bit(nr, (unsigned long *)&atom->counter);
|
return atomic_raw_clear_bit(nr, (unsigned long *)&atom->counter);
|
||||||
}
|
}
|
||||||
|
@@ -12,17 +12,22 @@
|
|||||||
#include <sbi/sbi_hart.h>
|
#include <sbi/sbi_hart.h>
|
||||||
#include <sbi/sbi_platform.h>
|
#include <sbi/sbi_platform.h>
|
||||||
#include <sbi/sbi_scratch.h>
|
#include <sbi/sbi_scratch.h>
|
||||||
|
#include <sbi/sbi_string.h>
|
||||||
|
|
||||||
|
#define CONSOLE_TBUF_MAX 256
|
||||||
|
|
||||||
static const struct sbi_console_device *console_dev = NULL;
|
static const struct sbi_console_device *console_dev = NULL;
|
||||||
|
static char console_tbuf[CONSOLE_TBUF_MAX];
|
||||||
|
static u32 console_tbuf_len;
|
||||||
static spinlock_t console_out_lock = SPIN_LOCK_INITIALIZER;
|
static spinlock_t console_out_lock = SPIN_LOCK_INITIALIZER;
|
||||||
|
|
||||||
bool sbi_isprintable(char c)
|
bool sbi_isprintable(char c)
|
||||||
{
|
{
|
||||||
if (((31 < c) && (c < 127)) || (c == '\f') || (c == '\r') ||
|
if (((31 < c) && (c < 127)) || (c == '\f') || (c == '\r') ||
|
||||||
(c == '\n') || (c == '\t')) {
|
(c == '\n') || (c == '\t')) {
|
||||||
return TRUE;
|
return true;
|
||||||
}
|
}
|
||||||
return FALSE;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sbi_getc(void)
|
int sbi_getc(void)
|
||||||
@@ -32,25 +37,57 @@ int sbi_getc(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned long nputs(const char *str, unsigned long len)
|
||||||
|
{
|
||||||
|
unsigned long i;
|
||||||
|
|
||||||
|
if (console_dev) {
|
||||||
|
if (console_dev->console_puts)
|
||||||
|
return console_dev->console_puts(str, len);
|
||||||
|
else if (console_dev->console_putc) {
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (str[i] == '\n')
|
||||||
|
console_dev->console_putc('\r');
|
||||||
|
console_dev->console_putc(str[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nputs_all(const char *str, unsigned long len)
|
||||||
|
{
|
||||||
|
unsigned long p = 0;
|
||||||
|
|
||||||
|
while (p < len)
|
||||||
|
p += nputs(&str[p], len - p);
|
||||||
|
}
|
||||||
|
|
||||||
void sbi_putc(char ch)
|
void sbi_putc(char ch)
|
||||||
{
|
{
|
||||||
if (console_dev && console_dev->console_putc) {
|
nputs_all(&ch, 1);
|
||||||
if (ch == '\n')
|
|
||||||
console_dev->console_putc('\r');
|
|
||||||
console_dev->console_putc(ch);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sbi_puts(const char *str)
|
void sbi_puts(const char *str)
|
||||||
{
|
{
|
||||||
|
unsigned long len = sbi_strlen(str);
|
||||||
|
|
||||||
spin_lock(&console_out_lock);
|
spin_lock(&console_out_lock);
|
||||||
while (*str) {
|
nputs_all(str, len);
|
||||||
sbi_putc(*str);
|
|
||||||
str++;
|
|
||||||
}
|
|
||||||
spin_unlock(&console_out_lock);
|
spin_unlock(&console_out_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned long sbi_nputs(const char *str, unsigned long len)
|
||||||
|
{
|
||||||
|
unsigned long ret;
|
||||||
|
|
||||||
|
spin_lock(&console_out_lock);
|
||||||
|
ret = nputs(str, len);
|
||||||
|
spin_unlock(&console_out_lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void sbi_gets(char *s, int maxwidth, char endchar)
|
void sbi_gets(char *s, int maxwidth, char endchar)
|
||||||
{
|
{
|
||||||
int ch;
|
int ch;
|
||||||
@@ -64,9 +101,26 @@ void sbi_gets(char *s, int maxwidth, char endchar)
|
|||||||
*retval = '\0';
|
*retval = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned long sbi_ngets(char *str, unsigned long len)
|
||||||
|
{
|
||||||
|
int ch;
|
||||||
|
unsigned long i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
ch = sbi_getc();
|
||||||
|
if (ch < 0)
|
||||||
|
break;
|
||||||
|
str[i] = ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
#define PAD_RIGHT 1
|
#define PAD_RIGHT 1
|
||||||
#define PAD_ZERO 2
|
#define PAD_ZERO 2
|
||||||
#define PAD_ALTERNATE 4
|
#define PAD_ALTERNATE 4
|
||||||
|
#define PAD_SIGN 8
|
||||||
|
#define USE_TBUF 16
|
||||||
#define PRINT_BUF_LEN 64
|
#define PRINT_BUF_LEN 64
|
||||||
|
|
||||||
#define va_start(v, l) __builtin_va_start((v), l)
|
#define va_start(v, l) __builtin_va_start((v), l)
|
||||||
@@ -74,72 +128,80 @@ void sbi_gets(char *s, int maxwidth, char endchar)
|
|||||||
#define va_arg __builtin_va_arg
|
#define va_arg __builtin_va_arg
|
||||||
typedef __builtin_va_list va_list;
|
typedef __builtin_va_list va_list;
|
||||||
|
|
||||||
static void printc(char **out, u32 *out_len, char ch)
|
static void printc(char **out, u32 *out_len, char ch, int flags)
|
||||||
{
|
{
|
||||||
if (out) {
|
if (!out) {
|
||||||
if (*out) {
|
sbi_putc(ch);
|
||||||
if (out_len && (0 < *out_len)) {
|
return;
|
||||||
**out = ch;
|
}
|
||||||
++(*out);
|
|
||||||
(*out_len)--;
|
/*
|
||||||
} else {
|
* The *printf entry point functions have enforced that (*out) can
|
||||||
**out = ch;
|
* only be null when out_len is non-null and its value is zero.
|
||||||
++(*out);
|
*/
|
||||||
|
if (!out_len || *out_len > 1) {
|
||||||
|
*(*out)++ = ch;
|
||||||
|
**out = '\0';
|
||||||
|
if (out_len) {
|
||||||
|
--(*out_len);
|
||||||
|
if ((flags & USE_TBUF) && *out_len == 1) {
|
||||||
|
nputs_all(console_tbuf, CONSOLE_TBUF_MAX - *out_len);
|
||||||
|
*out = console_tbuf;
|
||||||
|
*out_len = CONSOLE_TBUF_MAX;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
sbi_putc(ch);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int prints(char **out, u32 *out_len, const char *string, int width,
|
static int prints(char **out, u32 *out_len, const char *string, int width,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
int pc = 0;
|
int pc = 0;
|
||||||
char padchar = ' ';
|
width -= sbi_strlen(string);
|
||||||
|
|
||||||
if (width > 0) {
|
|
||||||
int len = 0;
|
|
||||||
const char *ptr;
|
|
||||||
for (ptr = string; *ptr; ++ptr)
|
|
||||||
++len;
|
|
||||||
if (len >= width)
|
|
||||||
width = 0;
|
|
||||||
else
|
|
||||||
width -= len;
|
|
||||||
if (flags & PAD_ZERO)
|
|
||||||
padchar = '0';
|
|
||||||
}
|
|
||||||
if (!(flags & PAD_RIGHT)) {
|
if (!(flags & PAD_RIGHT)) {
|
||||||
for (; width > 0; --width) {
|
for (; width > 0; --width) {
|
||||||
printc(out, out_len, padchar);
|
printc(out, out_len, flags & PAD_ZERO ? '0' : ' ', flags);
|
||||||
++pc;
|
++pc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (; *string; ++string) {
|
for (; *string; ++string) {
|
||||||
printc(out, out_len, *string);
|
printc(out, out_len, *string, flags);
|
||||||
++pc;
|
++pc;
|
||||||
}
|
}
|
||||||
for (; width > 0; --width) {
|
for (; width > 0; --width) {
|
||||||
printc(out, out_len, padchar);
|
printc(out, out_len, ' ', flags);
|
||||||
++pc;
|
++pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pc;
|
return pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int printi(char **out, u32 *out_len, long long i, int b, int sg,
|
static int printi(char **out, u32 *out_len, long long i,
|
||||||
int width, int flags, int letbase)
|
int width, int flags, int type)
|
||||||
{
|
{
|
||||||
char print_buf[PRINT_BUF_LEN];
|
int pc = 0;
|
||||||
char *s;
|
char *s, sign = 0, letbase, print_buf[PRINT_BUF_LEN];
|
||||||
int neg = 0, pc = 0;
|
unsigned long long u, b, t;
|
||||||
u64 t;
|
|
||||||
unsigned long long u = i;
|
|
||||||
|
|
||||||
if (sg && b == 10 && i < 0) {
|
b = 10;
|
||||||
neg = 1;
|
letbase = 'a';
|
||||||
u = -i;
|
if (type == 'o')
|
||||||
|
b = 8;
|
||||||
|
else if (type == 'x' || type == 'X' || type == 'p' || type == 'P') {
|
||||||
|
b = 16;
|
||||||
|
letbase &= ~0x20;
|
||||||
|
letbase |= type & 0x20;
|
||||||
|
}
|
||||||
|
|
||||||
|
u = i;
|
||||||
|
sign = 0;
|
||||||
|
if (type == 'i' || type == 'd') {
|
||||||
|
if ((flags & PAD_SIGN) && i > 0)
|
||||||
|
sign = '+';
|
||||||
|
if (i < 0) {
|
||||||
|
sign = '-';
|
||||||
|
u = -i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s = print_buf + PRINT_BUF_LEN - 1;
|
s = print_buf + PRINT_BUF_LEN - 1;
|
||||||
@@ -157,23 +219,33 @@ static int printi(char **out, u32 *out_len, long long i, int b, int sg,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & PAD_ALTERNATE) {
|
if (flags & PAD_ZERO) {
|
||||||
if ((b == 16) && (letbase == 'A')) {
|
if (sign) {
|
||||||
*--s = 'X';
|
printc(out, out_len, sign, flags);
|
||||||
} else if ((b == 16) && (letbase == 'a')) {
|
|
||||||
*--s = 'x';
|
|
||||||
}
|
|
||||||
*--s = '0';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (neg) {
|
|
||||||
if (width && (flags & PAD_ZERO)) {
|
|
||||||
printc(out, out_len, '-');
|
|
||||||
++pc;
|
++pc;
|
||||||
--width;
|
--width;
|
||||||
} else {
|
|
||||||
*--s = '-';
|
|
||||||
}
|
}
|
||||||
|
if (i && (flags & PAD_ALTERNATE)) {
|
||||||
|
if (b == 16 || b == 8) {
|
||||||
|
printc(out, out_len, '0', flags);
|
||||||
|
++pc;
|
||||||
|
--width;
|
||||||
|
}
|
||||||
|
if (b == 16) {
|
||||||
|
printc(out, out_len, 'x' - 'a' + letbase, flags);
|
||||||
|
++pc;
|
||||||
|
--width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (i && (flags & PAD_ALTERNATE)) {
|
||||||
|
if (b == 16)
|
||||||
|
*--s = 'x' - 'a' + letbase;
|
||||||
|
if (b == 16 || b == 8)
|
||||||
|
*--s = '0';
|
||||||
|
}
|
||||||
|
if (sign)
|
||||||
|
*--s = sign;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pc + prints(out, out_len, s, width, flags);
|
return pc + prints(out, out_len, s, width, flags);
|
||||||
@@ -181,32 +253,68 @@ static int printi(char **out, u32 *out_len, long long i, int b, int sg,
|
|||||||
|
|
||||||
static int print(char **out, u32 *out_len, const char *format, va_list args)
|
static int print(char **out, u32 *out_len, const char *format, va_list args)
|
||||||
{
|
{
|
||||||
int width, flags, acnt = 0;
|
bool flags_done;
|
||||||
int pc = 0;
|
int width, flags, pc = 0;
|
||||||
char scr[2];
|
char type, scr[2], *tout;
|
||||||
unsigned long long tmp;
|
bool use_tbuf = (!out) ? true : false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The console_tbuf is protected by console_out_lock and
|
||||||
|
* print() is always called with console_out_lock held
|
||||||
|
* when out == NULL.
|
||||||
|
*/
|
||||||
|
if (use_tbuf) {
|
||||||
|
console_tbuf_len = CONSOLE_TBUF_MAX;
|
||||||
|
tout = console_tbuf;
|
||||||
|
out = &tout;
|
||||||
|
out_len = &console_tbuf_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* handle special case: *out_len == 1*/
|
||||||
|
if (out) {
|
||||||
|
if(!out_len || *out_len)
|
||||||
|
**out = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
for (; *format != 0; ++format) {
|
for (; *format != 0; ++format) {
|
||||||
|
width = flags = 0;
|
||||||
|
if (use_tbuf)
|
||||||
|
flags |= USE_TBUF;
|
||||||
if (*format == '%') {
|
if (*format == '%') {
|
||||||
++format;
|
++format;
|
||||||
width = flags = 0;
|
|
||||||
if (*format == '\0')
|
if (*format == '\0')
|
||||||
break;
|
break;
|
||||||
if (*format == '%')
|
if (*format == '%')
|
||||||
goto out;
|
goto literal;
|
||||||
/* Get flags */
|
/* Get flags */
|
||||||
if (*format == '-') {
|
flags_done = false;
|
||||||
++format;
|
while (!flags_done) {
|
||||||
flags = PAD_RIGHT;
|
switch (*format) {
|
||||||
}
|
case '-':
|
||||||
if (*format == '#') {
|
flags |= PAD_RIGHT;
|
||||||
++format;
|
break;
|
||||||
flags |= PAD_ALTERNATE;
|
case '+':
|
||||||
}
|
flags |= PAD_SIGN;
|
||||||
while (*format == '0') {
|
break;
|
||||||
++format;
|
case '#':
|
||||||
flags |= PAD_ZERO;
|
flags |= PAD_ALTERNATE;
|
||||||
|
break;
|
||||||
|
case '0':
|
||||||
|
flags |= PAD_ZERO;
|
||||||
|
break;
|
||||||
|
case ' ':
|
||||||
|
case '\'':
|
||||||
|
/* Ignored flags, do nothing */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
flags_done = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!flags_done)
|
||||||
|
++format;
|
||||||
}
|
}
|
||||||
|
if (flags & PAD_RIGHT)
|
||||||
|
flags &= ~PAD_ZERO;
|
||||||
/* Get width */
|
/* Get width */
|
||||||
for (; *format >= '0' && *format <= '9'; ++format) {
|
for (; *format >= '0' && *format <= '9'; ++format) {
|
||||||
width *= 10;
|
width *= 10;
|
||||||
@@ -214,131 +322,70 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
|
|||||||
}
|
}
|
||||||
if (*format == 's') {
|
if (*format == 's') {
|
||||||
char *s = va_arg(args, char *);
|
char *s = va_arg(args, char *);
|
||||||
acnt += sizeof(char *);
|
|
||||||
pc += prints(out, out_len, s ? s : "(null)",
|
pc += prints(out, out_len, s ? s : "(null)",
|
||||||
width, flags);
|
width, flags);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ((*format == 'd') || (*format == 'i')) {
|
if ((*format == 'd') || (*format == 'i')) {
|
||||||
pc += printi(out, out_len, va_arg(args, int),
|
pc += printi(out, out_len, va_arg(args, int),
|
||||||
10, 1, width, flags, '0');
|
width, flags, *format);
|
||||||
acnt += sizeof(int);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (*format == 'x') {
|
if ((*format == 'u') || (*format == 'o')
|
||||||
pc += printi(out, out_len,
|
|| (*format == 'x') || (*format == 'X')) {
|
||||||
va_arg(args, unsigned int), 16, 0,
|
pc += printi(out, out_len, va_arg(args, unsigned int),
|
||||||
width, flags, 'a');
|
width, flags, *format);
|
||||||
acnt += sizeof(unsigned int);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (*format == 'X') {
|
if ((*format == 'p') || (*format == 'P')) {
|
||||||
pc += printi(out, out_len,
|
pc += printi(out, out_len, (uintptr_t)va_arg(args, void*),
|
||||||
va_arg(args, unsigned int), 16, 0,
|
width, flags, *format);
|
||||||
width, flags, 'A');
|
|
||||||
acnt += sizeof(unsigned int);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (*format == 'u') {
|
if (*format == 'l') {
|
||||||
pc += printi(out, out_len,
|
type = 'i';
|
||||||
va_arg(args, unsigned int), 10, 0,
|
if (format[1] == 'l') {
|
||||||
width, flags, 'a');
|
++format;
|
||||||
acnt += sizeof(unsigned int);
|
if ((format[1] == 'u') || (format[1] == 'o')
|
||||||
continue;
|
|| (format[1] == 'd') || (format[1] == 'i')
|
||||||
}
|
|| (format[1] == 'x') || (format[1] == 'X')) {
|
||||||
if (*format == 'p') {
|
++format;
|
||||||
pc += printi(out, out_len,
|
type = *format;
|
||||||
va_arg(args, unsigned long), 16, 0,
|
}
|
||||||
width, flags, 'a');
|
pc += printi(out, out_len, va_arg(args, long long),
|
||||||
acnt += sizeof(unsigned long);
|
width, flags, type);
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
if (*format == 'P') {
|
|
||||||
pc += printi(out, out_len,
|
|
||||||
va_arg(args, unsigned long), 16, 0,
|
|
||||||
width, flags, 'A');
|
|
||||||
acnt += sizeof(unsigned long);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (*format == 'l' && *(format + 1) == 'l') {
|
|
||||||
while (acnt &
|
|
||||||
(sizeof(unsigned long long) - 1)) {
|
|
||||||
va_arg(args, int);
|
|
||||||
acnt += sizeof(int);
|
|
||||||
}
|
}
|
||||||
if (sizeof(unsigned long long) ==
|
if ((format[1] == 'u') || (format[1] == 'o')
|
||||||
sizeof(unsigned long)) {
|
|| (format[1] == 'd') || (format[1] == 'i')
|
||||||
tmp = va_arg(args, unsigned long long);
|
|| (format[1] == 'x') || (format[1] == 'X')) {
|
||||||
acnt += sizeof(unsigned long long);
|
++format;
|
||||||
} else {
|
type = *format;
|
||||||
((unsigned long *)&tmp)[0] =
|
|
||||||
va_arg(args, unsigned long);
|
|
||||||
((unsigned long *)&tmp)[1] =
|
|
||||||
va_arg(args, unsigned long);
|
|
||||||
acnt += 2 * sizeof(unsigned long);
|
|
||||||
}
|
|
||||||
if (*(format + 2) == 'u') {
|
|
||||||
format += 2;
|
|
||||||
pc += printi(out, out_len, tmp, 10, 0,
|
|
||||||
width, flags, 'a');
|
|
||||||
} else if (*(format + 2) == 'x') {
|
|
||||||
format += 2;
|
|
||||||
pc += printi(out, out_len, tmp, 16, 0,
|
|
||||||
width, flags, 'a');
|
|
||||||
} else if (*(format + 2) == 'X') {
|
|
||||||
format += 2;
|
|
||||||
pc += printi(out, out_len, tmp, 16, 0,
|
|
||||||
width, flags, 'A');
|
|
||||||
} else {
|
|
||||||
format += 1;
|
|
||||||
pc += printi(out, out_len, tmp, 10, 1,
|
|
||||||
width, flags, '0');
|
|
||||||
}
|
}
|
||||||
|
if ((type == 'd') || (type == 'i'))
|
||||||
|
pc += printi(out, out_len, va_arg(args, long),
|
||||||
|
width, flags, type);
|
||||||
|
else
|
||||||
|
pc += printi(out, out_len, va_arg(args, unsigned long),
|
||||||
|
width, flags, type);
|
||||||
continue;
|
continue;
|
||||||
} else if (*format == 'l') {
|
|
||||||
if (*(format + 1) == 'u') {
|
|
||||||
format += 1;
|
|
||||||
pc += printi(
|
|
||||||
out, out_len,
|
|
||||||
va_arg(args, unsigned long), 10,
|
|
||||||
0, width, flags, 'a');
|
|
||||||
} else if (*(format + 1) == 'x') {
|
|
||||||
format += 1;
|
|
||||||
pc += printi(
|
|
||||||
out, out_len,
|
|
||||||
va_arg(args, unsigned long), 16,
|
|
||||||
0, width, flags, 'a');
|
|
||||||
acnt += sizeof(unsigned long);
|
|
||||||
} else if (*(format + 1) == 'X') {
|
|
||||||
format += 1;
|
|
||||||
pc += printi(
|
|
||||||
out, out_len,
|
|
||||||
va_arg(args, unsigned long), 16,
|
|
||||||
0, width, flags, 'A');
|
|
||||||
acnt += sizeof(unsigned long);
|
|
||||||
} else {
|
|
||||||
pc += printi(out, out_len,
|
|
||||||
va_arg(args, long), 10, 1,
|
|
||||||
width, flags, '0');
|
|
||||||
acnt += sizeof(long);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (*format == 'c') {
|
if (*format == 'c') {
|
||||||
/* char are converted to int then pushed on the stack */
|
/* char are converted to int then pushed on the stack */
|
||||||
scr[0] = va_arg(args, int);
|
scr[0] = va_arg(args, int);
|
||||||
scr[1] = '\0';
|
scr[1] = '\0';
|
||||||
pc += prints(out, out_len, scr, width, flags);
|
pc += prints(out, out_len, scr, width, flags);
|
||||||
acnt += sizeof(int);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
out:
|
literal:
|
||||||
printc(out, out_len, *format);
|
printc(out, out_len, *format, flags);
|
||||||
++pc;
|
++pc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (out)
|
|
||||||
**out = '\0';
|
if (use_tbuf && console_tbuf_len < CONSOLE_TBUF_MAX)
|
||||||
|
nputs_all(console_tbuf, CONSOLE_TBUF_MAX - console_tbuf_len);
|
||||||
|
|
||||||
return pc;
|
return pc;
|
||||||
}
|
}
|
||||||
@@ -348,6 +395,9 @@ int sbi_sprintf(char *out, const char *format, ...)
|
|||||||
va_list args;
|
va_list args;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
if (unlikely(!out))
|
||||||
|
sbi_panic("sbi_sprintf called with NULL output string\n");
|
||||||
|
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
retval = print(&out, NULL, format, args);
|
retval = print(&out, NULL, format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
@@ -360,6 +410,10 @@ int sbi_snprintf(char *out, u32 out_sz, const char *format, ...)
|
|||||||
va_list args;
|
va_list args;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
if (unlikely(!out && out_sz != 0))
|
||||||
|
sbi_panic("sbi_snprintf called with NULL output string and "
|
||||||
|
"output size is not zero\n");
|
||||||
|
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
retval = print(&out, &out_sz, format, args);
|
retval = print(&out, &out_sz, format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
@@ -426,5 +480,11 @@ void sbi_console_set_device(const struct sbi_console_device *dev)
|
|||||||
|
|
||||||
int sbi_console_init(struct sbi_scratch *scratch)
|
int sbi_console_init(struct sbi_scratch *scratch)
|
||||||
{
|
{
|
||||||
return sbi_platform_console_init(sbi_platform_ptr(scratch));
|
int rc = sbi_platform_console_init(sbi_platform_ptr(scratch));
|
||||||
|
|
||||||
|
/* console is not a necessary device */
|
||||||
|
if (rc == SBI_ENODEV)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
110
lib/sbi/sbi_cppc.c
Normal file
110
lib/sbi/sbi_cppc.c
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Ventana Micro Systems Inc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi/sbi_error.h>
|
||||||
|
#include <sbi/sbi_cppc.h>
|
||||||
|
|
||||||
|
static const struct sbi_cppc_device *cppc_dev = NULL;
|
||||||
|
|
||||||
|
const struct sbi_cppc_device *sbi_cppc_get_device(void)
|
||||||
|
{
|
||||||
|
return cppc_dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sbi_cppc_set_device(const struct sbi_cppc_device *dev)
|
||||||
|
{
|
||||||
|
if (!dev || cppc_dev)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cppc_dev = dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool sbi_cppc_is_reserved(unsigned long reg)
|
||||||
|
{
|
||||||
|
if ((reg > SBI_CPPC_ACPI_LAST && reg < SBI_CPPC_TRANSITION_LATENCY) ||
|
||||||
|
reg > SBI_CPPC_NON_ACPI_LAST)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool sbi_cppc_readable(unsigned long reg)
|
||||||
|
{
|
||||||
|
/* there are no write-only cppc registers currently */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool sbi_cppc_writable(unsigned long reg)
|
||||||
|
{
|
||||||
|
switch (reg) {
|
||||||
|
case SBI_CPPC_HIGHEST_PERF:
|
||||||
|
case SBI_CPPC_NOMINAL_PERF:
|
||||||
|
case SBI_CPPC_LOW_NON_LINEAR_PERF:
|
||||||
|
case SBI_CPPC_LOWEST_PERF:
|
||||||
|
case SBI_CPPC_GUARANTEED_PERF:
|
||||||
|
case SBI_CPPC_CTR_WRAP_TIME:
|
||||||
|
case SBI_CPPC_REFERENCE_CTR:
|
||||||
|
case SBI_CPPC_DELIVERED_CTR:
|
||||||
|
case SBI_CPPC_REFERENCE_PERF:
|
||||||
|
case SBI_CPPC_LOWEST_FREQ:
|
||||||
|
case SBI_CPPC_NOMINAL_FREQ:
|
||||||
|
case SBI_CPPC_TRANSITION_LATENCY:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sbi_cppc_probe(unsigned long reg)
|
||||||
|
{
|
||||||
|
if (!cppc_dev || !cppc_dev->cppc_probe)
|
||||||
|
return SBI_EFAIL;
|
||||||
|
|
||||||
|
/* Check whether register is reserved */
|
||||||
|
if (sbi_cppc_is_reserved(reg))
|
||||||
|
return SBI_ERR_INVALID_PARAM;
|
||||||
|
|
||||||
|
return cppc_dev->cppc_probe(reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sbi_cppc_read(unsigned long reg, uint64_t *val)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!cppc_dev || !cppc_dev->cppc_read)
|
||||||
|
return SBI_EFAIL;
|
||||||
|
|
||||||
|
/* Check whether register is implemented */
|
||||||
|
ret = sbi_cppc_probe(reg);
|
||||||
|
if (ret <= 0)
|
||||||
|
return SBI_ERR_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
/* Check whether the register is write-only */
|
||||||
|
if (!sbi_cppc_readable(reg))
|
||||||
|
return SBI_ERR_DENIED;
|
||||||
|
|
||||||
|
return cppc_dev->cppc_read(reg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sbi_cppc_write(unsigned long reg, uint64_t val)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!cppc_dev || !cppc_dev->cppc_write)
|
||||||
|
return SBI_EFAIL;
|
||||||
|
|
||||||
|
/* Check whether register is implemented */
|
||||||
|
ret = sbi_cppc_probe(reg);
|
||||||
|
if (ret <= 0)
|
||||||
|
return SBI_ERR_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
/* Check whether the register is read-only */
|
||||||
|
if (!sbi_cppc_writable(reg))
|
||||||
|
return SBI_ERR_DENIED;
|
||||||
|
|
||||||
|
return cppc_dev->cppc_write(reg, val);
|
||||||
|
}
|
@@ -11,67 +11,77 @@
|
|||||||
#include <sbi/sbi_console.h>
|
#include <sbi/sbi_console.h>
|
||||||
#include <sbi/sbi_domain.h>
|
#include <sbi/sbi_domain.h>
|
||||||
#include <sbi/sbi_hartmask.h>
|
#include <sbi/sbi_hartmask.h>
|
||||||
|
#include <sbi/sbi_heap.h>
|
||||||
#include <sbi/sbi_hsm.h>
|
#include <sbi/sbi_hsm.h>
|
||||||
#include <sbi/sbi_math.h>
|
#include <sbi/sbi_math.h>
|
||||||
#include <sbi/sbi_platform.h>
|
#include <sbi/sbi_platform.h>
|
||||||
#include <sbi/sbi_scratch.h>
|
#include <sbi/sbi_scratch.h>
|
||||||
#include <sbi/sbi_string.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 };
|
* We allocate an extra element because sbi_domain_for_each() expects
|
||||||
|
* the array to be null-terminated.
|
||||||
|
*/
|
||||||
|
struct sbi_domain *domidx_to_domain_table[SBI_DOMAIN_MAX_INDEX + 1] = { 0 };
|
||||||
static u32 domain_count = 0;
|
static u32 domain_count = 0;
|
||||||
static bool domain_finalized = false;
|
static bool domain_finalized = false;
|
||||||
|
|
||||||
static struct sbi_hartmask root_hmask = { 0 };
|
|
||||||
|
|
||||||
#define ROOT_REGION_MAX 16
|
#define ROOT_REGION_MAX 16
|
||||||
static u32 root_memregs_count = 0;
|
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 = {
|
struct sbi_domain root = {
|
||||||
.name = "root",
|
.name = "root",
|
||||||
.possible_harts = &root_hmask,
|
.possible_harts = NULL,
|
||||||
.regions = root_memregs,
|
.regions = NULL,
|
||||||
.system_reset_allowed = TRUE,
|
.system_reset_allowed = true,
|
||||||
|
.system_suspend_allowed = true,
|
||||||
|
.fw_region_inited = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static unsigned long domain_hart_ptr_offset;
|
||||||
|
|
||||||
|
struct sbi_domain *sbi_hartindex_to_domain(u32 hartindex)
|
||||||
|
{
|
||||||
|
struct sbi_scratch *scratch;
|
||||||
|
|
||||||
|
scratch = sbi_hartindex_to_scratch(hartindex);
|
||||||
|
if (!scratch || !domain_hart_ptr_offset)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return sbi_scratch_read_type(scratch, void *, domain_hart_ptr_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_hartindex_to_domain(u32 hartindex, struct sbi_domain *dom)
|
||||||
|
{
|
||||||
|
struct sbi_scratch *scratch;
|
||||||
|
|
||||||
|
scratch = sbi_hartindex_to_scratch(hartindex);
|
||||||
|
if (!scratch)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sbi_scratch_write_type(scratch, void *, domain_hart_ptr_offset, dom);
|
||||||
|
}
|
||||||
|
|
||||||
bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid)
|
bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid)
|
||||||
{
|
{
|
||||||
if (dom)
|
if (dom)
|
||||||
return sbi_hartmask_test_hart(hartid, &dom->assigned_harts);
|
return sbi_hartmask_test_hartid(hartid, &dom->assigned_harts);
|
||||||
|
|
||||||
return FALSE;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom,
|
ulong sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom,
|
||||||
ulong hbase)
|
ulong hbase)
|
||||||
{
|
{
|
||||||
ulong ret, bword, boff;
|
ulong ret = 0;
|
||||||
|
for (int i = 0; i < 8 * sizeof(ret); i++) {
|
||||||
if (!dom)
|
if (sbi_domain_is_assigned_hart(dom, hbase + i))
|
||||||
return 0;
|
ret |= 1UL << i;
|
||||||
|
|
||||||
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;
|
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,
|
void sbi_domain_memregion_init(unsigned long addr,
|
||||||
unsigned long size,
|
unsigned long size,
|
||||||
unsigned long flags,
|
unsigned long flags,
|
||||||
@@ -105,51 +115,64 @@ bool sbi_domain_check_addr(const struct sbi_domain *dom,
|
|||||||
unsigned long addr, unsigned long mode,
|
unsigned long addr, unsigned long mode,
|
||||||
unsigned long access_flags)
|
unsigned long access_flags)
|
||||||
{
|
{
|
||||||
bool mmio = FALSE;
|
bool rmmio, mmio = false;
|
||||||
struct sbi_domain_memregion *reg;
|
struct sbi_domain_memregion *reg;
|
||||||
unsigned long rstart, rend, rflags, rwx = 0;
|
unsigned long rstart, rend, rflags, rwx = 0, rrwx = 0;
|
||||||
|
|
||||||
if (!dom)
|
if (!dom)
|
||||||
return FALSE;
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use M_{R/W/X} bits because the SU-bits are at the
|
||||||
|
* same relative offsets. If the mode is not M, the SU
|
||||||
|
* bits will fall at same offsets after the shift.
|
||||||
|
*/
|
||||||
if (access_flags & SBI_DOMAIN_READ)
|
if (access_flags & SBI_DOMAIN_READ)
|
||||||
rwx |= SBI_DOMAIN_MEMREGION_READABLE;
|
rwx |= SBI_DOMAIN_MEMREGION_M_READABLE;
|
||||||
|
|
||||||
if (access_flags & SBI_DOMAIN_WRITE)
|
if (access_flags & SBI_DOMAIN_WRITE)
|
||||||
rwx |= SBI_DOMAIN_MEMREGION_WRITEABLE;
|
rwx |= SBI_DOMAIN_MEMREGION_M_WRITABLE;
|
||||||
|
|
||||||
if (access_flags & SBI_DOMAIN_EXECUTE)
|
if (access_flags & SBI_DOMAIN_EXECUTE)
|
||||||
rwx |= SBI_DOMAIN_MEMREGION_EXECUTABLE;
|
rwx |= SBI_DOMAIN_MEMREGION_M_EXECUTABLE;
|
||||||
|
|
||||||
if (access_flags & SBI_DOMAIN_MMIO)
|
if (access_flags & SBI_DOMAIN_MMIO)
|
||||||
mmio = TRUE;
|
mmio = true;
|
||||||
|
|
||||||
sbi_domain_for_each_memregion(dom, reg) {
|
sbi_domain_for_each_memregion(dom, reg) {
|
||||||
rflags = reg->flags;
|
rflags = reg->flags;
|
||||||
if (mode == PRV_M && !(rflags & SBI_DOMAIN_MEMREGION_MMODE))
|
rrwx = (mode == PRV_M ?
|
||||||
continue;
|
(rflags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK) :
|
||||||
|
(rflags & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK)
|
||||||
|
>> SBI_DOMAIN_MEMREGION_SU_ACCESS_SHIFT);
|
||||||
|
|
||||||
rstart = reg->base;
|
rstart = reg->base;
|
||||||
rend = (reg->order < __riscv_xlen) ?
|
rend = (reg->order < __riscv_xlen) ?
|
||||||
rstart + ((1UL << reg->order) - 1) : -1UL;
|
rstart + ((1UL << reg->order) - 1) : -1UL;
|
||||||
if (rstart <= addr && addr <= rend) {
|
if (rstart <= addr && addr <= rend) {
|
||||||
if ((mmio && !(rflags & SBI_DOMAIN_MEMREGION_MMIO)) ||
|
rmmio = (rflags & SBI_DOMAIN_MEMREGION_MMIO) ? true : false;
|
||||||
(!mmio && (rflags & SBI_DOMAIN_MEMREGION_MMIO)))
|
if (mmio != rmmio)
|
||||||
return FALSE;
|
return false;
|
||||||
return ((rflags & rwx) == rwx) ? TRUE : FALSE;
|
return ((rrwx & rwx) == rwx) ? true : false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (mode == PRV_M) ? TRUE : FALSE;
|
return (mode == PRV_M) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if region complies with constraints */
|
/* Check if region complies with constraints */
|
||||||
static bool is_region_valid(const struct sbi_domain_memregion *reg)
|
static bool is_region_valid(const struct sbi_domain_memregion *reg)
|
||||||
{
|
{
|
||||||
if (reg->order < 3 || __riscv_xlen < reg->order)
|
if (reg->order < 3 || __riscv_xlen < reg->order)
|
||||||
return FALSE;
|
return false;
|
||||||
|
|
||||||
if (reg->base & (BIT(reg->order) - 1))
|
if (reg->order == __riscv_xlen && reg->base != 0)
|
||||||
return FALSE;
|
return false;
|
||||||
|
|
||||||
return TRUE;
|
if (reg->order < __riscv_xlen && (reg->base & (BIT(reg->order) - 1)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check if regionA is sub-region of regionB */
|
/** Check if regionA is sub-region of regionB */
|
||||||
@@ -165,20 +188,19 @@ static bool is_region_subset(const struct sbi_domain_memregion *regA,
|
|||||||
(regA_start < regB_end) &&
|
(regA_start < regB_end) &&
|
||||||
(regB_start < regA_end) &&
|
(regB_start < regA_end) &&
|
||||||
(regA_end <= regB_end))
|
(regA_end <= regB_end))
|
||||||
return TRUE;
|
return true;
|
||||||
|
|
||||||
return FALSE;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check if regionA conflicts regionB */
|
/** Check if regionA can be replaced by regionB */
|
||||||
static bool is_region_conflict(const struct sbi_domain_memregion *regA,
|
static bool is_region_compatible(const struct sbi_domain_memregion *regA,
|
||||||
const struct sbi_domain_memregion *regB)
|
const struct sbi_domain_memregion *regB)
|
||||||
{
|
{
|
||||||
if ((is_region_subset(regA, regB) || is_region_subset(regB, regA)) &&
|
if (is_region_subset(regA, regB) && regA->flags == regB->flags)
|
||||||
regA->flags == regB->flags)
|
return true;
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
return FALSE;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check if regionA should be placed before regionB */
|
/** Check if regionA should be placed before regionB */
|
||||||
@@ -186,21 +208,73 @@ static bool is_region_before(const struct sbi_domain_memregion *regA,
|
|||||||
const struct sbi_domain_memregion *regB)
|
const struct sbi_domain_memregion *regB)
|
||||||
{
|
{
|
||||||
if (regA->order < regB->order)
|
if (regA->order < regB->order)
|
||||||
return TRUE;
|
return true;
|
||||||
|
|
||||||
if ((regA->order == regB->order) &&
|
if ((regA->order == regB->order) &&
|
||||||
(regA->base < regB->base))
|
(regA->base < regB->base))
|
||||||
return TRUE;
|
return true;
|
||||||
|
|
||||||
return FALSE;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sanitize_domain(const struct sbi_platform *plat,
|
static const struct sbi_domain_memregion *find_region(
|
||||||
struct sbi_domain *dom)
|
const struct sbi_domain *dom,
|
||||||
|
unsigned long addr)
|
||||||
|
{
|
||||||
|
unsigned long rstart, rend;
|
||||||
|
struct sbi_domain_memregion *reg;
|
||||||
|
|
||||||
|
sbi_domain_for_each_memregion(dom, reg) {
|
||||||
|
rstart = reg->base;
|
||||||
|
rend = (reg->order < __riscv_xlen) ?
|
||||||
|
rstart + ((1UL << reg->order) - 1) : -1UL;
|
||||||
|
if (rstart <= addr && addr <= rend)
|
||||||
|
return reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct sbi_domain_memregion *find_next_subset_region(
|
||||||
|
const struct sbi_domain *dom,
|
||||||
|
const struct sbi_domain_memregion *reg,
|
||||||
|
unsigned long addr)
|
||||||
|
{
|
||||||
|
struct sbi_domain_memregion *sreg, *ret = NULL;
|
||||||
|
|
||||||
|
sbi_domain_for_each_memregion(dom, sreg) {
|
||||||
|
if (sreg == reg || (sreg->base <= addr) ||
|
||||||
|
!is_region_subset(sreg, reg))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!ret || (sreg->base < ret->base) ||
|
||||||
|
((sreg->base == ret->base) && (sreg->order < ret->order)))
|
||||||
|
ret = sreg;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void swap_region(struct sbi_domain_memregion* reg1,
|
||||||
|
struct sbi_domain_memregion* reg2)
|
||||||
|
{
|
||||||
|
struct sbi_domain_memregion treg;
|
||||||
|
|
||||||
|
sbi_memcpy(&treg, reg1, sizeof(treg));
|
||||||
|
sbi_memcpy(reg1, reg2, sizeof(treg));
|
||||||
|
sbi_memcpy(reg2, &treg, sizeof(treg));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clear_region(struct sbi_domain_memregion* reg)
|
||||||
|
{
|
||||||
|
sbi_memset(reg, 0x0, sizeof(*reg));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sanitize_domain(struct sbi_domain *dom)
|
||||||
{
|
{
|
||||||
u32 i, j, count;
|
u32 i, j, count;
|
||||||
bool have_fw_reg;
|
bool is_covered;
|
||||||
struct sbi_domain_memregion treg, *reg, *reg1;
|
struct sbi_domain_memregion *reg, *reg1;
|
||||||
|
|
||||||
/* Check possible HARTs */
|
/* Check possible HARTs */
|
||||||
if (!dom->possible_harts) {
|
if (!dom->possible_harts) {
|
||||||
@@ -208,13 +282,14 @@ static int sanitize_domain(const struct sbi_platform *plat,
|
|||||||
__func__, dom->name);
|
__func__, dom->name);
|
||||||
return SBI_EINVAL;
|
return SBI_EINVAL;
|
||||||
}
|
}
|
||||||
sbi_hartmask_for_each_hart(i, dom->possible_harts) {
|
sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
|
||||||
if (sbi_platform_hart_invalid(plat, i)) {
|
if (!sbi_hartindex_valid(i)) {
|
||||||
sbi_printf("%s: %s possible HART mask has invalid "
|
sbi_printf("%s: %s possible HART mask has invalid "
|
||||||
"hart %d\n", __func__, dom->name, i);
|
"hart %d\n", __func__,
|
||||||
|
dom->name, sbi_hartindex_to_hartid(i));
|
||||||
return SBI_EINVAL;
|
return SBI_EINVAL;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/* Check memory regions */
|
/* Check memory regions */
|
||||||
if (!dom->regions) {
|
if (!dom->regions) {
|
||||||
@@ -232,17 +307,13 @@ static int sanitize_domain(const struct sbi_platform *plat,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Count memory regions and check presence of firmware region */
|
/* Count memory regions */
|
||||||
count = 0;
|
count = 0;
|
||||||
have_fw_reg = FALSE;
|
sbi_domain_for_each_memregion(dom, reg)
|
||||||
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++;
|
count++;
|
||||||
}
|
|
||||||
if (!have_fw_reg) {
|
/* Check presence of firmware regions */
|
||||||
|
if (!dom->fw_region_inited) {
|
||||||
sbi_printf("%s: %s does not have firmware region\n",
|
sbi_printf("%s: %s does not have firmware region\n",
|
||||||
__func__, dom->name);
|
__func__, dom->name);
|
||||||
return SBI_EINVAL;
|
return SBI_EINVAL;
|
||||||
@@ -254,25 +325,38 @@ static int sanitize_domain(const struct sbi_platform *plat,
|
|||||||
for (j = i + 1; j < count; j++) {
|
for (j = i + 1; j < count; j++) {
|
||||||
reg1 = &dom->regions[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))
|
if (!is_region_before(reg1, reg))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
sbi_memcpy(&treg, reg1, sizeof(treg));
|
swap_region(reg, reg1);
|
||||||
sbi_memcpy(reg1, reg, sizeof(treg));
|
|
||||||
sbi_memcpy(reg, &treg, sizeof(treg));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Remove covered regions */
|
||||||
|
while(i < (count - 1)) {
|
||||||
|
is_covered = false;
|
||||||
|
reg = &dom->regions[i];
|
||||||
|
|
||||||
|
for (j = i + 1; j < count; j++) {
|
||||||
|
reg1 = &dom->regions[j];
|
||||||
|
|
||||||
|
if (is_region_compatible(reg, reg1)) {
|
||||||
|
is_covered = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find a region is superset of reg, remove reg */
|
||||||
|
if (is_covered) {
|
||||||
|
for (j = i; j < (count - 1); j++)
|
||||||
|
swap_region(&dom->regions[j],
|
||||||
|
&dom->regions[j + 1]);
|
||||||
|
clear_region(&dom->regions[count - 1]);
|
||||||
|
count--;
|
||||||
|
} else
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We don't need to check boot HART id of domain because if boot
|
* 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
|
* HART id is not possible/assigned to this domain then it won't
|
||||||
@@ -282,7 +366,7 @@ static int sanitize_domain(const struct sbi_platform *plat,
|
|||||||
/*
|
/*
|
||||||
* Check next mode
|
* Check next mode
|
||||||
*
|
*
|
||||||
* We only allow next mode to be S-mode or U-mode.so that we can
|
* 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.
|
* protect M-mode context and enforce checks on memory accesses.
|
||||||
*/
|
*/
|
||||||
if (dom->next_mode != PRV_S &&
|
if (dom->next_mode != PRV_S &&
|
||||||
@@ -292,7 +376,7 @@ static int sanitize_domain(const struct sbi_platform *plat,
|
|||||||
return SBI_EINVAL;
|
return SBI_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check next address and next mode*/
|
/* Check next address and next mode */
|
||||||
if (!sbi_domain_check_addr(dom, dom->next_addr, dom->next_mode,
|
if (!sbi_domain_check_addr(dom, dom->next_addr, dom->next_mode,
|
||||||
SBI_DOMAIN_EXECUTE)) {
|
SBI_DOMAIN_EXECUTE)) {
|
||||||
sbi_printf("%s: %s next booting stage address 0x%lx can't "
|
sbi_printf("%s: %s next booting stage address 0x%lx can't "
|
||||||
@@ -303,9 +387,40 @@ static int sanitize_domain(const struct sbi_platform *plat,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool sbi_domain_check_addr_range(const struct sbi_domain *dom,
|
||||||
|
unsigned long addr, unsigned long size,
|
||||||
|
unsigned long mode,
|
||||||
|
unsigned long access_flags)
|
||||||
|
{
|
||||||
|
unsigned long max = addr + size;
|
||||||
|
const struct sbi_domain_memregion *reg, *sreg;
|
||||||
|
|
||||||
|
if (!dom)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
while (addr < max) {
|
||||||
|
reg = find_region(dom, addr);
|
||||||
|
if (!reg)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!sbi_domain_check_addr(dom, addr, mode, access_flags))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
sreg = find_next_subset_region(dom, reg, addr);
|
||||||
|
if (sreg)
|
||||||
|
addr = sreg->base;
|
||||||
|
else if (reg->order < __riscv_xlen)
|
||||||
|
addr = reg->base + (1UL << reg->order);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
|
void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
|
||||||
{
|
{
|
||||||
u32 i, k;
|
u32 i, j, k;
|
||||||
unsigned long rstart, rend;
|
unsigned long rstart, rend;
|
||||||
struct sbi_domain_memregion *reg;
|
struct sbi_domain_memregion *reg;
|
||||||
|
|
||||||
@@ -317,9 +432,11 @@ void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
|
|||||||
|
|
||||||
k = 0;
|
k = 0;
|
||||||
sbi_printf("Domain%d HARTs %s: ", dom->index, suffix);
|
sbi_printf("Domain%d HARTs %s: ", dom->index, suffix);
|
||||||
sbi_hartmask_for_each_hart(i, dom->possible_harts)
|
sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
|
||||||
|
j = sbi_hartindex_to_hartid(i);
|
||||||
sbi_printf("%s%d%s", (k++) ? "," : "",
|
sbi_printf("%s%d%s", (k++) ? "," : "",
|
||||||
i, sbi_domain_is_assigned_hart(dom, i) ? "*" : "");
|
j, sbi_domain_is_assigned_hart(dom, j) ? "*" : "");
|
||||||
|
}
|
||||||
sbi_printf("\n");
|
sbi_printf("\n");
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
@@ -332,15 +449,25 @@ void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
|
|||||||
dom->index, i, suffix, rstart, rend);
|
dom->index, i, suffix, rstart, rend);
|
||||||
|
|
||||||
k = 0;
|
k = 0;
|
||||||
if (reg->flags & SBI_DOMAIN_MEMREGION_MMODE)
|
|
||||||
sbi_printf("%cM", (k++) ? ',' : '(');
|
sbi_printf("M: ");
|
||||||
if (reg->flags & SBI_DOMAIN_MEMREGION_MMIO)
|
if (reg->flags & SBI_DOMAIN_MEMREGION_MMIO)
|
||||||
sbi_printf("%cI", (k++) ? ',' : '(');
|
sbi_printf("%cI", (k++) ? ',' : '(');
|
||||||
if (reg->flags & SBI_DOMAIN_MEMREGION_READABLE)
|
if (reg->flags & SBI_DOMAIN_MEMREGION_M_READABLE)
|
||||||
sbi_printf("%cR", (k++) ? ',' : '(');
|
sbi_printf("%cR", (k++) ? ',' : '(');
|
||||||
if (reg->flags & SBI_DOMAIN_MEMREGION_WRITEABLE)
|
if (reg->flags & SBI_DOMAIN_MEMREGION_M_WRITABLE)
|
||||||
sbi_printf("%cW", (k++) ? ',' : '(');
|
sbi_printf("%cW", (k++) ? ',' : '(');
|
||||||
if (reg->flags & SBI_DOMAIN_MEMREGION_EXECUTABLE)
|
if (reg->flags & SBI_DOMAIN_MEMREGION_M_EXECUTABLE)
|
||||||
|
sbi_printf("%cX", (k++) ? ',' : '(');
|
||||||
|
sbi_printf("%s ", (k++) ? ")" : "()");
|
||||||
|
|
||||||
|
k = 0;
|
||||||
|
sbi_printf("S/U: ");
|
||||||
|
if (reg->flags & SBI_DOMAIN_MEMREGION_SU_READABLE)
|
||||||
|
sbi_printf("%cR", (k++) ? ',' : '(');
|
||||||
|
if (reg->flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE)
|
||||||
|
sbi_printf("%cW", (k++) ? ',' : '(');
|
||||||
|
if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
|
||||||
sbi_printf("%cX", (k++) ? ',' : '(');
|
sbi_printf("%cX", (k++) ? ',' : '(');
|
||||||
sbi_printf("%s\n", (k++) ? ")" : "()");
|
sbi_printf("%s\n", (k++) ? ")" : "()");
|
||||||
|
|
||||||
@@ -367,10 +494,13 @@ void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
|
|||||||
default:
|
default:
|
||||||
sbi_printf("Unknown\n");
|
sbi_printf("Unknown\n");
|
||||||
break;
|
break;
|
||||||
};
|
}
|
||||||
|
|
||||||
sbi_printf("Domain%d SysReset %s: %s\n",
|
sbi_printf("Domain%d SysReset %s: %s\n",
|
||||||
dom->index, suffix, (dom->system_reset_allowed) ? "yes" : "no");
|
dom->index, suffix, (dom->system_reset_allowed) ? "yes" : "no");
|
||||||
|
|
||||||
|
sbi_printf("Domain%d SysSuspend %s: %s\n",
|
||||||
|
dom->index, suffix, (dom->system_suspend_allowed) ? "yes" : "no");
|
||||||
}
|
}
|
||||||
|
|
||||||
void sbi_domain_dump_all(const char *suffix)
|
void sbi_domain_dump_all(const char *suffix)
|
||||||
@@ -391,7 +521,6 @@ int sbi_domain_register(struct sbi_domain *dom,
|
|||||||
int rc;
|
int rc;
|
||||||
struct sbi_domain *tdom;
|
struct sbi_domain *tdom;
|
||||||
u32 cold_hartid = current_hartid();
|
u32 cold_hartid = current_hartid();
|
||||||
const struct sbi_platform *plat = sbi_platform_thishart_ptr();
|
|
||||||
|
|
||||||
/* Sanity checks */
|
/* Sanity checks */
|
||||||
if (!dom || !assign_mask || domain_finalized)
|
if (!dom || !assign_mask || domain_finalized)
|
||||||
@@ -414,7 +543,7 @@ int sbi_domain_register(struct sbi_domain *dom,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Sanitize discovered domain */
|
/* Sanitize discovered domain */
|
||||||
rc = sanitize_domain(plat, dom);
|
rc = sanitize_domain(dom);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
sbi_printf("%s: sanity checks failed for"
|
sbi_printf("%s: sanity checks failed for"
|
||||||
" %s (error %d)\n", __func__,
|
" %s (error %d)\n", __func__,
|
||||||
@@ -430,22 +559,22 @@ int sbi_domain_register(struct sbi_domain *dom,
|
|||||||
sbi_hartmask_clear_all(&dom->assigned_harts);
|
sbi_hartmask_clear_all(&dom->assigned_harts);
|
||||||
|
|
||||||
/* Assign domain to HART if HART is a possible HART */
|
/* Assign domain to HART if HART is a possible HART */
|
||||||
sbi_hartmask_for_each_hart(i, assign_mask) {
|
sbi_hartmask_for_each_hartindex(i, assign_mask) {
|
||||||
if (!sbi_hartmask_test_hart(i, dom->possible_harts))
|
if (!sbi_hartmask_test_hartindex(i, dom->possible_harts))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
tdom = hartid_to_domain_table[i];
|
tdom = sbi_hartindex_to_domain(i);
|
||||||
if (tdom)
|
if (tdom)
|
||||||
sbi_hartmask_clear_hart(i,
|
sbi_hartmask_clear_hartindex(i,
|
||||||
&tdom->assigned_harts);
|
&tdom->assigned_harts);
|
||||||
hartid_to_domain_table[i] = dom;
|
update_hartindex_to_domain(i, dom);
|
||||||
sbi_hartmask_set_hart(i, &dom->assigned_harts);
|
sbi_hartmask_set_hartindex(i, &dom->assigned_harts);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If cold boot HART is assigned to this domain then
|
* If cold boot HART is assigned to this domain then
|
||||||
* override boot HART of this domain.
|
* override boot HART of this domain.
|
||||||
*/
|
*/
|
||||||
if (i == cold_hartid &&
|
if (sbi_hartindex_to_hartid(i) == cold_hartid &&
|
||||||
dom->boot_hartid != cold_hartid) {
|
dom->boot_hartid != cold_hartid) {
|
||||||
sbi_printf("Domain%d Boot HARTID forced to"
|
sbi_printf("Domain%d Boot HARTID forced to"
|
||||||
" %d\n", dom->index, cold_hartid);
|
" %d\n", dom->index, cold_hartid);
|
||||||
@@ -461,34 +590,28 @@ int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg)
|
|||||||
int rc;
|
int rc;
|
||||||
bool reg_merged;
|
bool reg_merged;
|
||||||
struct sbi_domain_memregion *nreg, *nreg1, *nreg2;
|
struct sbi_domain_memregion *nreg, *nreg1, *nreg2;
|
||||||
const struct sbi_platform *plat = sbi_platform_thishart_ptr();
|
|
||||||
|
|
||||||
/* Sanity checks */
|
/* Sanity checks */
|
||||||
if (!reg || domain_finalized ||
|
if (!reg || domain_finalized || !root.regions ||
|
||||||
(root.regions != root_memregs) ||
|
|
||||||
(ROOT_REGION_MAX <= root_memregs_count))
|
(ROOT_REGION_MAX <= root_memregs_count))
|
||||||
return SBI_EINVAL;
|
return SBI_EINVAL;
|
||||||
|
|
||||||
/* Check for conflicts */
|
/* Check whether compatible region exists for the new one */
|
||||||
sbi_domain_for_each_memregion(&root, nreg) {
|
sbi_domain_for_each_memregion(&root, nreg) {
|
||||||
if (is_region_conflict(reg, nreg)) {
|
if (is_region_compatible(reg, nreg))
|
||||||
sbi_printf("%s: is_region_conflict check failed"
|
return 0;
|
||||||
" 0x%lx conflicts existing 0x%lx\n", __func__,
|
|
||||||
reg->base, nreg->base);
|
|
||||||
return SBI_EALREADY;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Append the memregion to root memregions */
|
/* Append the memregion to root memregions */
|
||||||
nreg = &root_memregs[root_memregs_count];
|
nreg = &root.regions[root_memregs_count];
|
||||||
sbi_memcpy(nreg, reg, sizeof(*reg));
|
sbi_memcpy(nreg, reg, sizeof(*reg));
|
||||||
root_memregs_count++;
|
root_memregs_count++;
|
||||||
root_memregs[root_memregs_count].order = 0;
|
root.regions[root_memregs_count].order = 0;
|
||||||
|
|
||||||
/* Sort and optimize root regions */
|
/* Sort and optimize root regions */
|
||||||
do {
|
do {
|
||||||
/* Sanitize the root domain so that memregions are sorted */
|
/* Sanitize the root domain so that memregions are sorted */
|
||||||
rc = sanitize_domain(plat, &root);
|
rc = sanitize_domain(&root);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
sbi_printf("%s: sanity checks failed for"
|
sbi_printf("%s: sanity checks failed for"
|
||||||
" %s (error %d)\n", __func__,
|
" %s (error %d)\n", __func__,
|
||||||
@@ -522,6 +645,33 @@ int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sbi_domain_root_add_memrange(unsigned long addr, unsigned long size,
|
||||||
|
unsigned long align, unsigned long region_flags)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
unsigned long pos, end, rsize;
|
||||||
|
struct sbi_domain_memregion reg;
|
||||||
|
|
||||||
|
pos = addr;
|
||||||
|
end = addr + size;
|
||||||
|
while (pos < end) {
|
||||||
|
rsize = pos & (align - 1);
|
||||||
|
if (rsize)
|
||||||
|
rsize = 1UL << sbi_ffs(pos);
|
||||||
|
else
|
||||||
|
rsize = ((end - pos) < align) ?
|
||||||
|
(end - pos) : align;
|
||||||
|
|
||||||
|
sbi_domain_memregion_init(pos, rsize, region_flags, ®);
|
||||||
|
rc = sbi_domain_root_add_memregion(®);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
pos += rsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
|
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
@@ -539,36 +689,37 @@ int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
|
|||||||
|
|
||||||
/* Startup boot HART of domains */
|
/* Startup boot HART of domains */
|
||||||
sbi_domain_for_each(i, dom) {
|
sbi_domain_for_each(i, dom) {
|
||||||
/* Domain boot HART */
|
/* Domain boot HART index */
|
||||||
dhart = dom->boot_hartid;
|
dhart = sbi_hartid_to_hartindex(dom->boot_hartid);
|
||||||
|
|
||||||
/* Ignore of boot HART is off limits */
|
/* Ignore of boot HART is off limits */
|
||||||
if (SBI_HARTMASK_MAX_BITS <= dhart)
|
if (!sbi_hartindex_valid(dhart))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Ignore if boot HART not possible for this domain */
|
/* Ignore if boot HART not possible for this domain */
|
||||||
if (!sbi_hartmask_test_hart(dhart, dom->possible_harts))
|
if (!sbi_hartmask_test_hartindex(dhart, dom->possible_harts))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Ignore if boot HART assigned different domain */
|
/* Ignore if boot HART assigned different domain */
|
||||||
if (sbi_hartid_to_domain(dhart) != dom ||
|
if (sbi_hartindex_to_domain(dhart) != dom ||
|
||||||
!sbi_hartmask_test_hart(dhart, &dom->assigned_harts))
|
!sbi_hartmask_test_hartindex(dhart, &dom->assigned_harts))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Startup boot HART of domain */
|
/* Startup boot HART of domain */
|
||||||
if (dhart == cold_hartid) {
|
if (dom->boot_hartid == cold_hartid) {
|
||||||
scratch->next_addr = dom->next_addr;
|
scratch->next_addr = dom->next_addr;
|
||||||
scratch->next_mode = dom->next_mode;
|
scratch->next_mode = dom->next_mode;
|
||||||
scratch->next_arg1 = dom->next_arg1;
|
scratch->next_arg1 = dom->next_arg1;
|
||||||
} else {
|
} else {
|
||||||
rc = sbi_hsm_hart_start(scratch, NULL, dhart,
|
rc = sbi_hsm_hart_start(scratch, NULL,
|
||||||
|
dom->boot_hartid,
|
||||||
dom->next_addr,
|
dom->next_addr,
|
||||||
dom->next_mode,
|
dom->next_mode,
|
||||||
dom->next_arg1);
|
dom->next_arg1);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
sbi_printf("%s: failed to start boot HART %d"
|
sbi_printf("%s: failed to start boot HART %d"
|
||||||
" for %s (error %d)\n", __func__,
|
" for %s (error %d)\n", __func__,
|
||||||
dhart, dom->name, rc);
|
dom->boot_hartid, dom->name, rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -586,18 +737,69 @@ int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
|
|||||||
int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
|
int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
|
||||||
{
|
{
|
||||||
u32 i;
|
u32 i;
|
||||||
|
int rc;
|
||||||
|
struct sbi_hartmask *root_hmask;
|
||||||
|
struct sbi_domain_memregion *root_memregs;
|
||||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||||
|
|
||||||
/* Root domain firmware memory region */
|
if (scratch->fw_rw_offset == 0 ||
|
||||||
sbi_domain_memregion_init(scratch->fw_start, scratch->fw_size, 0,
|
(scratch->fw_rw_offset & (scratch->fw_rw_offset - 1)) != 0) {
|
||||||
&root_fw_region);
|
sbi_printf("%s: fw_rw_offset is not a power of 2 (0x%lx)\n",
|
||||||
domain_memregion_initfw(&root_memregs[root_memregs_count++]);
|
__func__, scratch->fw_rw_offset);
|
||||||
|
return SBI_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Root domain allow everything memory region */
|
if ((scratch->fw_start & (scratch->fw_rw_offset - 1)) != 0) {
|
||||||
|
sbi_printf("%s: fw_start and fw_rw_offset not aligned\n",
|
||||||
|
__func__);
|
||||||
|
return SBI_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
domain_hart_ptr_offset = sbi_scratch_alloc_type_offset(void *);
|
||||||
|
if (!domain_hart_ptr_offset)
|
||||||
|
return SBI_ENOMEM;
|
||||||
|
|
||||||
|
root_memregs = sbi_calloc(sizeof(*root_memregs), ROOT_REGION_MAX + 1);
|
||||||
|
if (!root_memregs) {
|
||||||
|
sbi_printf("%s: no memory for root regions\n", __func__);
|
||||||
|
rc = SBI_ENOMEM;
|
||||||
|
goto fail_free_domain_hart_ptr_offset;
|
||||||
|
}
|
||||||
|
root.regions = root_memregs;
|
||||||
|
|
||||||
|
root_hmask = sbi_zalloc(sizeof(*root_hmask));
|
||||||
|
if (!root_hmask) {
|
||||||
|
sbi_printf("%s: no memory for root hartmask\n", __func__);
|
||||||
|
rc = SBI_ENOMEM;
|
||||||
|
goto fail_free_root_memregs;
|
||||||
|
}
|
||||||
|
root.possible_harts = root_hmask;
|
||||||
|
|
||||||
|
/* Root domain firmware memory region */
|
||||||
|
sbi_domain_memregion_init(scratch->fw_start, scratch->fw_rw_offset,
|
||||||
|
(SBI_DOMAIN_MEMREGION_M_READABLE |
|
||||||
|
SBI_DOMAIN_MEMREGION_M_EXECUTABLE),
|
||||||
|
&root_memregs[root_memregs_count++]);
|
||||||
|
|
||||||
|
sbi_domain_memregion_init((scratch->fw_start + scratch->fw_rw_offset),
|
||||||
|
(scratch->fw_size - scratch->fw_rw_offset),
|
||||||
|
(SBI_DOMAIN_MEMREGION_M_READABLE |
|
||||||
|
SBI_DOMAIN_MEMREGION_M_WRITABLE),
|
||||||
|
&root_memregs[root_memregs_count++]);
|
||||||
|
|
||||||
|
root.fw_region_inited = true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allow SU RWX on rest of the memory region. Since pmp entries
|
||||||
|
* have implicit priority on index, previous entries will
|
||||||
|
* deny access to SU on M-mode region. Also, M-mode will not
|
||||||
|
* have access to SU region while previous entries will allow
|
||||||
|
* access to M-mode regions.
|
||||||
|
*/
|
||||||
sbi_domain_memregion_init(0, ~0UL,
|
sbi_domain_memregion_init(0, ~0UL,
|
||||||
(SBI_DOMAIN_MEMREGION_READABLE |
|
(SBI_DOMAIN_MEMREGION_SU_READABLE |
|
||||||
SBI_DOMAIN_MEMREGION_WRITEABLE |
|
SBI_DOMAIN_MEMREGION_SU_WRITABLE |
|
||||||
SBI_DOMAIN_MEMREGION_EXECUTABLE),
|
SBI_DOMAIN_MEMREGION_SU_EXECUTABLE),
|
||||||
&root_memregs[root_memregs_count++]);
|
&root_memregs[root_memregs_count++]);
|
||||||
|
|
||||||
/* Root domain memory region end */
|
/* Root domain memory region end */
|
||||||
@@ -612,11 +814,21 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
|
|||||||
root.next_mode = scratch->next_mode;
|
root.next_mode = scratch->next_mode;
|
||||||
|
|
||||||
/* Root domain possible and assigned HARTs */
|
/* Root domain possible and assigned HARTs */
|
||||||
for (i = 0; i < SBI_HARTMASK_MAX_BITS; i++) {
|
for (i = 0; i < plat->hart_count; i++)
|
||||||
if (sbi_platform_hart_invalid(plat, i))
|
sbi_hartmask_set_hartindex(i, root_hmask);
|
||||||
continue;
|
|
||||||
sbi_hartmask_set_hart(i, &root_hmask);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sbi_domain_register(&root, &root_hmask);
|
/* Finally register the root domain */
|
||||||
|
rc = sbi_domain_register(&root, root_hmask);
|
||||||
|
if (rc)
|
||||||
|
goto fail_free_root_hmask;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail_free_root_hmask:
|
||||||
|
sbi_free(root_hmask);
|
||||||
|
fail_free_root_memregs:
|
||||||
|
sbi_free(root_memregs);
|
||||||
|
fail_free_domain_hart_ptr_offset:
|
||||||
|
sbi_scratch_free_offset(domain_hart_ptr_offset);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
@@ -13,6 +13,9 @@
|
|||||||
#include <sbi/sbi_error.h>
|
#include <sbi/sbi_error.h>
|
||||||
#include <sbi/sbi_trap.h>
|
#include <sbi/sbi_trap.h>
|
||||||
|
|
||||||
|
extern struct sbi_ecall_extension *sbi_ecall_exts[];
|
||||||
|
extern unsigned long sbi_ecall_exts_size;
|
||||||
|
|
||||||
u16 sbi_ecall_version_major(void)
|
u16 sbi_ecall_version_major(void)
|
||||||
{
|
{
|
||||||
return SBI_ECALL_VERSION_MAJOR;
|
return SBI_ECALL_VERSION_MAJOR;
|
||||||
@@ -75,7 +78,7 @@ int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)
|
|||||||
|
|
||||||
void sbi_ecall_unregister_extension(struct sbi_ecall_extension *ext)
|
void sbi_ecall_unregister_extension(struct sbi_ecall_extension *ext)
|
||||||
{
|
{
|
||||||
bool found = FALSE;
|
bool found = false;
|
||||||
struct sbi_ecall_extension *t;
|
struct sbi_ecall_extension *t;
|
||||||
|
|
||||||
if (!ext)
|
if (!ext)
|
||||||
@@ -83,7 +86,7 @@ void sbi_ecall_unregister_extension(struct sbi_ecall_extension *ext)
|
|||||||
|
|
||||||
sbi_list_for_each_entry(t, &ecall_exts_list, head) {
|
sbi_list_for_each_entry(t, &ecall_exts_list, head) {
|
||||||
if (t == ext) {
|
if (t == ext) {
|
||||||
found = TRUE;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,14 +101,12 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs)
|
|||||||
struct sbi_ecall_extension *ext;
|
struct sbi_ecall_extension *ext;
|
||||||
unsigned long extension_id = regs->a7;
|
unsigned long extension_id = regs->a7;
|
||||||
unsigned long func_id = regs->a6;
|
unsigned long func_id = regs->a6;
|
||||||
struct sbi_trap_info trap = {0};
|
struct sbi_ecall_return out = {0};
|
||||||
unsigned long out_val = 0;
|
|
||||||
bool is_0_1_spec = 0;
|
bool is_0_1_spec = 0;
|
||||||
|
|
||||||
ext = sbi_ecall_find_extension(extension_id);
|
ext = sbi_ecall_find_extension(extension_id);
|
||||||
if (ext && ext->handle) {
|
if (ext && ext->handle) {
|
||||||
ret = ext->handle(extension_id, func_id,
|
ret = ext->handle(extension_id, func_id, regs, &out);
|
||||||
regs, &out_val, &trap);
|
|
||||||
if (extension_id >= SBI_EXT_0_1_SET_TIMER &&
|
if (extension_id >= SBI_EXT_0_1_SET_TIMER &&
|
||||||
extension_id <= SBI_EXT_0_1_SHUTDOWN)
|
extension_id <= SBI_EXT_0_1_SHUTDOWN)
|
||||||
is_0_1_spec = 1;
|
is_0_1_spec = 1;
|
||||||
@@ -113,11 +114,10 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs)
|
|||||||
ret = SBI_ENOTSUPP;
|
ret = SBI_ENOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == SBI_ETRAP) {
|
if (!out.skip_regs_update) {
|
||||||
trap.epc = regs->mepc;
|
if (ret < SBI_LAST_ERR ||
|
||||||
sbi_trap_redirect(regs, &trap);
|
(extension_id != SBI_EXT_0_1_CONSOLE_GETCHAR &&
|
||||||
} else {
|
SBI_SUCCESS < ret)) {
|
||||||
if (ret < SBI_LAST_ERR) {
|
|
||||||
sbi_printf("%s: Invalid error %d for ext=0x%lx "
|
sbi_printf("%s: Invalid error %d for ext=0x%lx "
|
||||||
"func=0x%lx\n", __func__, ret,
|
"func=0x%lx\n", __func__, ret,
|
||||||
extension_id, func_id);
|
extension_id, func_id);
|
||||||
@@ -135,7 +135,7 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs)
|
|||||||
regs->mepc += 4;
|
regs->mepc += 4;
|
||||||
regs->a0 = ret;
|
regs->a0 = ret;
|
||||||
if (!is_0_1_spec)
|
if (!is_0_1_spec)
|
||||||
regs->a1 = out_val;
|
regs->a1 = out.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -144,35 +144,18 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs)
|
|||||||
int sbi_ecall_init(void)
|
int sbi_ecall_init(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
struct sbi_ecall_extension *ext;
|
||||||
|
unsigned long i;
|
||||||
|
|
||||||
/* The order of below registrations is performance optimized */
|
for (i = 0; i < sbi_ecall_exts_size; i++) {
|
||||||
ret = sbi_ecall_register_extension(&ecall_time);
|
ext = sbi_ecall_exts[i];
|
||||||
if (ret)
|
ret = SBI_ENODEV;
|
||||||
return ret;
|
|
||||||
ret = sbi_ecall_register_extension(&ecall_rfence);
|
if (ext->register_extensions)
|
||||||
if (ret)
|
ret = ext->register_extensions();
|
||||||
return ret;
|
if (ret)
|
||||||
ret = sbi_ecall_register_extension(&ecall_ipi);
|
return ret;
|
||||||
if (ret)
|
}
|
||||||
return ret;
|
|
||||||
ret = sbi_ecall_register_extension(&ecall_base);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
ret = sbi_ecall_register_extension(&ecall_hsm);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
ret = sbi_ecall_register_extension(&ecall_srst);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
ret = sbi_ecall_register_extension(&ecall_pmu);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
ret = sbi_ecall_register_extension(&ecall_legacy);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
ret = sbi_ecall_register_extension(&ecall_vendor);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -33,37 +33,36 @@ 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,
|
static int sbi_ecall_base_handler(unsigned long extid, unsigned long funcid,
|
||||||
const struct sbi_trap_regs *regs,
|
struct sbi_trap_regs *regs,
|
||||||
unsigned long *out_val,
|
struct sbi_ecall_return *out)
|
||||||
struct sbi_trap_info *out_trap)
|
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
switch (funcid) {
|
switch (funcid) {
|
||||||
case SBI_EXT_BASE_GET_SPEC_VERSION:
|
case SBI_EXT_BASE_GET_SPEC_VERSION:
|
||||||
*out_val = (SBI_ECALL_VERSION_MAJOR <<
|
out->value = (SBI_ECALL_VERSION_MAJOR <<
|
||||||
SBI_SPEC_VERSION_MAJOR_OFFSET) &
|
SBI_SPEC_VERSION_MAJOR_OFFSET) &
|
||||||
(SBI_SPEC_VERSION_MAJOR_MASK <<
|
(SBI_SPEC_VERSION_MAJOR_MASK <<
|
||||||
SBI_SPEC_VERSION_MAJOR_OFFSET);
|
SBI_SPEC_VERSION_MAJOR_OFFSET);
|
||||||
*out_val = *out_val | SBI_ECALL_VERSION_MINOR;
|
out->value = out->value | SBI_ECALL_VERSION_MINOR;
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_BASE_GET_IMP_ID:
|
case SBI_EXT_BASE_GET_IMP_ID:
|
||||||
*out_val = sbi_ecall_get_impid();
|
out->value = sbi_ecall_get_impid();
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_BASE_GET_IMP_VERSION:
|
case SBI_EXT_BASE_GET_IMP_VERSION:
|
||||||
*out_val = OPENSBI_VERSION;
|
out->value = OPENSBI_VERSION;
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_BASE_GET_MVENDORID:
|
case SBI_EXT_BASE_GET_MVENDORID:
|
||||||
*out_val = csr_read(CSR_MVENDORID);
|
out->value = csr_read(CSR_MVENDORID);
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_BASE_GET_MARCHID:
|
case SBI_EXT_BASE_GET_MARCHID:
|
||||||
*out_val = csr_read(CSR_MARCHID);
|
out->value = csr_read(CSR_MARCHID);
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_BASE_GET_MIMPID:
|
case SBI_EXT_BASE_GET_MIMPID:
|
||||||
*out_val = csr_read(CSR_MIMPID);
|
out->value = csr_read(CSR_MIMPID);
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_BASE_PROBE_EXT:
|
case SBI_EXT_BASE_PROBE_EXT:
|
||||||
ret = sbi_ecall_base_probe(regs->a0, out_val);
|
ret = sbi_ecall_base_probe(regs->a0, &out->value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = SBI_ENOTSUPP;
|
ret = SBI_ENOTSUPP;
|
||||||
@@ -72,8 +71,16 @@ static int sbi_ecall_base_handler(unsigned long extid, unsigned long funcid,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct sbi_ecall_extension ecall_base;
|
||||||
|
|
||||||
|
static int sbi_ecall_base_register_extensions(void)
|
||||||
|
{
|
||||||
|
return sbi_ecall_register_extension(&ecall_base);
|
||||||
|
}
|
||||||
|
|
||||||
struct sbi_ecall_extension ecall_base = {
|
struct sbi_ecall_extension ecall_base = {
|
||||||
.extid_start = SBI_EXT_BASE,
|
.extid_start = SBI_EXT_BASE,
|
||||||
.extid_end = SBI_EXT_BASE,
|
.extid_end = SBI_EXT_BASE,
|
||||||
.handle = sbi_ecall_base_handler,
|
.register_extensions = sbi_ecall_base_register_extensions,
|
||||||
|
.handle = sbi_ecall_base_handler,
|
||||||
};
|
};
|
||||||
|
66
lib/sbi/sbi_ecall_cppc.c
Normal file
66
lib/sbi/sbi_ecall_cppc.c
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Ventana Micro Systems Inc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi/sbi_ecall.h>
|
||||||
|
#include <sbi/sbi_ecall_interface.h>
|
||||||
|
#include <sbi/sbi_error.h>
|
||||||
|
#include <sbi/sbi_trap.h>
|
||||||
|
#include <sbi/sbi_cppc.h>
|
||||||
|
|
||||||
|
static int sbi_ecall_cppc_handler(unsigned long extid, unsigned long funcid,
|
||||||
|
struct sbi_trap_regs *regs,
|
||||||
|
struct sbi_ecall_return *out)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
uint64_t temp;
|
||||||
|
|
||||||
|
switch (funcid) {
|
||||||
|
case SBI_EXT_CPPC_READ:
|
||||||
|
ret = sbi_cppc_read(regs->a0, &temp);
|
||||||
|
out->value = temp;
|
||||||
|
break;
|
||||||
|
case SBI_EXT_CPPC_READ_HI:
|
||||||
|
#if __riscv_xlen == 32
|
||||||
|
ret = sbi_cppc_read(regs->a0, &temp);
|
||||||
|
out->value = temp >> 32;
|
||||||
|
#else
|
||||||
|
out->value = 0;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case SBI_EXT_CPPC_WRITE:
|
||||||
|
ret = sbi_cppc_write(regs->a0, regs->a1);
|
||||||
|
break;
|
||||||
|
case SBI_EXT_CPPC_PROBE:
|
||||||
|
ret = sbi_cppc_probe(regs->a0);
|
||||||
|
if (ret >= 0) {
|
||||||
|
out->value = ret;
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = SBI_ENOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sbi_ecall_extension ecall_cppc;
|
||||||
|
|
||||||
|
static int sbi_ecall_cppc_register_extensions(void)
|
||||||
|
{
|
||||||
|
if (!sbi_cppc_get_device())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return sbi_ecall_register_extension(&ecall_cppc);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sbi_ecall_extension ecall_cppc = {
|
||||||
|
.extid_start = SBI_EXT_CPPC,
|
||||||
|
.extid_end = SBI_EXT_CPPC,
|
||||||
|
.register_extensions = sbi_ecall_cppc_register_extensions,
|
||||||
|
.handle = sbi_ecall_cppc_handler,
|
||||||
|
};
|
81
lib/sbi/sbi_ecall_dbcn.c
Normal file
81
lib/sbi/sbi_ecall_dbcn.c
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Ventana Micro Systems Inc.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <apatel@ventanamicro.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi/sbi_console.h>
|
||||||
|
#include <sbi/sbi_domain.h>
|
||||||
|
#include <sbi/sbi_error.h>
|
||||||
|
#include <sbi/sbi_ecall.h>
|
||||||
|
#include <sbi/sbi_ecall_interface.h>
|
||||||
|
#include <sbi/sbi_trap.h>
|
||||||
|
#include <sbi/riscv_asm.h>
|
||||||
|
#include <sbi/sbi_hart.h>
|
||||||
|
|
||||||
|
static int sbi_ecall_dbcn_handler(unsigned long extid, unsigned long funcid,
|
||||||
|
struct sbi_trap_regs *regs,
|
||||||
|
struct sbi_ecall_return *out)
|
||||||
|
{
|
||||||
|
ulong smode = (csr_read(CSR_MSTATUS) & MSTATUS_MPP) >>
|
||||||
|
MSTATUS_MPP_SHIFT;
|
||||||
|
|
||||||
|
switch (funcid) {
|
||||||
|
case SBI_EXT_DBCN_CONSOLE_WRITE:
|
||||||
|
case SBI_EXT_DBCN_CONSOLE_READ:
|
||||||
|
/*
|
||||||
|
* On RV32, the M-mode can only access the first 4GB of
|
||||||
|
* the physical address space because M-mode does not have
|
||||||
|
* MMU to access full 34-bit physical address space.
|
||||||
|
*
|
||||||
|
* Based on above, we simply fail if the upper 32bits of
|
||||||
|
* the physical address (i.e. a2 register) is non-zero on
|
||||||
|
* RV32.
|
||||||
|
*
|
||||||
|
* Analogously, we fail if the upper 64bit of the
|
||||||
|
* physical address (i.e. a2 register) is non-zero on
|
||||||
|
* RV64.
|
||||||
|
*/
|
||||||
|
if (regs->a2)
|
||||||
|
return SBI_ERR_FAILED;
|
||||||
|
|
||||||
|
if (!sbi_domain_check_addr_range(sbi_domain_thishart_ptr(),
|
||||||
|
regs->a1, regs->a0, smode,
|
||||||
|
SBI_DOMAIN_READ|SBI_DOMAIN_WRITE))
|
||||||
|
return SBI_ERR_INVALID_PARAM;
|
||||||
|
sbi_hart_map_saddr(regs->a1, regs->a0);
|
||||||
|
if (funcid == SBI_EXT_DBCN_CONSOLE_WRITE)
|
||||||
|
out->value = sbi_nputs((const char *)regs->a1, regs->a0);
|
||||||
|
else
|
||||||
|
out->value = sbi_ngets((char *)regs->a1, regs->a0);
|
||||||
|
sbi_hart_unmap_saddr();
|
||||||
|
return 0;
|
||||||
|
case SBI_EXT_DBCN_CONSOLE_WRITE_BYTE:
|
||||||
|
sbi_putc(regs->a0);
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SBI_ENOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sbi_ecall_extension ecall_dbcn;
|
||||||
|
|
||||||
|
static int sbi_ecall_dbcn_register_extensions(void)
|
||||||
|
{
|
||||||
|
if (!sbi_console_get_device())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return sbi_ecall_register_extension(&ecall_dbcn);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sbi_ecall_extension ecall_dbcn = {
|
||||||
|
.extid_start = SBI_EXT_DBCN,
|
||||||
|
.extid_end = SBI_EXT_DBCN,
|
||||||
|
.register_extensions = sbi_ecall_dbcn_register_extensions,
|
||||||
|
.handle = sbi_ecall_dbcn_handler,
|
||||||
|
};
|
3
lib/sbi/sbi_ecall_exts.carray
Normal file
3
lib/sbi/sbi_ecall_exts.carray
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
HEADER: sbi/sbi_ecall.h
|
||||||
|
TYPE: struct sbi_ecall_extension
|
||||||
|
NAME: sbi_ecall_exts
|
@@ -12,15 +12,13 @@
|
|||||||
#include <sbi/sbi_ecall_interface.h>
|
#include <sbi/sbi_ecall_interface.h>
|
||||||
#include <sbi/sbi_error.h>
|
#include <sbi/sbi_error.h>
|
||||||
#include <sbi/sbi_trap.h>
|
#include <sbi/sbi_trap.h>
|
||||||
#include <sbi/sbi_version.h>
|
|
||||||
#include <sbi/sbi_hsm.h>
|
#include <sbi/sbi_hsm.h>
|
||||||
#include <sbi/sbi_scratch.h>
|
#include <sbi/sbi_scratch.h>
|
||||||
#include <sbi/riscv_asm.h>
|
#include <sbi/riscv_asm.h>
|
||||||
|
|
||||||
static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid,
|
static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid,
|
||||||
const struct sbi_trap_regs *regs,
|
struct sbi_trap_regs *regs,
|
||||||
unsigned long *out_val,
|
struct sbi_ecall_return *out)
|
||||||
struct sbi_trap_info *out_trap)
|
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||||
@@ -33,7 +31,7 @@ static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid,
|
|||||||
regs->a0, regs->a1, smode, regs->a2);
|
regs->a0, regs->a1, smode, regs->a2);
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_HSM_HART_STOP:
|
case SBI_EXT_HSM_HART_STOP:
|
||||||
ret = sbi_hsm_hart_stop(scratch, TRUE);
|
ret = sbi_hsm_hart_stop(scratch, true);
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_HSM_HART_GET_STATUS:
|
case SBI_EXT_HSM_HART_GET_STATUS:
|
||||||
ret = sbi_hsm_hart_get_state(sbi_domain_thishart_ptr(),
|
ret = sbi_hsm_hart_get_state(sbi_domain_thishart_ptr(),
|
||||||
@@ -45,17 +43,26 @@ static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid,
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = SBI_ENOTSUPP;
|
ret = SBI_ENOTSUPP;
|
||||||
};
|
}
|
||||||
|
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
*out_val = ret;
|
out->value = ret;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct sbi_ecall_extension ecall_hsm;
|
||||||
|
|
||||||
|
static int sbi_ecall_hsm_register_extensions(void)
|
||||||
|
{
|
||||||
|
return sbi_ecall_register_extension(&ecall_hsm);
|
||||||
|
}
|
||||||
|
|
||||||
struct sbi_ecall_extension ecall_hsm = {
|
struct sbi_ecall_extension ecall_hsm = {
|
||||||
.extid_start = SBI_EXT_HSM,
|
.extid_start = SBI_EXT_HSM,
|
||||||
.extid_end = SBI_EXT_HSM,
|
.extid_end = SBI_EXT_HSM,
|
||||||
.handle = sbi_ecall_hsm_handler,
|
.register_extensions = sbi_ecall_hsm_register_extensions,
|
||||||
|
.handle = sbi_ecall_hsm_handler,
|
||||||
};
|
};
|
||||||
|
43
lib/sbi/sbi_ecall_ipi.c
Normal file
43
lib/sbi/sbi_ecall_ipi.c
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
* Atish Patra <atish.patra@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi/sbi_error.h>
|
||||||
|
#include <sbi/sbi_ecall.h>
|
||||||
|
#include <sbi/sbi_ecall_interface.h>
|
||||||
|
#include <sbi/sbi_trap.h>
|
||||||
|
#include <sbi/sbi_ipi.h>
|
||||||
|
|
||||||
|
static int sbi_ecall_ipi_handler(unsigned long extid, unsigned long funcid,
|
||||||
|
struct sbi_trap_regs *regs,
|
||||||
|
struct sbi_ecall_return *out)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (funcid == SBI_EXT_IPI_SEND_IPI)
|
||||||
|
ret = sbi_ipi_send_smode(regs->a0, regs->a1);
|
||||||
|
else
|
||||||
|
ret = SBI_ENOTSUPP;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sbi_ecall_extension ecall_ipi;
|
||||||
|
|
||||||
|
static int sbi_ecall_ipi_register_extensions(void)
|
||||||
|
{
|
||||||
|
return sbi_ecall_register_extension(&ecall_ipi);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sbi_ecall_extension ecall_ipi = {
|
||||||
|
.extid_start = SBI_EXT_IPI,
|
||||||
|
.extid_end = SBI_EXT_IPI,
|
||||||
|
.register_extensions = sbi_ecall_ipi_register_extensions,
|
||||||
|
.handle = sbi_ecall_ipi_handler,
|
||||||
|
};
|
@@ -24,32 +24,32 @@
|
|||||||
#include <sbi/sbi_unpriv.h>
|
#include <sbi/sbi_unpriv.h>
|
||||||
#include <sbi/sbi_hart.h>
|
#include <sbi/sbi_hart.h>
|
||||||
|
|
||||||
static int sbi_load_hart_mask_unpriv(ulong *pmask, ulong *hmask,
|
static bool sbi_load_hart_mask_unpriv(ulong *pmask, ulong *hmask,
|
||||||
struct sbi_trap_info *uptrap)
|
struct sbi_trap_info *uptrap)
|
||||||
{
|
{
|
||||||
ulong mask = 0;
|
ulong mask = 0;
|
||||||
|
|
||||||
if (pmask) {
|
if (pmask) {
|
||||||
mask = sbi_load_ulong(pmask, uptrap);
|
mask = sbi_load_ulong(pmask, uptrap);
|
||||||
if (uptrap->cause)
|
if (uptrap->cause)
|
||||||
return SBI_ETRAP;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
sbi_hsm_hart_interruptible_mask(sbi_domain_thishart_ptr(),
|
sbi_hsm_hart_interruptible_mask(sbi_domain_thishart_ptr(),
|
||||||
0, &mask);
|
0, &mask);
|
||||||
}
|
}
|
||||||
*hmask = mask;
|
*hmask = mask;
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
|
static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
|
||||||
const struct sbi_trap_regs *regs,
|
struct sbi_trap_regs *regs,
|
||||||
unsigned long *out_val,
|
struct sbi_ecall_return *out)
|
||||||
struct sbi_trap_info *out_trap)
|
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct sbi_tlb_info tlb_info;
|
struct sbi_tlb_info tlb_info;
|
||||||
u32 source_hart = current_hartid();
|
u32 source_hart = current_hartid();
|
||||||
|
struct sbi_trap_info trap = {0};
|
||||||
ulong hmask = 0;
|
ulong hmask = 0;
|
||||||
|
|
||||||
switch (extid) {
|
switch (extid) {
|
||||||
@@ -70,40 +70,51 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
|
|||||||
sbi_ipi_clear_smode();
|
sbi_ipi_clear_smode();
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_0_1_SEND_IPI:
|
case SBI_EXT_0_1_SEND_IPI:
|
||||||
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
|
if (sbi_load_hart_mask_unpriv((ulong *)regs->a0,
|
||||||
&hmask, out_trap);
|
&hmask, &trap)) {
|
||||||
if (ret != SBI_ETRAP)
|
|
||||||
ret = sbi_ipi_send_smode(hmask, 0);
|
ret = sbi_ipi_send_smode(hmask, 0);
|
||||||
|
} else {
|
||||||
|
trap.epc = regs->mepc;
|
||||||
|
sbi_trap_redirect(regs, &trap);
|
||||||
|
out->skip_regs_update = true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_0_1_REMOTE_FENCE_I:
|
case SBI_EXT_0_1_REMOTE_FENCE_I:
|
||||||
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
|
if (sbi_load_hart_mask_unpriv((ulong *)regs->a0,
|
||||||
&hmask, out_trap);
|
&hmask, &trap)) {
|
||||||
if (ret != SBI_ETRAP) {
|
|
||||||
SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, 0,
|
SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, 0,
|
||||||
sbi_tlb_local_fence_i,
|
SBI_TLB_FENCE_I, source_hart);
|
||||||
source_hart);
|
|
||||||
ret = sbi_tlb_request(hmask, 0, &tlb_info);
|
ret = sbi_tlb_request(hmask, 0, &tlb_info);
|
||||||
|
} else {
|
||||||
|
trap.epc = regs->mepc;
|
||||||
|
sbi_trap_redirect(regs, &trap);
|
||||||
|
out->skip_regs_update = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_0_1_REMOTE_SFENCE_VMA:
|
case SBI_EXT_0_1_REMOTE_SFENCE_VMA:
|
||||||
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
|
if (sbi_load_hart_mask_unpriv((ulong *)regs->a0,
|
||||||
&hmask, out_trap);
|
&hmask, &trap)) {
|
||||||
if (ret != SBI_ETRAP) {
|
|
||||||
SBI_TLB_INFO_INIT(&tlb_info, regs->a1, regs->a2, 0, 0,
|
SBI_TLB_INFO_INIT(&tlb_info, regs->a1, regs->a2, 0, 0,
|
||||||
sbi_tlb_local_sfence_vma,
|
SBI_TLB_SFENCE_VMA, source_hart);
|
||||||
source_hart);
|
|
||||||
ret = sbi_tlb_request(hmask, 0, &tlb_info);
|
ret = sbi_tlb_request(hmask, 0, &tlb_info);
|
||||||
|
} else {
|
||||||
|
trap.epc = regs->mepc;
|
||||||
|
sbi_trap_redirect(regs, &trap);
|
||||||
|
out->skip_regs_update = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID:
|
case SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID:
|
||||||
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
|
if (sbi_load_hart_mask_unpriv((ulong *)regs->a0,
|
||||||
&hmask, out_trap);
|
&hmask, &trap)) {
|
||||||
if (ret != SBI_ETRAP) {
|
|
||||||
SBI_TLB_INFO_INIT(&tlb_info, regs->a1,
|
SBI_TLB_INFO_INIT(&tlb_info, regs->a1,
|
||||||
regs->a2, regs->a3, 0,
|
regs->a2, regs->a3, 0,
|
||||||
sbi_tlb_local_sfence_vma_asid,
|
SBI_TLB_SFENCE_VMA_ASID,
|
||||||
source_hart);
|
source_hart);
|
||||||
ret = sbi_tlb_request(hmask, 0, &tlb_info);
|
ret = sbi_tlb_request(hmask, 0, &tlb_info);
|
||||||
|
} else {
|
||||||
|
trap.epc = regs->mepc;
|
||||||
|
sbi_trap_redirect(regs, &trap);
|
||||||
|
out->skip_regs_update = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_0_1_SHUTDOWN:
|
case SBI_EXT_0_1_SHUTDOWN:
|
||||||
@@ -112,13 +123,21 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = SBI_ENOTSUPP;
|
ret = SBI_ENOTSUPP;
|
||||||
};
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct sbi_ecall_extension ecall_legacy;
|
||||||
|
|
||||||
|
static int sbi_ecall_legacy_register_extensions(void)
|
||||||
|
{
|
||||||
|
return sbi_ecall_register_extension(&ecall_legacy);
|
||||||
|
}
|
||||||
|
|
||||||
struct sbi_ecall_extension ecall_legacy = {
|
struct sbi_ecall_extension ecall_legacy = {
|
||||||
.extid_start = SBI_EXT_0_1_SET_TIMER,
|
.extid_start = SBI_EXT_0_1_SET_TIMER,
|
||||||
.extid_end = SBI_EXT_0_1_SHUTDOWN,
|
.extid_end = SBI_EXT_0_1_SHUTDOWN,
|
||||||
.handle = sbi_ecall_legacy_handler,
|
.register_extensions = sbi_ecall_legacy_register_extensions,
|
||||||
|
.handle = sbi_ecall_legacy_handler,
|
||||||
};
|
};
|
||||||
|
@@ -18,9 +18,8 @@
|
|||||||
#include <sbi/riscv_asm.h>
|
#include <sbi/riscv_asm.h>
|
||||||
|
|
||||||
static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid,
|
static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid,
|
||||||
const struct sbi_trap_regs *regs,
|
struct sbi_trap_regs *regs,
|
||||||
unsigned long *out_val,
|
struct sbi_ecall_return *out)
|
||||||
struct sbi_trap_info *out_trap)
|
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
uint64_t temp;
|
uint64_t temp;
|
||||||
@@ -29,12 +28,12 @@ static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid,
|
|||||||
case SBI_EXT_PMU_NUM_COUNTERS:
|
case SBI_EXT_PMU_NUM_COUNTERS:
|
||||||
ret = sbi_pmu_num_ctr();
|
ret = sbi_pmu_num_ctr();
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
*out_val = ret;
|
out->value = ret;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_PMU_COUNTER_GET_INFO:
|
case SBI_EXT_PMU_COUNTER_GET_INFO:
|
||||||
ret = sbi_pmu_ctr_get_info(regs->a0, out_val);
|
ret = sbi_pmu_ctr_get_info(regs->a0, &out->value);
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_PMU_COUNTER_CFG_MATCH:
|
case SBI_EXT_PMU_COUNTER_CFG_MATCH:
|
||||||
#if __riscv_xlen == 32
|
#if __riscv_xlen == 32
|
||||||
@@ -45,13 +44,22 @@ static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid,
|
|||||||
ret = sbi_pmu_ctr_cfg_match(regs->a0, regs->a1, regs->a2,
|
ret = sbi_pmu_ctr_cfg_match(regs->a0, regs->a1, regs->a2,
|
||||||
regs->a3, temp);
|
regs->a3, temp);
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
*out_val = ret;
|
out->value = ret;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_PMU_COUNTER_FW_READ:
|
case SBI_EXT_PMU_COUNTER_FW_READ:
|
||||||
ret = sbi_pmu_ctr_read(regs->a0, out_val);
|
ret = sbi_pmu_ctr_fw_read(regs->a0, &temp);
|
||||||
|
out->value = temp;
|
||||||
|
break;
|
||||||
|
case SBI_EXT_PMU_COUNTER_FW_READ_HI:
|
||||||
|
#if __riscv_xlen == 32
|
||||||
|
ret = sbi_pmu_ctr_fw_read(regs->a0, &temp);
|
||||||
|
out->value = temp >> 32;
|
||||||
|
#else
|
||||||
|
out->value = 0;
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_PMU_COUNTER_START:
|
case SBI_EXT_PMU_COUNTER_START:
|
||||||
|
|
||||||
@@ -65,23 +73,25 @@ static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid,
|
|||||||
case SBI_EXT_PMU_COUNTER_STOP:
|
case SBI_EXT_PMU_COUNTER_STOP:
|
||||||
ret = sbi_pmu_ctr_stop(regs->a0, regs->a1, regs->a2);
|
ret = sbi_pmu_ctr_stop(regs->a0, regs->a1, regs->a2);
|
||||||
break;
|
break;
|
||||||
|
case SBI_EXT_PMU_SNAPSHOT_SET_SHMEM:
|
||||||
|
/* fallthrough as OpenSBI doesn't support snapshot yet */
|
||||||
default:
|
default:
|
||||||
ret = SBI_ENOTSUPP;
|
ret = SBI_ENOTSUPP;
|
||||||
};
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sbi_ecall_pmu_probe(unsigned long extid, unsigned long *out_val)
|
struct sbi_ecall_extension ecall_pmu;
|
||||||
|
|
||||||
|
static int sbi_ecall_pmu_register_extensions(void)
|
||||||
{
|
{
|
||||||
/* PMU extension is always enabled */
|
return sbi_ecall_register_extension(&ecall_pmu);
|
||||||
*out_val = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sbi_ecall_extension ecall_pmu = {
|
struct sbi_ecall_extension ecall_pmu = {
|
||||||
.extid_start = SBI_EXT_PMU,
|
.extid_start = SBI_EXT_PMU,
|
||||||
.extid_end = SBI_EXT_PMU,
|
.extid_end = SBI_EXT_PMU,
|
||||||
.handle = sbi_ecall_pmu_handler,
|
.register_extensions = sbi_ecall_pmu_register_extensions,
|
||||||
.probe = sbi_ecall_pmu_probe,
|
.handle = sbi_ecall_pmu_handler,
|
||||||
};
|
};
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user