mirror of
https://github.com/riscv-software-src/opensbi.git
synced 2025-08-24 15:31:22 +01:00
Compare commits
151 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ac5e821d50 | ||
![]() |
f8b3bb826d | ||
![]() |
393624377a | ||
![]() |
c3b3b8f43b | ||
![]() |
3e7d666d7c | ||
![]() |
66fb729a1e | ||
![]() |
24c3082ea4 | ||
![]() |
bc874e34ce | ||
![]() |
c66543d049 | ||
![]() |
0b414532c4 | ||
![]() |
27a5c7f3c8 | ||
![]() |
f8ce996d90 | ||
![]() |
82fd42fcce | ||
![]() |
a8ef0b5d53 | ||
![]() |
44d1296018 | ||
![]() |
fdfb5332f3 | ||
![]() |
892e87998c | ||
![]() |
48b06ad16e | ||
![]() |
29bb2a6835 | ||
![]() |
c03c8a1e2c | ||
![]() |
a062200b89 | ||
![]() |
c2f23cc6ed | ||
![]() |
c2bfa2bff3 | ||
![]() |
1a8ca08cc0 | ||
![]() |
897b8fbdd9 | ||
![]() |
179eddeb9c | ||
![]() |
d6fa7f95bb | ||
![]() |
9a717ec12e | ||
![]() |
6d0b4c520d | ||
![]() |
5ff1ab0ed8 | ||
![]() |
2c2bbe7374 | ||
![]() |
d79173b4b7 | ||
![]() |
ac1c229b61 | ||
![]() |
85647a1a76 | ||
![]() |
021b9e7c76 | ||
![]() |
43ac621ecb | ||
![]() |
161b348e7e | ||
![]() |
766850222a | ||
![]() |
37923c4a66 | ||
![]() |
0a411bf717 | ||
![]() |
84cd4fc913 | ||
![]() |
817d50d0d4 | ||
![]() |
5f762d14f0 | ||
![]() |
a8b4b83b7f | ||
![]() |
da9b76b957 | ||
![]() |
3d2aaac69a | ||
![]() |
046cc16e8b | ||
![]() |
0492c5d92b | ||
![]() |
30cdf00655 | ||
![]() |
a73d45ccac | ||
![]() |
7daccaeebd | ||
![]() |
6ffe1bed09 | ||
![]() |
f95dd39ab6 | ||
![]() |
adf8b73675 | ||
![]() |
b28b8ac0d2 | ||
![]() |
e340bbf7b5 | ||
![]() |
049ad0b387 | ||
![]() |
a67fd68cbf | ||
![]() |
73c19e69f3 | ||
![]() |
15ed1e7452 | ||
![]() |
b0c9787435 | ||
![]() |
2aa43a13cd | ||
![]() |
1993182f03 | ||
![]() |
b325f6baef | ||
![]() |
6469ed101c | ||
![]() |
55e191e3b0 | ||
![]() |
c3e406f160 | ||
![]() |
e746673a79 | ||
![]() |
c0849cd731 | ||
![]() |
46a90d90e7 | ||
![]() |
fc6bd90457 | ||
![]() |
9beb57362f | ||
![]() |
c7d1b12199 | ||
![]() |
86a31f5437 | ||
![]() |
331ff6a162 | ||
![]() |
9407202532 | ||
![]() |
9777aeef41 | ||
![]() |
109266397a | ||
![]() |
aa0ed1d733 | ||
![]() |
b8732feaf7 | ||
![]() |
7219477f7b | ||
![]() |
2be424bd28 | ||
![]() |
086dbdfc92 | ||
![]() |
4370f18f34 | ||
![]() |
6590a7dab9 | ||
![]() |
bd732ae612 | ||
![]() |
dc40042322 | ||
![]() |
813f7f4c25 | ||
![]() |
ab14f94a8c | ||
![]() |
c96cc03fcc | ||
![]() |
75f903dd78 | ||
![]() |
0e1322bacb | ||
![]() |
b1d8c988bc | ||
![]() |
838657c052 | ||
![]() |
215421ca61 | ||
![]() |
7a13beb213 | ||
![]() |
18897aaf5d | ||
![]() |
f728a0be42 | ||
![]() |
98f4a20899 | ||
![]() |
dd8ef28b27 | ||
![]() |
be92da280d | ||
![]() |
30f09fbfd1 | ||
![]() |
0790be0f2c | ||
![]() |
848ed4f644 | ||
![]() |
26aec6afed | ||
![]() |
3d335bc54b | ||
![]() |
8925e3865c | ||
![]() |
e561c63036 | ||
![]() |
2c7bab76a2 | ||
![]() |
1e9f88889f | ||
![]() |
7d4420bd69 | ||
![]() |
a14e7ee82c | ||
![]() |
bbeb8e619d | ||
![]() |
1a5614e971 | ||
![]() |
0089897d41 | ||
![]() |
1ed9eb255d | ||
![]() |
0a482e2edb | ||
![]() |
190e3f4bd9 | ||
![]() |
8853758268 | ||
![]() |
98ee15ca3a | ||
![]() |
f2e82c3d79 | ||
![]() |
144acef684 | ||
![]() |
9dfe720579 | ||
![]() |
fca8c3be01 | ||
![]() |
6ed2bc154f | ||
![]() |
7b7690ed9c | ||
![]() |
6bd1512024 | ||
![]() |
2e5cc9051b | ||
![]() |
ffa6c5f457 | ||
![]() |
3cbb419def | ||
![]() |
a2a7763ac7 | ||
![]() |
75229705a0 | ||
![]() |
897a97a6af | ||
![]() |
f6e13e0dd3 | ||
![]() |
a88e424f6c | ||
![]() |
2e0f3ac758 | ||
![]() |
6c24193293 | ||
![]() |
5e4021a2f5 | ||
![]() |
6ddf71e6e9 | ||
![]() |
3f738f5897 | ||
![]() |
88c87f0af4 | ||
![]() |
dbff3e9f12 | ||
![]() |
b1318e578b | ||
![]() |
446b6f30a4 | ||
![]() |
c1b9dd3ab5 | ||
![]() |
0f18b3fe0a | ||
![]() |
85546a5477 | ||
![]() |
c90009aa20 | ||
![]() |
bf2ee7bcdc | ||
![]() |
e3f743339a | ||
![]() |
e7456399e4 |
19
Makefile
19
Makefile
@@ -12,10 +12,17 @@
|
||||
# o Do not print "Entering directory ...";
|
||||
MAKEFLAGS += -r --no-print-directory
|
||||
|
||||
# Readlink -f requires GNU readlink
|
||||
ifeq ($(shell uname -s),Darwin)
|
||||
READLINK ?= greadlink
|
||||
else
|
||||
READLINK ?= readlink
|
||||
endif
|
||||
|
||||
# Find out source, build, and install directories
|
||||
src_dir=$(CURDIR)
|
||||
ifdef O
|
||||
build_dir=$(shell readlink -f $(O))
|
||||
build_dir=$(shell $(READLINK) -f $(O))
|
||||
else
|
||||
build_dir=$(CURDIR)/build
|
||||
endif
|
||||
@@ -23,7 +30,7 @@ ifeq ($(build_dir),$(CURDIR))
|
||||
$(error Build directory is same as source directory.)
|
||||
endif
|
||||
ifdef I
|
||||
install_dir=$(shell readlink -f $(I))
|
||||
install_dir=$(shell $(READLINK) -f $(I))
|
||||
else
|
||||
install_dir=$(CURDIR)/install
|
||||
endif
|
||||
@@ -34,7 +41,7 @@ ifeq ($(install_dir),$(build_dir))
|
||||
$(error Install directory is same as build directory.)
|
||||
endif
|
||||
ifdef PLATFORM_DIR
|
||||
platform_dir_path=$(shell readlink -f $(PLATFORM_DIR))
|
||||
platform_dir_path=$(shell $(READLINK) -f $(PLATFORM_DIR))
|
||||
ifdef PLATFORM
|
||||
platform_parent_dir=$(platform_dir_path)
|
||||
else
|
||||
@@ -65,6 +72,7 @@ export firmware_dir=$(CURDIR)/firmware
|
||||
# Find library version
|
||||
OPENSBI_VERSION_MAJOR=`grep "define OPENSBI_VERSION_MAJOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MAJOR.*\([0-9][0-9]*\)/\1/'`
|
||||
OPENSBI_VERSION_MINOR=`grep "define OPENSBI_VERSION_MINOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MINOR.*\([0-9][0-9]*\)/\1/'`
|
||||
OPENSBI_VERSION_GIT=$(shell if [ -d $(src_dir)/.git ]; then git describe 2> /dev/null; fi)
|
||||
|
||||
# Setup compilation commands
|
||||
ifdef CROSS_COMPILE
|
||||
@@ -151,11 +159,14 @@ endif
|
||||
# Setup compilation commands flags
|
||||
GENFLAGS = -I$(platform_src_dir)/include
|
||||
GENFLAGS += -I$(include_dir)
|
||||
ifneq ($(OPENSBI_VERSION_GIT),)
|
||||
GENFLAGS += -DOPENSBI_VERSION_GIT="\"$(OPENSBI_VERSION_GIT)\""
|
||||
endif
|
||||
GENFLAGS += $(libsbiutils-genflags-y)
|
||||
GENFLAGS += $(platform-genflags-y)
|
||||
GENFLAGS += $(firmware-genflags-y)
|
||||
|
||||
CFLAGS = -g -Wall -Werror -nostdlib -fno-strict-aliasing -O2
|
||||
CFLAGS = -g -Wall -Werror -ffreestanding -nostdlib -fno-strict-aliasing -O2
|
||||
CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
|
||||
CFLAGS += -mno-save-restore -mstrict-align
|
||||
CFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
|
||||
|
27
README.md
27
README.md
@@ -47,7 +47,7 @@ cross-compilation, you can build your own toolchain or just download
|
||||
a prebuilt one from the
|
||||
[Bootlin toolchain repository] (https://toolchains.bootlin.com/).
|
||||
|
||||
Please note that only a 64bit version of the toolchain is available in
|
||||
Please note that only a 64-bit version of the toolchain is available in
|
||||
the Bootlin toolchain repository for now.
|
||||
|
||||
Building and Installing the OpenSBI Platform-Independent Library
|
||||
@@ -131,6 +131,25 @@ top-level make command line. These options, such as *PLATFORM_<xyz>* or
|
||||
*docs/platform/<platform_name>.md* files and
|
||||
*docs/firmware/<firmware_name>.md* files.
|
||||
|
||||
Building 32-bit / 64-bit OpenSBI Images
|
||||
---------------------------------------
|
||||
By default, building OpenSBI generates 32-bit or 64-bit images based on the
|
||||
supplied RISC-V cross-compile toolchain. For example if *CROSS_COMPILE* is set
|
||||
to *riscv64-unknown-elf-*, 64-bit OpenSBI images will be generated. If building
|
||||
32-bit OpenSBI images, *CROSS_COMPILE* should be set to a toolchain that is
|
||||
pre-configured to generate 32-bit RISC-V codes, like *riscv32-unknown-elf-*.
|
||||
|
||||
However it's possible to explicitly specify the image bits we want to build with
|
||||
a given RISC-V toolchain. This can be done by setting the environment variable
|
||||
*PLATFORM_RISCV_XLEN* to the desired width, for example:
|
||||
|
||||
```
|
||||
export CROSS_COMPILE=riscv64-unknown-elf-
|
||||
export PLATFORM_RISCV_XLEN=32
|
||||
```
|
||||
|
||||
will generate 32-bit OpenSBI images. And vice vesa.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
@@ -153,14 +172,10 @@ OpenSBI source code also contains code reused from other projects as listed
|
||||
below. The original license text of these projects is included in the source
|
||||
files where the reused code is present.
|
||||
|
||||
1. The libfdt source code is disjunctively dual licensed
|
||||
* The libfdt source code is disjunctively dual licensed
|
||||
(GPL-2.0+ OR BSD-2-Clause). Some of this project code is used in OpenSBI
|
||||
under the terms of the BSD 2-Clause license. Any contributions to this
|
||||
code must be made under the terms of both licenses.
|
||||
2. Some source file for the Kendryte/k210 platform code are based on code from
|
||||
the [Kendryte standalone SDK] available on github. These files retain the
|
||||
original copyright and license of the Kendryte standalone SDK project and
|
||||
are licensed under the terms of the Apache License, Version 2.0.
|
||||
|
||||
See also the [third party notices] file for more information.
|
||||
|
||||
|
@@ -16,192 +16,3 @@ The libfdt source code is disjunctively dual licensed (GPL-2.0+ or
|
||||
BSD-2-Clause). Some of this project code is used in OpenSBI under the terms of
|
||||
the BSD 2-Clause license. The full text of this license can be found in the
|
||||
file [COPYING.BSD](COPYING.BSD).
|
||||
|
||||
Kendryte Standalone SDK
|
||||
-----------------------
|
||||
|
||||
Copyright 2018 Canaan Inc.
|
||||
|
||||
The Kendryte K210 platform code reuses some code from Kendryte standalone SDK
|
||||
licensed under the terms of the Apache License, Version 2.0. The full text of
|
||||
this license is available at http://www.apache.org/licenses/LICENSE-2.0 and
|
||||
included below.
|
||||
|
||||
```
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
```
|
||||
|
14
docs/external/coreboot.md
vendored
14
docs/external/coreboot.md
vendored
@@ -1,7 +1,10 @@
|
||||
OpenSBI as coreboot payload
|
||||
==============================
|
||||
===========================
|
||||
|
||||
[coreboot](https://www.coreboot.org/) is a free/libre and open source firmware platform support multiple hardware architectures( x86, ARMv7, arm64, PowerPC64, MIPS and RISC-V) and diverse hardware models. In RISC-V world, coreboot currently support HiFive Unleashed with OpenSBI as a payload to boot GNU/Linux:
|
||||
[coreboot] is a free/libre and open source firmware platform support multiple
|
||||
hardware architectures(x86, ARMv7, arm64, PowerPC64, MIPS and RISC-V) and
|
||||
diverse hardware models. In RISC-V world, coreboot currently support HiFive
|
||||
Unleashed with OpenSBI as a payload to boot GNU/Linux:
|
||||
|
||||
```
|
||||
SiFive HiFive unleashed's original firmware boot process:
|
||||
@@ -21,4 +24,9 @@ coreboot boot process:
|
||||
+---------------------------------------------+-------------+-------+-+
|
||||
```
|
||||
|
||||
The upstreaming work is still in progress. There's a [documentation](https://github.com/hardenedlinux/embedded-iot_profile/blob/master/docs/riscv/hifiveunleashed_coreboot_notes-en.md) about how to build [out-of-tree code](https://github.com/hardenedlinux/coreboot-HiFiveUnleashed) to load OpenSBI.
|
||||
The upstreaming work is still in progress. There's a [documentation] about how
|
||||
to build [out-of-tree code] to load OpenSBI.
|
||||
|
||||
[coreboot]: https://www.coreboot.org/
|
||||
[documentation]: https://github.com/hardenedlinux/embedded-iot_profile/blob/master/docs/riscv/hifiveunleashed_coreboot_notes-en.md
|
||||
[out-of-tree code]: https://github.com/hardenedlinux/coreboot-HiFiveUnleashed
|
||||
|
@@ -38,15 +38,14 @@ follows:
|
||||
* **FW_JUMP_FDT_ADDR** - Address where the *flattened device tree (FDT file)*
|
||||
passed by the prior booting stage will be placed in memory before executing
|
||||
the booting stage following the OpenSBI firmware. If this option is not
|
||||
provided, then the OpenSBI firmware will pass zero as the FDT address to the
|
||||
following booting stage.
|
||||
provided, then the OpenSBI firmware will pass the FDT address passed by the
|
||||
previous booting stage to the next booting stage.
|
||||
|
||||
*FW_JUMP* Example
|
||||
-----------------
|
||||
|
||||
The *[qemu/virt]* and *[qemu/sifive_u]* platforms illustrate how to configure
|
||||
and use a *FW_JUMP* firmware. Detailed information regarding these platforms
|
||||
can be found in the platform documentation files.
|
||||
The *[qemu/virt]* platform illustrates how to configure and use a *FW_JUMP*
|
||||
firmware. Detailed information regarding these platforms can be found in the
|
||||
platform documentation files.
|
||||
|
||||
[qemu/virt]: ../platform/qemu_virt.md
|
||||
[qemu/sifive_u]: ../platform/qemu_sifive_u.md
|
||||
|
@@ -73,17 +73,17 @@ file. The parameters currently defined are as follows:
|
||||
stage or specified by the *FW_PAYLOAD_FDT_PATH* parameter and embedded in
|
||||
the *.text* section will be placed before executing the next booting stage,
|
||||
that is, the payload firmware. If this option is not provided, then the
|
||||
firmware will pass zero as the FDT address to the next booting stage.
|
||||
firmware will pass the FDT address passed by the previous booting stage
|
||||
to the next booting stage.
|
||||
|
||||
*FW_PAYLOAD* Example
|
||||
--------------------
|
||||
|
||||
The *[qemu/virt]* and *[qemu/sifive_u]* platforms illustrate how to configure
|
||||
and use a *FW_PAYLOAD* firmware. Detailed information regarding these platforms
|
||||
can be found in the platform documentation files.
|
||||
The *[qemu/virt]* platforms illustrate how to configure and use a *FW_PAYLOAD*
|
||||
firmware. Detailed information regarding these platforms can be found in the
|
||||
platform documentation files.
|
||||
|
||||
The *kendryte/k210* platform also enables a build of a *FW_PAYLOAD* using an
|
||||
internally defined device tree file (*FW_PAYLOAD_FDT*).
|
||||
|
||||
[qemu/virt]: ../platform/qemu_virt.md
|
||||
[qemu/sifive_u]: ../platform/qemu_sifive_u.md
|
||||
|
@@ -7,4 +7,3 @@ provided as a payload to OpenSBI.
|
||||
|
||||
Detailed examples can be found in both the [QEMU](../platform/qemu_virt.md)
|
||||
and the [HiFive Unleashed](../platform/sifive_fu540.md) platform guides.
|
||||
|
||||
|
@@ -66,3 +66,24 @@ bootloader to service the following interrupts and traps:
|
||||
|
||||
**Note:** external firmwares or bootloaders can be more conservative by
|
||||
forwarding all traps and interrupts to *sbi_trap_handler()*.
|
||||
|
||||
Definitions of OpenSBI Data Types for the External Firmware
|
||||
-----------------------------------------------------------
|
||||
|
||||
OpenSBI can be built as library using external firmware build system such as EDK2
|
||||
code base (The open source of UEFI firmware implementation) and linked with external
|
||||
firmware drivers based on the external firmware architecture.
|
||||
|
||||
**OPENSBI_EXTERNAL_SBI_TYPES** identifier is introduced to *sbi_types.h* for selecting
|
||||
external header file during the build preprocess in order to define OpensSBI data types
|
||||
based on external firmware data type binding.
|
||||
For example, *bool* is declared as *int* in sbi_types.h. However in EDK2 build system,
|
||||
*bool* is declared as *BOOLEAN* which is defined as *unsigned char* data type.
|
||||
|
||||
External firmware can define **OPENSBI_EXTERNAL_SBI_TYPES** in CFLAGS and specify it to the
|
||||
header file maintained in its code tree. However, the external build system has to address
|
||||
the additional include directory for the external header file based on its own build system.
|
||||
For example,
|
||||
*-D***OPENSBI_EXTERNAL_SBI_TYPES***=OpensbiTypes.h*
|
||||
Above tells *sbi_types.h* to refer to *OpensbiTypes.h* instead of using original definitions of
|
||||
data types.
|
||||
|
30
docs/platform/andes-ae350.md
Normal file
30
docs/platform/andes-ae350.md
Normal file
@@ -0,0 +1,30 @@
|
||||
Andes AE350 SoC Platform
|
||||
========================
|
||||
The AE350 AXI/AHB-based platform N25(F)/NX25(F)/D25F/A25/AX25 CPU with level-one
|
||||
memories,interrupt controller, debug module, AXI and AHB Bus Matrix Controller,
|
||||
AXI-to-AHB Bridge and a collection of fundamentalAHB/APB bus IP components
|
||||
pre-integrated together as a system design.The high-quality and configurable
|
||||
AHB/APB IPs suites a majority embedded systems, and the verified platform serves
|
||||
as a starting point to jump start SoC designs.
|
||||
|
||||
To build platform specific library and firmwares, provide the
|
||||
*PLATFORM=andes/ae350* parameter to the top level make command.
|
||||
|
||||
Platform Options
|
||||
----------------
|
||||
|
||||
The Andes AE350 platform does not have any platform-specific options.
|
||||
|
||||
Building Andes AE350 Platform
|
||||
-----------------------------
|
||||
|
||||
To use Linux v5.2 should be used to build Andes AE350 OpenSBI binaries by using
|
||||
the compile time option FW_PAYLOAD_FDT_PATH.
|
||||
|
||||
AE350's dts is included in https://github.com/andestech/linux/tree/ast-v3_2_0-release-public
|
||||
|
||||
**Linux Kernel Payload**
|
||||
|
||||
```
|
||||
make PLATFORM=andes/ae350 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_PAYLOAD_FDT_PATH=<ae350.dtb path>
|
||||
```
|
@@ -1,8 +1,10 @@
|
||||
Ariane FPGA SoC Platform
|
||||
==========================
|
||||
Ariane is a 6-stage, single issue, in-order CPU which implements the 64-bit RISC-V instruction set.
|
||||
The Ariane FPGA development platform is based on FPGA FPGA SoC(which currently supports only Genesys 2 board) and is capable
|
||||
of running Linux.
|
||||
========================
|
||||
Ariane is a 6-stage, single issue, in-order CPU which implements the 64-bit
|
||||
RISC-V instruction set. The Ariane FPGA development platform is based on FPGA
|
||||
SoC (which currently supports only Genesys 2 board) and is capable of running
|
||||
Linux.
|
||||
|
||||
The FPGA SoC currently contains the following peripherals:
|
||||
- DDR3 memory controller
|
||||
- SPI controller to conncet to an SDCard
|
||||
@@ -16,22 +18,21 @@ To build platform specific library and firmwares, provide the
|
||||
Platform Options
|
||||
----------------
|
||||
|
||||
The *Ariane FPGA* platform does not have any platform-specific
|
||||
options.
|
||||
The *Ariane FPGA* platform does not have any platform-specific options.
|
||||
|
||||
Building Ariane FPGA Platform
|
||||
-----------------------------
|
||||
**Linux Kernel Payload**
|
||||
|
||||
**Linux Kernel Payload**
|
||||
|
||||
```
|
||||
make PLATFORM=ariane-fpga FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
||||
```
|
||||
|
||||
Booting Ariane FPGA Platform
|
||||
-----------------------------
|
||||
----------------------------
|
||||
|
||||
**Linux Kernel Payload**
|
||||
|
||||
As Linux kernel image is embedded in the OpenSBI firmware binary, Ariane will directly
|
||||
boot into Linux directly after powered on.
|
||||
As Linux kernel image is embedded in the OpenSBI firmware binary, Ariane will
|
||||
directly boot into Linux directly after powered on.
|
||||
|
@@ -8,14 +8,9 @@ OpenSBI currently supports the following virtual and hardware platforms:
|
||||
development and tests. More details on this platform can be found in the
|
||||
file *[qemu_virt.md]*.
|
||||
|
||||
* **QEMU SiFive Unleashed Machine**: Platform support for the *sifive_u* QEMU
|
||||
virtual RISC-V machine. This is an emulation machine of the HiFive Unleashed
|
||||
board by SiFive. More details on this platform can be found in the file
|
||||
*[qemu_sifive_u.md]*.
|
||||
|
||||
* **SiFive FU540 SoC**: Platform support for SiFive FU540 SoC used on the
|
||||
HiFive Unleashed board. This platform is very similar to the *QEMU sifive_u*
|
||||
platform. More details on this platform can be found in the file
|
||||
HiFive Unleashed board, as well as the *sifive_u* QEMU virtual RISC-V
|
||||
machine. More details on this platform can be found in the file
|
||||
*[sifive_fu540.md]*.
|
||||
|
||||
* **Kendryte K210 SoC**: Platform support for the Kendryte K210 SoC used on
|
||||
@@ -24,6 +19,12 @@ OpenSBI currently supports the following virtual and hardware platforms:
|
||||
* **Ariane FPGA SoC**: Platform support for the Ariane FPGA SoC used on
|
||||
Genesys 2 board.
|
||||
|
||||
* **Andes AE350 SoC**: Platform support for the Andes's SoC (AE350).
|
||||
|
||||
* **T-HEAD C910**: Platform support for the T-HEAD C910 Processor.
|
||||
|
||||
* **Spike**: Platform support for the Spike emulator.
|
||||
|
||||
The code for these supported platforms can be used as example to implement
|
||||
support for other platforms. The *platform/template* directory also provides
|
||||
template files for implementing support for a new platform. The *object.mk*,
|
||||
@@ -31,6 +32,8 @@ template files for implementing support for a new platform. The *object.mk*,
|
||||
facilitate the implementation.
|
||||
|
||||
[qemu_virt.md]: qemu_virt.md
|
||||
[qemu_sifive_u.md]: qemu_sifive_u.md
|
||||
[sifive_fu540.md]: sifive_fu540.md
|
||||
[ariane-fpga.md]: ariane-fpga.md
|
||||
[andes_ae350.md]: andes-ae350.md
|
||||
[thead-c910.md]: thead-c910.md
|
||||
[spike.md]: spike.md
|
||||
|
@@ -1,52 +0,0 @@
|
||||
QEMU SiFive Unleashed Machine Platform
|
||||
======================================
|
||||
|
||||
The **QEMU SiFive Unleashed Machine** is an emulation of the SiFive Unleashed
|
||||
platform.
|
||||
|
||||
To build this platform specific library and firmwares, provide the
|
||||
*PLATFORM=qemu/sifive_u* parameter to the top level `make` command line.
|
||||
|
||||
Platform Options
|
||||
----------------
|
||||
|
||||
The *QEMU SiFive Unleashed Machine* platform does not have any platform specific
|
||||
options.
|
||||
|
||||
Executing on QEMU RISC-V 64bit
|
||||
------------------------------
|
||||
|
||||
**No Payload Case**
|
||||
|
||||
Build:
|
||||
```
|
||||
make PLATFORM=qemu/sifive_u
|
||||
```
|
||||
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv64 -M sifive_u -m 256M -display none -serial stdio \
|
||||
-kernel build/platform/qemu/sifive_u/firmware/fw_payload.elf
|
||||
```
|
||||
|
||||
**U-Boot as a Payload**
|
||||
|
||||
Note: the command line examples here assume that U-Boot was compiled using
|
||||
the `sifive_fu540_defconfig` configuration.
|
||||
|
||||
Build:
|
||||
```
|
||||
make PLATFORM=qemu/sifive_u FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
|
||||
```
|
||||
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv64 -M sifive_u -m 256M -display none -serial stdio \
|
||||
-kernel build/platform/qemu/sifive_u/firmware/fw_payload.elf
|
||||
```
|
||||
or
|
||||
```
|
||||
qemu-system-riscv64 -M sifive_u -m 256M -display none -serial stdio \
|
||||
-kernel build/platform/qemu/sifive_u/firmware/fw_jump.elf \
|
||||
-device loader,file=<uboot_build_directory>/u-boot.bin,addr=0x80200000
|
||||
```
|
@@ -15,8 +15,8 @@ Platform Options
|
||||
The *QEMU RISC-V Virt Machine* platform does not have any platform-specific
|
||||
options.
|
||||
|
||||
Execution on QEMU RISC-V 64bit
|
||||
------------------------------
|
||||
Execution on QEMU RISC-V 64-bit
|
||||
-------------------------------
|
||||
|
||||
**No Payload Case**
|
||||
|
||||
@@ -82,8 +82,8 @@ qemu-system-riscv64 -M virt -m 256M -nographic \
|
||||
```
|
||||
|
||||
|
||||
Execution on QEMU RISC-V 32bit
|
||||
------------------------------
|
||||
Execution on QEMU RISC-V 32-bit
|
||||
-------------------------------
|
||||
|
||||
**No Payload Case**
|
||||
|
||||
@@ -149,4 +149,3 @@ qemu-system-riscv32 -M virt -m 256M -nographic \
|
||||
-device virtio-blk-device,drive=hd0 \
|
||||
-append "root=/dev/vda rw console=ttyS0"
|
||||
```
|
||||
|
||||
|
@@ -1,9 +1,12 @@
|
||||
SiFive FU540 SoC Platform
|
||||
==========================
|
||||
=========================
|
||||
The FU540-C000 is the world’s first 4+1 64-bit RISC-V SoC from SiFive.
|
||||
The HiFive Unleashed development platform is based on FU540-C000 and capable
|
||||
of running Linux.
|
||||
|
||||
With QEMU v4.2 or above release, the 'sifive_u' machine can be used to test
|
||||
OpenSBI image built for the real hardware as well.
|
||||
|
||||
To build platform specific library and firmwares, provide the
|
||||
*PLATFORM=sifive/fu540* parameter to the top level `make` command.
|
||||
|
||||
@@ -22,10 +25,10 @@ make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=Image FU540_ENABLED_HART_MASK=0x02
|
||||
This will let the board boot only hart1 instead of default 1-4.
|
||||
|
||||
Building SiFive Fu540 Platform
|
||||
-----------------------------
|
||||
------------------------------
|
||||
|
||||
In order to boot SMP Linux in U-Boot, Linux v5.1 (or higher) and latest
|
||||
U-Boot v2019.04 (or higher) should be used.
|
||||
U-Boot v2020.01 (or higher) should be used.
|
||||
|
||||
**Linux Kernel Payload**
|
||||
|
||||
@@ -46,25 +49,12 @@ make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/bo
|
||||
**U-Boot Payload**
|
||||
|
||||
The command-line example here assumes that U-Boot was compiled using the
|
||||
sifive_fu540_defconfig configuration and with U-Boot v2019.04 (or higher)
|
||||
having SMP support.
|
||||
sifive_fu540_defconfig configuration and with U-Boot v2020.01 (or higher).
|
||||
|
||||
To use U-Boot which follows Linux v5.2 (or higher) DT bindings, we will
|
||||
need custom U-Boot with required driver changes which can be found in
|
||||
riscv_unleashed_mmc_spi_v2 branch of https://github.com/avpatel/u-boot.git
|
||||
The detailed U-Boot booting guide is avaialble at [U-Boot].
|
||||
|
||||
```
|
||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin
|
||||
or
|
||||
(For U-Boot which follows Linux v5.2 (or higher) DT bindings)
|
||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin FW_PAYLOAD_FDT_PATH=<hifive-unleashed-a00.dtb path from Linux kernel>
|
||||
```
|
||||
|
||||
Generate the uImage from Linux Image.
|
||||
```
|
||||
mkimage -A riscv -O linux -T kernel -C none -a 0x80200000 -e 0x80200000 -n Linux -d \
|
||||
<linux_build_directory>/arch/riscv/boot/Image \
|
||||
<linux_build_directory>/arch/riscv/boot/uImage
|
||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot-dtb.bin
|
||||
```
|
||||
|
||||
**U-Boot & Linux Kernel as a single payload**
|
||||
@@ -72,37 +62,29 @@ mkimage -A riscv -O linux -T kernel -C none -a 0x80200000 -e 0x80200000 -n Linux
|
||||
A single monolithic image containing both U-Boot & Linux can also be used if
|
||||
network boot setup is not available.
|
||||
|
||||
1. Generate the uImage from Linux Image.
|
||||
```
|
||||
mkimage -A riscv -O linux -T kernel -C none -a 0x80200000 -e 0x80200000 -n Linux -d \
|
||||
<linux_build_directory>/arch/riscv/boot/Image \
|
||||
<linux_build_directory>/arch/riscv/boot/uImage
|
||||
```
|
||||
|
||||
2. Create a temporary image with u-boot.bin as the first payload. The
|
||||
1. Create a temporary image with u-boot-dtb.bin as the first payload. The
|
||||
command-line example here assumes that U-Boot was compiled using
|
||||
sifive_fu540_defconfig configuration.
|
||||
```
|
||||
dd if=~/workspace/u-boot-riscv/u-boot.bin of=/tmp/temp.bin bs=1M
|
||||
dd if=~/workspace/u-boot-riscv/u-boot-dtb.bin of=/tmp/temp.bin bs=1M
|
||||
```
|
||||
3. Append the Linux Kernel image generated in step 1.
|
||||
2. Append the Linux Kernel image.
|
||||
```
|
||||
dd if=<linux_build_directory>/arch/riscv/boot/uImage of=/tmp/temp.bin bs=1M seek=4
|
||||
dd if=<linux_build_directory>/arch/riscv/boot/Image of=/tmp/temp.bin bs=1M seek=4
|
||||
```
|
||||
4. Compile OpenSBI with temp.bin (generated in step 3) as payload.
|
||||
3. Compile OpenSBI with temp.bin (generated in step 2) as payload.
|
||||
```
|
||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=/tmp/temp.bin
|
||||
or
|
||||
(For U-Boot which follows Linux v5.2 (or higher) DT bindings)
|
||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=/tmp/temp.bin FW_PAYLOAD_FDT_PATH=<hifive-unleashed-a00.dtb path from Linux kernel>
|
||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=/tmp/temp.bin
|
||||
```
|
||||
|
||||
Flashing the OpenSBI firmware binary to storage media:
|
||||
-----------------------------------------------------
|
||||
The first stage boot loader([FSBL](https://github.com/sifive/freedom-u540-c000-bootloader))
|
||||
expects the storage media to have a GPT partition table. It tries to look for
|
||||
a partition with following GUID to load the next stage boot loader (OpenSBI
|
||||
in this case).
|
||||
------------------------------------------------------
|
||||
The first stage boot loader ([FSBL]) expects the storage media to have a GPT
|
||||
partition table. It tries to look for a partition with following GUID to load
|
||||
the next stage boot loader (OpenSBI in this case).
|
||||
|
||||
```
|
||||
2E54B353-1271-4842-806F-E436D6AF6985
|
||||
@@ -142,39 +124,32 @@ As U-Boot image is used as payload, HiFive Unleashed will boot into a U-Boot
|
||||
prompt. U-Boot tftp boot method can be used to load kernel image in U-Boot
|
||||
prompt. Here are the steps do a tftpboot.
|
||||
|
||||
1. Set the mac address of the board.
|
||||
```
|
||||
setenv ethaddr <mac address of the board>
|
||||
```
|
||||
(Note: This step is optional)
|
||||
|
||||
2. Set the ip address of the board.
|
||||
1. Set the ip address of the board.
|
||||
```
|
||||
setenv ipaddr <ipaddr of the board>
|
||||
```
|
||||
|
||||
3. Set the tftpboot server IP.
|
||||
2. Set the tftpboot server IP.
|
||||
```
|
||||
setenv serverip <ipaddr of the tftp server>
|
||||
```
|
||||
|
||||
4. Set the network gateway address.
|
||||
3. Set the network gateway address.
|
||||
```
|
||||
setenv gatewayip <ipaddress of the network gateway>
|
||||
```
|
||||
|
||||
5. Load the Linux kernel image from the tftp server.
|
||||
4. Load the Linux kernel image from the tftp server.
|
||||
```
|
||||
tftpboot ${kernel_addr_r} <uImage path in tftpboot directory>
|
||||
tftpboot ${kernel_addr_r} <Image path in tftpboot directory>
|
||||
```
|
||||
|
||||
6. Load the ramdisk image from the tftp server. This is only required if
|
||||
5. Load the ramdisk image from the tftp server. This is only required if
|
||||
ramdisk is loaded from tftp server. This step is optional, if rootfs is
|
||||
already part of the kernel or loaded from an external storage by kernel.
|
||||
```
|
||||
tftpboot ${ramdisk_addr_r} <ramdisk path in tftpboot directory>
|
||||
```
|
||||
|
||||
6. Load the pre-compiled device tree via tftpboot.
|
||||
```
|
||||
tftpboot ${fdt_addr_r} <hifive-unleashed-a00.dtb path in tftpboot directory>
|
||||
```
|
||||
7. Set the boot command-line arguments.
|
||||
```
|
||||
setenv bootargs "root=<root partition> rw console=ttySIF0 earlycon=sbi"
|
||||
@@ -183,13 +158,12 @@ setenv bootargs "root=<root partition> rw console=ttySIF0 earlycon=sbi"
|
||||
** /dev/ram ** - If a ramdisk is used
|
||||
** root=/dev/mmcblk0pX ** - If a rootfs is already on some other partition
|
||||
of sdcard)
|
||||
|
||||
8. Now boot into Linux.
|
||||
```
|
||||
bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdtcontroladdr}
|
||||
booti ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}
|
||||
or
|
||||
(If ramdisk is not loaded from network)
|
||||
bootm ${kernel_addr_r} - ${fdtcontroladdr}
|
||||
booti ${kernel_addr_r} - ${fdt_addr_r}
|
||||
```
|
||||
|
||||
**U-Boot & Linux Kernel as a single payload**
|
||||
@@ -197,5 +171,31 @@ bootm ${kernel_addr_r} - ${fdtcontroladdr}
|
||||
At U-Boot prompt execute the following boot command to boot Linux.
|
||||
|
||||
```
|
||||
bootm ${kernel_addr_r} - ${fdtcontroladdr}
|
||||
booti ${kernel_addr_r} - ${fdt_addr_r}
|
||||
```
|
||||
|
||||
QEMU Specific Instructions
|
||||
--------------------------
|
||||
If you want to test OpenSBI with QEMU 'sifive_u' machine, please follow the
|
||||
same instructions above, with the exception of not passing FW_PAYLOAD_FDT_PATH.
|
||||
|
||||
This is because QEMU generates a device tree blob on the fly based on the
|
||||
command line parameters and it's compatible with the one used in the upstream
|
||||
Linux kernel.
|
||||
|
||||
When U-Boot v2020.01 (or higher) is used as the payload, as the SiFive FU540
|
||||
DTB for the real hardware is embedded in U-Boot binary itself, due to the same
|
||||
reason above, we need to switch the U-Boot sifive_fu540_defconfig configuration
|
||||
from CONFIG_OF_SEPARATE to CONFIG_OF_PRIOR_STAGE so that U-Boot uses the DTB
|
||||
generated by QEMU, and u-boot.bin should be used as the payload image, like:
|
||||
|
||||
```
|
||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin
|
||||
```
|
||||
|
||||
While the real hardware operates at the 64-bit mode, it's possible for QEMU to
|
||||
test the 32-bit OpenSBI firmware. This can be helpful for testing 32-bit SiFive
|
||||
specific drivers.
|
||||
|
||||
[U-Boot]: https://gitlab.denx.de/u-boot/u-boot/blob/master/doc/board/sifive/fu540.rst
|
||||
[FSBL]: https://github.com/sifive/freedom-u540-c000-bootloader
|
||||
|
89
docs/platform/spike.md
Normal file
89
docs/platform/spike.md
Normal file
@@ -0,0 +1,89 @@
|
||||
Spike Simulator Platform
|
||||
========================
|
||||
|
||||
The **Spike** is a RISC-V ISA simulator which implements a functional model
|
||||
of one or more RISC-V harts. The **Spike** compatible virtual platform is
|
||||
also available on QEMU. In fact, we can use same OpenSBI firmware binaries
|
||||
on **Spike** simulator and QEMU Spike machine.
|
||||
|
||||
For more details, refer [Spike on GitHub](https://github.com/riscv/riscv-isa-sim)
|
||||
|
||||
To build the platform-specific library and firmware images, provide the
|
||||
*PLATFORM=spike* parameter to the top level `make` command.
|
||||
|
||||
Platform Options
|
||||
----------------
|
||||
|
||||
The *Spike* platform does not have any platform-specific options.
|
||||
|
||||
Execution on Spike Simulator
|
||||
----------------------------
|
||||
|
||||
**No Payload Case**
|
||||
|
||||
Build:
|
||||
```
|
||||
make PLATFORM=spike
|
||||
```
|
||||
|
||||
Run:
|
||||
```
|
||||
spike build/platform/spike/firmware/fw_payload.elf
|
||||
```
|
||||
|
||||
**Linux Kernel Payload**
|
||||
|
||||
Note: We assume that the Linux kernel is compiled using
|
||||
*arch/riscv/configs/defconfig*.
|
||||
|
||||
Build:
|
||||
```
|
||||
make PLATFORM=spike FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
||||
```
|
||||
|
||||
Run:
|
||||
```
|
||||
spike --initrd <path_to_cpio_ramdisk> build/platform/spike/firmware/fw_payload.elf
|
||||
```
|
||||
|
||||
Execution on QEMU RISC-V 64-bit
|
||||
-------------------------------
|
||||
|
||||
**No Payload Case**
|
||||
|
||||
Build:
|
||||
```
|
||||
make PLATFORM=spike
|
||||
```
|
||||
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv64 -M spike -m 256M -nographic \
|
||||
-kernel build/platform/spike/firmware/fw_payload.elf
|
||||
```
|
||||
|
||||
**Linux Kernel Payload**
|
||||
|
||||
Note: We assume that the Linux kernel is compiled using
|
||||
*arch/riscv/configs/defconfig*.
|
||||
|
||||
Build:
|
||||
```
|
||||
make PLATFORM=spike FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
||||
```
|
||||
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv64 -M spike -m 256M -nographic \
|
||||
-kernel build/platform/spike/firmware/fw_payload.elf \
|
||||
-initrd <path_to_cpio_ramdisk> \
|
||||
-append "root=/dev/ram rw console=hvc0 earlycon=sbi"
|
||||
```
|
||||
or
|
||||
```
|
||||
qemu-system-riscv64 -M spike -m 256M -nographic \
|
||||
-bios build/platform/spike/firmware/fw_jump.elf \
|
||||
-kernel <linux_build_directory>/arch/riscv/boot/Image \
|
||||
-initrd <path_to_cpio_ramdisk> \
|
||||
-append "root=/dev/ram rw console=hvc0 earlycon=sbi"
|
||||
```
|
34
docs/platform/thead-c910.md
Normal file
34
docs/platform/thead-c910.md
Normal file
@@ -0,0 +1,34 @@
|
||||
T-HEAD C910 Processor
|
||||
=====================
|
||||
C910 is a 12-stage, 3 issues, 8 executions, out-of-order 64-bit RISC-V CPU which
|
||||
supports 16 cores, runs with 2.5GHz, and is capable of running Linux.
|
||||
|
||||
To build platform specific library and firmwares, provide the
|
||||
*PLATFORM=thead/c910* parameter to the top level make command.
|
||||
|
||||
Platform Options
|
||||
----------------
|
||||
|
||||
The *T-HEAD C910* platform does not have any platform-specific options.
|
||||
|
||||
Building T-HEAD C910 Platform
|
||||
-----------------------------
|
||||
|
||||
```
|
||||
make PLATFORM=thead/c910
|
||||
```
|
||||
|
||||
Booting T-HEAD C910 Platform
|
||||
----------------------------
|
||||
|
||||
**No Payload**
|
||||
|
||||
As there's no payload, you may download vmlinux or u-boot to FW_JUMP_ADDR which
|
||||
specified in config.mk or compile commands with GDB. And the execution flow will
|
||||
turn to vmlinux or u-boot when opensbi ends.
|
||||
|
||||
**Linux Kernel Payload**
|
||||
|
||||
You can also choose to use Linux kernel as payload by enabling FW_PAYLOAD=y
|
||||
along with specifying FW_PAYLOAD_OFFSET. The kernel image will be embedded in
|
||||
the OPENSBI firmware binary, T-head will directly boot into Linux after OpenSBI.
|
@@ -13,6 +13,9 @@
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
|
||||
#define BOOT_STATUS_RELOCATE_DONE 1
|
||||
#define BOOT_STATUS_BOOT_HART_DONE 2
|
||||
|
||||
.macro MOV_3R __d0, __s0, __d1, __s1, __d2, __s2
|
||||
add \__d0, \__s0, zero
|
||||
add \__d1, \__s1, zero
|
||||
@@ -38,17 +41,26 @@
|
||||
999:
|
||||
.endm
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _start
|
||||
.globl _start_warm
|
||||
_start:
|
||||
/*
|
||||
* Jump to warm-boot if this is not the first core booting,
|
||||
* that is, for mhartid != 0
|
||||
*/
|
||||
csrr a6, CSR_MHARTID
|
||||
blt zero, a6, _wait_relocate_copy_done
|
||||
/* Find preferred boot HART id */
|
||||
MOV_3R s0, a0, s1, a1, s2, a2
|
||||
call fw_boot_hart
|
||||
add a6, a0, zero
|
||||
MOV_3R a0, s0, a1, s1, a2, s2
|
||||
li a7, -1
|
||||
beq a6, a7, _try_lottery
|
||||
/* Jump to relocation wait loop if we are not boot hart */
|
||||
bne a0, a6, _wait_relocate_copy_done
|
||||
_try_lottery:
|
||||
/* Jump to relocation wait loop if we don't get relocation lottery */
|
||||
la a6, _relocate_lottery
|
||||
li a7, 1
|
||||
amoadd.w a6, a7, (a6)
|
||||
bnez a6, _wait_relocate_copy_done
|
||||
|
||||
/* Save load address */
|
||||
la t0, _load_start
|
||||
@@ -72,6 +84,8 @@ _relocate:
|
||||
blt t2, t0, _relocate_copy_to_upper
|
||||
_relocate_copy_to_lower:
|
||||
ble t1, t2, _relocate_copy_to_lower_loop
|
||||
la t3, _relocate_lottery
|
||||
BRANGE t2, t1, t3, _start_hang
|
||||
la t3, _boot_status
|
||||
BRANGE t2, t1, t3, _start_hang
|
||||
la t3, _relocate
|
||||
@@ -88,6 +102,8 @@ _relocate_copy_to_lower_loop:
|
||||
jr t4
|
||||
_relocate_copy_to_upper:
|
||||
ble t3, t0, _relocate_copy_to_upper_loop
|
||||
la t2, _relocate_lottery
|
||||
BRANGE t0, t3, t2, _start_hang
|
||||
la t2, _boot_status
|
||||
BRANGE t0, t3, t2, _start_hang
|
||||
la t2, _relocate
|
||||
@@ -108,26 +124,33 @@ _wait_relocate_copy_done:
|
||||
REG_L t1, 0(t1)
|
||||
beq t0, t1, _wait_for_boot_hart
|
||||
la t2, _boot_status
|
||||
sub t2, t2, t0
|
||||
add t2, t2, t1
|
||||
la t3, _wait_for_boot_hart
|
||||
sub t3, t3, t0
|
||||
add t3, t3, t1
|
||||
1:
|
||||
/* waitting for relocate copy done (_boot_status == 1) */
|
||||
li t4, 1
|
||||
li t4, BOOT_STATUS_RELOCATE_DONE
|
||||
REG_L t5, 0(t2)
|
||||
/* Reduce the bus traffic so that boot hart may proceed faster */
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
bne t4, t5, 1b
|
||||
bgt t4, t5, 1b
|
||||
jr t3
|
||||
_relocate_done:
|
||||
|
||||
/* mark relocate copy done */
|
||||
/*
|
||||
* Mark relocate copy done
|
||||
* Use _boot_status copy relative to the load address
|
||||
*/
|
||||
la t0, _boot_status
|
||||
li t1, 1
|
||||
la t1, _link_start
|
||||
REG_L t1, 0(t1)
|
||||
la t2, _load_start
|
||||
REG_L t2, 0(t2)
|
||||
sub t0, t0, t1
|
||||
add t0, t0, t2
|
||||
li t1, BOOT_STATUS_RELOCATE_DONE
|
||||
REG_S t1, 0(t0)
|
||||
fence rw, rw
|
||||
|
||||
@@ -302,7 +325,7 @@ _fdt_reloc_again:
|
||||
_fdt_reloc_done:
|
||||
|
||||
/* mark boot hart done */
|
||||
li t0, 2
|
||||
li t0, BOOT_STATUS_BOOT_HART_DONE
|
||||
la t1, _boot_status
|
||||
REG_S t0, 0(t1)
|
||||
fence rw, rw
|
||||
@@ -310,7 +333,7 @@ _fdt_reloc_done:
|
||||
|
||||
/* waitting for boot hart done (_boot_status == 2) */
|
||||
_wait_for_boot_hart:
|
||||
li t0, 2
|
||||
li t0, BOOT_STATUS_BOOT_HART_DONE
|
||||
la t1, _boot_status
|
||||
REG_L t1, 0(t1)
|
||||
/* Reduce the bus traffic so that boot hart may proceed faster */
|
||||
@@ -371,6 +394,8 @@ _start_warm:
|
||||
j _start_hang
|
||||
|
||||
.align 3
|
||||
_relocate_lottery:
|
||||
RISCV_PTR 0
|
||||
_boot_status:
|
||||
RISCV_PTR 0
|
||||
_load_start:
|
||||
@@ -380,8 +405,8 @@ _link_start:
|
||||
_link_end:
|
||||
RISCV_PTR _fw_reloc_end
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _hartid_to_scratch
|
||||
_hartid_to_scratch:
|
||||
add sp, sp, -(3 * __SIZEOF_POINTER__)
|
||||
@@ -415,15 +440,15 @@ _hartid_to_scratch:
|
||||
add sp, sp, (3 * __SIZEOF_POINTER__)
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _start_hang
|
||||
_start_hang:
|
||||
wfi
|
||||
j _start_hang
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _trap_handler
|
||||
_trap_handler:
|
||||
/* Swap TP and MSCRATCH */
|
||||
@@ -476,6 +501,16 @@ _trap_handler_all_mode:
|
||||
REG_S t0, SBI_TRAP_REGS_OFFSET(mepc)(sp)
|
||||
csrr t0, CSR_MSTATUS
|
||||
REG_S t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
|
||||
REG_S zero, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
|
||||
#if __riscv_xlen == 32
|
||||
csrr t0, CSR_MISA
|
||||
srli t0, t0, ('H' - 'A')
|
||||
andi t0, t0, 0x1
|
||||
beq t0, zero, _skip_mstatush_save
|
||||
csrr t0, CSR_MSTATUSH
|
||||
REG_S t0, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
|
||||
_skip_mstatush_save:
|
||||
#endif
|
||||
|
||||
/* Save all general regisers except SP and T0 */
|
||||
REG_S zero, SBI_TRAP_REGS_OFFSET(zero)(sp)
|
||||
@@ -550,6 +585,15 @@ _trap_handler_all_mode:
|
||||
csrw CSR_MEPC, t0
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
|
||||
csrw CSR_MSTATUS, t0
|
||||
#if __riscv_xlen == 32
|
||||
csrr t0, CSR_MISA
|
||||
srli t0, t0, ('H' - 'A')
|
||||
andi t0, t0, 0x1
|
||||
beq t0, zero, _skip_mstatush_restore
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
|
||||
csrw CSR_MSTATUSH, t0
|
||||
_skip_mstatush_restore:
|
||||
#endif
|
||||
|
||||
/* Restore T0 */
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(t0)(sp)
|
||||
@@ -559,8 +603,8 @@ _trap_handler_all_mode:
|
||||
|
||||
mret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _reset_regs
|
||||
_reset_regs:
|
||||
|
||||
|
@@ -11,14 +11,40 @@
|
||||
|
||||
#include "fw_base.S"
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
_bad_dynamic_info:
|
||||
wfi
|
||||
j _bad_dynamic_info
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_boot_hart
|
||||
/*
|
||||
* This function is called very early even before
|
||||
* fw_save_info() is called.
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
* The boot HART id should be returned in 'a0'.
|
||||
*/
|
||||
fw_boot_hart:
|
||||
/* Sanity checks */
|
||||
li a1, FW_DYNAMIC_INFO_MAGIC_VALUE
|
||||
REG_L a0, FW_DYNAMIC_INFO_MAGIC_OFFSET(a2)
|
||||
bne a0, a1, _bad_dynamic_info
|
||||
li a1, FW_DYNAMIC_INFO_VERSION_MAX
|
||||
REG_L a0, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
|
||||
bgt a0, a1, _bad_dynamic_info
|
||||
|
||||
/* Read boot HART id */
|
||||
li a1, 0x2
|
||||
blt a0, a1, 2f
|
||||
REG_L a0, FW_DYNAMIC_INFO_BOOT_HART_OFFSET(a2)
|
||||
ret
|
||||
2: li a0, -1
|
||||
ret
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_save_info
|
||||
/*
|
||||
* We can only use a0, a1, a2, a3, and a4 registers here.
|
||||
@@ -27,14 +53,19 @@ _bad_dynamic_info:
|
||||
* Nothing to be returned here.
|
||||
*/
|
||||
fw_save_info:
|
||||
/* Save next arg1 in 'a1' */
|
||||
la a4, _dynamic_next_arg1
|
||||
REG_S a1, (a4)
|
||||
|
||||
/* Sanity checks */
|
||||
li a4, FW_DYNAMIC_INFO_MAGIC_VALUE
|
||||
REG_L a3, FW_DYNAMIC_INFO_MAGIC_OFFSET(a2)
|
||||
bne a3, a4, _bad_dynamic_info
|
||||
li a4, FW_DYNAMIC_INFO_VERSION_MAX
|
||||
REG_L a3, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
|
||||
bgt a3, a4, _bad_dynamic_info
|
||||
|
||||
/* Save version == 0x1 fields */
|
||||
la a4, _dynamic_next_addr
|
||||
REG_L a3, FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET(a2)
|
||||
REG_S a3, (a4)
|
||||
@@ -44,24 +75,37 @@ fw_save_info:
|
||||
la a4, _dynamic_options
|
||||
REG_L a3, FW_DYNAMIC_INFO_OPTIONS_OFFSET(a2)
|
||||
REG_S a3, (a4)
|
||||
|
||||
/* Save version == 0x2 fields */
|
||||
li a4, 0x2
|
||||
REG_L a3, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
|
||||
blt a3, a4, 2f
|
||||
la a4, _dynamic_boot_hart
|
||||
REG_L a3, FW_DYNAMIC_INFO_BOOT_HART_OFFSET(a2)
|
||||
REG_S a3, (a4)
|
||||
2:
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_prev_arg1
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
* The a0, a1, and a2 registers will be same as passed by
|
||||
* previous booting stage.
|
||||
* The previous arg1 should be returned in 'a0'.
|
||||
*/
|
||||
fw_prev_arg1:
|
||||
add a0, zero, zero
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_arg1
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
* The a0, a1, and a2 registers will be same as passed by
|
||||
* previous booting stage.
|
||||
* The next arg1 should be returned in 'a0'.
|
||||
*/
|
||||
fw_next_arg1:
|
||||
@@ -69,8 +113,8 @@ fw_next_arg1:
|
||||
REG_L a0, (a0)
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_addr
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
@@ -81,8 +125,8 @@ fw_next_addr:
|
||||
REG_L a0, (a0)
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_mode
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
@@ -93,8 +137,8 @@ fw_next_mode:
|
||||
REG_L a0, (a0)
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_options
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
@@ -106,8 +150,8 @@ fw_options:
|
||||
REG_L a0, (a0)
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
_dynamic_next_arg1:
|
||||
RISCV_PTR 0x0
|
||||
_dynamic_next_addr:
|
||||
@@ -116,3 +160,5 @@ _dynamic_next_mode:
|
||||
RISCV_PTR PRV_S
|
||||
_dynamic_options:
|
||||
RISCV_PTR 0x0
|
||||
_dynamic_boot_hart:
|
||||
RISCV_PTR -1
|
||||
|
@@ -9,8 +9,21 @@
|
||||
|
||||
#include "fw_base.S"
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_boot_hart
|
||||
/*
|
||||
* This function is called very early even before
|
||||
* fw_save_info() is called.
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
* The boot HART id should be returned in 'a0'.
|
||||
*/
|
||||
fw_boot_hart:
|
||||
li a0, -1
|
||||
ret
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_save_info
|
||||
/*
|
||||
* We can only use a0, a1, a2, a3, and a4 registers here.
|
||||
@@ -21,34 +34,38 @@
|
||||
fw_save_info:
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_prev_arg1
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
* The a0, a1, and a2 registers will be same as passed by
|
||||
* previous booting stage.
|
||||
* The previous arg1 should be returned in 'a0'.
|
||||
*/
|
||||
fw_prev_arg1:
|
||||
add a0, zero, zero
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_arg1
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
* The a0, a1, and a2 registers will be same as passed by
|
||||
* previous booting stage.
|
||||
* The next arg1 should be returned in 'a0'.
|
||||
*/
|
||||
fw_next_arg1:
|
||||
#ifdef FW_JUMP_FDT_ADDR
|
||||
li a0, FW_JUMP_FDT_ADDR
|
||||
#else
|
||||
add a0, zero, zero
|
||||
add a0, a1, zero
|
||||
#endif
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_addr
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
@@ -59,8 +76,8 @@ fw_next_addr:
|
||||
REG_L a0, (a0)
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_mode
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
@@ -70,8 +87,8 @@ fw_next_mode:
|
||||
li a0, PRV_S
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_options
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
@@ -86,7 +103,7 @@ fw_options:
|
||||
#error "Must define FW_JUMP_ADDR"
|
||||
#endif
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
_jump_addr:
|
||||
RISCV_PTR FW_JUMP_ADDR
|
||||
|
@@ -9,8 +9,21 @@
|
||||
|
||||
#include "fw_base.S"
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_boot_hart
|
||||
/*
|
||||
* This function is called very early even before
|
||||
* fw_save_info() is called.
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
* The boot HART id should be returned in 'a0'.
|
||||
*/
|
||||
fw_boot_hart:
|
||||
li a0, -1
|
||||
ret
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_save_info
|
||||
/*
|
||||
* We can only use a0, a1, a2, a3, and a4 registers here.
|
||||
@@ -21,11 +34,13 @@
|
||||
fw_save_info:
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_prev_arg1
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
* The a0, a1, and a2 registers will be same as passed by
|
||||
* previous booting stage.
|
||||
* The previous arg1 should be returned in 'a0'.
|
||||
*/
|
||||
fw_prev_arg1:
|
||||
@@ -36,23 +51,25 @@ fw_prev_arg1:
|
||||
#endif
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_arg1
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
* The a0, a1, and a2 registers will be same as passed by
|
||||
* previous booting stage.
|
||||
* The next arg1 should be returned in 'a0'.
|
||||
*/
|
||||
fw_next_arg1:
|
||||
#ifdef FW_PAYLOAD_FDT_ADDR
|
||||
li a0, FW_PAYLOAD_FDT_ADDR
|
||||
#else
|
||||
add a0, zero, zero
|
||||
add a0, a1, zero
|
||||
#endif
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_addr
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
@@ -62,8 +79,8 @@ fw_next_addr:
|
||||
la a0, payload_bin
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_mode
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
@@ -73,8 +90,8 @@ fw_next_mode:
|
||||
li a0, PRV_S
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_options
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
@@ -86,15 +103,15 @@ fw_options:
|
||||
ret
|
||||
|
||||
#ifdef FW_PAYLOAD_FDT_PATH
|
||||
.align 4
|
||||
.section .text, "ax", %progbits
|
||||
.align 4
|
||||
.globl fdt_bin
|
||||
fdt_bin:
|
||||
.incbin FW_PAYLOAD_FDT_PATH
|
||||
#endif
|
||||
|
||||
.align 4
|
||||
.section .payload, "ax", %progbits
|
||||
.align 4
|
||||
.globl payload_bin
|
||||
payload_bin:
|
||||
#ifndef FW_PAYLOAD_PATH
|
||||
|
@@ -23,8 +23,8 @@
|
||||
#define REG_L __REG_SEL(ld, lw)
|
||||
#define REG_S __REG_SEL(sd, sw)
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _start
|
||||
_start:
|
||||
/* Pick one hart to run the main boot sequence */
|
||||
@@ -71,15 +71,15 @@ _start_warm:
|
||||
/* We don't expect to reach here hence just hang */
|
||||
j _start_hang
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _start_hang
|
||||
_start_hang:
|
||||
wfi
|
||||
j _start_hang
|
||||
|
||||
.align 3
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
_hart_lottery:
|
||||
RISCV_PTR 0
|
||||
_boot_a0:
|
||||
|
@@ -9,6 +9,31 @@
|
||||
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
|
||||
#define SBI_ECALL(__num, __a0, __a1, __a2) \
|
||||
({ \
|
||||
register unsigned long a0 asm("a0") = (unsigned long)(__a0); \
|
||||
register unsigned long a1 asm("a1") = (unsigned long)(__a1); \
|
||||
register unsigned long a2 asm("a2") = (unsigned long)(__a2); \
|
||||
register unsigned long a7 asm("a7") = (unsigned long)(__num); \
|
||||
asm volatile("ecall" \
|
||||
: "+r"(a0) \
|
||||
: "r"(a1), "r"(a2), "r"(a7) \
|
||||
: "memory"); \
|
||||
a0; \
|
||||
})
|
||||
|
||||
#define SBI_ECALL_0(__num) SBI_ECALL(__num, 0, 0, 0)
|
||||
#define SBI_ECALL_1(__num, __a0) SBI_ECALL(__num, __a0, 0, 0)
|
||||
#define SBI_ECALL_2(__num, __a0, __a1) SBI_ECALL(__num, __a0, __a1, 0)
|
||||
|
||||
#define sbi_ecall_console_putc(c) SBI_ECALL_1(SBI_EXT_0_1_CONSOLE_PUTCHAR, (c))
|
||||
|
||||
static inline void sbi_ecall_console_puts(const char *str)
|
||||
{
|
||||
while (str && *str)
|
||||
sbi_ecall_console_putc(*str++);
|
||||
}
|
||||
|
||||
#define wfi() \
|
||||
do { \
|
||||
__asm__ __volatile__("wfi" ::: "memory"); \
|
||||
|
@@ -18,18 +18,20 @@
|
||||
#define FW_DYNAMIC_INFO_MAGIC_OFFSET (0 * __SIZEOF_POINTER__)
|
||||
/** Offset of version member in fw_dynamic_info */
|
||||
#define FW_DYNAMIC_INFO_VERSION_OFFSET (1 * __SIZEOF_POINTER__)
|
||||
/** Offset of next_addr member in fw_dynamic_info */
|
||||
/** Offset of next_addr member in fw_dynamic_info (version >= 1) */
|
||||
#define FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET (2 * __SIZEOF_POINTER__)
|
||||
/** Offset of next_mode member in fw_dynamic_info */
|
||||
/** Offset of next_mode member in fw_dynamic_info (version >= 1) */
|
||||
#define FW_DYNAMIC_INFO_NEXT_MODE_OFFSET (3 * __SIZEOF_POINTER__)
|
||||
/** Offset of options member in fw_dynamic_info */
|
||||
/** Offset of options member in fw_dynamic_info (version >= 1) */
|
||||
#define FW_DYNAMIC_INFO_OPTIONS_OFFSET (4 * __SIZEOF_POINTER__)
|
||||
/** Offset of boot_hart member in fw_dynamic_info (version >= 2) */
|
||||
#define FW_DYNAMIC_INFO_BOOT_HART_OFFSET (5 * __SIZEOF_POINTER__)
|
||||
|
||||
/** Expected value of info magic ('OSBI' ascii string in hex) */
|
||||
#define FW_DYNAMIC_INFO_MAGIC_VALUE 0x4942534f
|
||||
|
||||
/** Maximum supported info version */
|
||||
#define FW_DYNAMIC_INFO_VERSION_MAX 0x1
|
||||
#define FW_DYNAMIC_INFO_VERSION_MAX 0x2
|
||||
|
||||
/** Possible next mode values */
|
||||
#define FW_DYNAMIC_INFO_NEXT_MODE_U 0x0
|
||||
@@ -54,6 +56,22 @@ struct fw_dynamic_info {
|
||||
unsigned long next_mode;
|
||||
/** Options for OpenSBI library */
|
||||
unsigned long options;
|
||||
/**
|
||||
* Preferred boot HART id
|
||||
*
|
||||
* It is possible that the previous booting stage uses same link
|
||||
* address as the FW_DYNAMIC firmware. In this case, the relocation
|
||||
* lottery mechanism can potentially overwrite the previous booting
|
||||
* stage while other HARTs are still running in the previous booting
|
||||
* stage leading to boot-time crash. To avoid this boot-time crash,
|
||||
* the previous booting stage can specify last HART that will jump
|
||||
* to the FW_DYNAMIC firmware as the preferred boot HART.
|
||||
*
|
||||
* To avoid specifying a preferred boot HART, the previous booting
|
||||
* stage can set it to -1UL which will force the FW_DYNAMIC firmware
|
||||
* to use the relocation lottery mechanism.
|
||||
*/
|
||||
unsigned long boot_hart;
|
||||
} __packed;
|
||||
|
||||
#endif
|
||||
|
@@ -159,22 +159,26 @@ void csr_write_num(int csr_num, unsigned long val);
|
||||
__asm__ __volatile__("wfi" ::: "memory"); \
|
||||
} while (0)
|
||||
|
||||
static inline int misa_extension(char ext)
|
||||
{
|
||||
return csr_read(CSR_MISA) & (1 << (ext - 'A'));
|
||||
}
|
||||
|
||||
static inline int misa_xlen(void)
|
||||
{
|
||||
return ((long)csr_read(CSR_MISA) < 0) ? 64 : 32;
|
||||
}
|
||||
/* determine CPU extension, return non-zero support */
|
||||
int misa_extension_imp(char ext);
|
||||
|
||||
#define misa_extension(c)\
|
||||
({\
|
||||
_Static_assert(((c >= 'A') && (c <= 'Z')),\
|
||||
"The parameter of misa_extension must be [A-Z]");\
|
||||
misa_extension_imp(c);\
|
||||
})
|
||||
|
||||
/* Get MXL field of misa, return -1 on error */
|
||||
int misa_xlen(void);
|
||||
|
||||
static inline void misa_string(char *out, unsigned int out_sz)
|
||||
{
|
||||
unsigned long i, val = csr_read(CSR_MISA);
|
||||
unsigned long i;
|
||||
|
||||
for (i = 0; i < 26; i++) {
|
||||
if (val & (1 << i)) {
|
||||
if (misa_extension_imp('A' + i)) {
|
||||
*out = 'A' + i;
|
||||
out++;
|
||||
}
|
||||
|
@@ -35,6 +35,9 @@ long arch_atomic_xchg(atomic_t *atom, long newval);
|
||||
|
||||
unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
|
||||
unsigned int newval);
|
||||
|
||||
unsigned long atomic_raw_xchg_ulong(volatile unsigned long *ptr,
|
||||
unsigned long newval);
|
||||
/**
|
||||
* Set a bit in an atomic variable and return the new value.
|
||||
* @nr : Bit to set.
|
||||
|
@@ -12,170 +12,125 @@
|
||||
|
||||
#include <sbi/sbi_const.h>
|
||||
|
||||
/* TODO: Make constants usable in assembly with _AC() macro */
|
||||
|
||||
/* clang-format off */
|
||||
#define MSTATUS_UIE 0x00000001
|
||||
#define MSTATUS_SIE 0x00000002
|
||||
#define MSTATUS_HIE 0x00000004
|
||||
#define MSTATUS_MIE 0x00000008
|
||||
#define MSTATUS_UPIE 0x00000010
|
||||
#define MSTATUS_SIE _UL(0x00000002)
|
||||
#define MSTATUS_MIE _UL(0x00000008)
|
||||
#define MSTATUS_SPIE_SHIFT 5
|
||||
#define MSTATUS_SPIE (1UL << MSTATUS_SPIE_SHIFT)
|
||||
#define MSTATUS_HPIE 0x00000040
|
||||
#define MSTATUS_MPIE 0x00000080
|
||||
#define MSTATUS_SPIE (_UL(1) << MSTATUS_SPIE_SHIFT)
|
||||
#define MSTATUS_UBE _UL(0x00000040)
|
||||
#define MSTATUS_MPIE _UL(0x00000080)
|
||||
#define MSTATUS_SPP_SHIFT 8
|
||||
#define MSTATUS_SPP (1UL << MSTATUS_SPP_SHIFT)
|
||||
#define MSTATUS_HPP 0x00000600
|
||||
#define MSTATUS_SPP (_UL(1) << MSTATUS_SPP_SHIFT)
|
||||
#define MSTATUS_MPP_SHIFT 11
|
||||
#define MSTATUS_MPP (3UL << MSTATUS_MPP_SHIFT)
|
||||
#define MSTATUS_FS 0x00006000
|
||||
#define MSTATUS_XS 0x00018000
|
||||
#define MSTATUS_MPRV 0x00020000
|
||||
#define MSTATUS_SUM 0x00040000
|
||||
#define MSTATUS_MXR 0x00080000
|
||||
#define MSTATUS_TVM 0x00100000
|
||||
#define MSTATUS_TW 0x00200000
|
||||
#define MSTATUS_TSR 0x00400000
|
||||
#define MSTATUS32_SD 0x80000000
|
||||
#define MSTATUS_UXL 0x0000000300000000
|
||||
#define MSTATUS_SXL 0x0000000C00000000
|
||||
#define MSTATUS64_SD 0x8000000000000000
|
||||
#define MSTATUS_MPP (_UL(3) << MSTATUS_MPP_SHIFT)
|
||||
#define MSTATUS_FS _UL(0x00006000)
|
||||
#define MSTATUS_XS _UL(0x00018000)
|
||||
#define MSTATUS_MPRV _UL(0x00020000)
|
||||
#define MSTATUS_SUM _UL(0x00040000)
|
||||
#define MSTATUS_MXR _UL(0x00080000)
|
||||
#define MSTATUS_TVM _UL(0x00100000)
|
||||
#define MSTATUS_TW _UL(0x00200000)
|
||||
#define MSTATUS_TSR _UL(0x00400000)
|
||||
#define MSTATUS32_SD _UL(0x80000000)
|
||||
#if __riscv_xlen == 64
|
||||
#define MSTATUS_UXL _ULL(0x0000000300000000)
|
||||
#define MSTATUS_SXL _ULL(0x0000000C00000000)
|
||||
#define MSTATUS_SBE _ULL(0x0000001000000000)
|
||||
#define MSTATUS_MBE _ULL(0x0000002000000000)
|
||||
#define MSTATUS_MPV _ULL(0x0000008000000000)
|
||||
#else
|
||||
#define MSTATUSH_SBE _UL(0x00000010)
|
||||
#define MSTATUSH_MBE _UL(0x00000020)
|
||||
#define MSTATUSH_MPV _UL(0x00000080)
|
||||
#endif
|
||||
#define MSTATUS32_SD _UL(0x80000000)
|
||||
#define MSTATUS64_SD _ULL(0x8000000000000000)
|
||||
|
||||
#define SSTATUS_UIE 0x00000001
|
||||
#define SSTATUS_SIE 0x00000002
|
||||
#define SSTATUS_UPIE 0x00000010
|
||||
#define SSTATUS_SPIE 0x00000020
|
||||
#define SSTATUS_SPP 0x00000100
|
||||
#define SSTATUS_FS 0x00006000
|
||||
#define SSTATUS_XS 0x00018000
|
||||
#define SSTATUS_SUM 0x00040000
|
||||
#define SSTATUS_MXR 0x00080000
|
||||
#define SSTATUS32_SD 0x80000000
|
||||
#define SSTATUS_UXL 0x0000000300000000
|
||||
#define SSTATUS64_SD 0x8000000000000000
|
||||
#define SSTATUS_SIE MSTATUS_SIE
|
||||
#define SSTATUS_SPIE_SHIFT MSTATUS_SPIE_SHIFT
|
||||
#define SSTATUS_SPIE MSTATUS_SPIE
|
||||
#define SSTATUS_SPP_SHIFT MSTATUS_SPP_SHIFT
|
||||
#define SSTATUS_SPP MSTATUS_SPP
|
||||
#define SSTATUS_FS MSTATUS_FS
|
||||
#define SSTATUS_XS MSTATUS_XS
|
||||
#define SSTATUS_SUM MSTATUS_SUM
|
||||
#define SSTATUS_MXR MSTATUS_MXR
|
||||
#define SSTATUS32_SD MSTATUS32_SD
|
||||
#define SSTATUS64_UXL MSTATUS_UXL
|
||||
#define SSTATUS64_SD MSTATUS64_SD
|
||||
|
||||
#define DCSR_XDEBUGVER (3U<<30)
|
||||
#define DCSR_NDRESET (1<<29)
|
||||
#define DCSR_FULLRESET (1<<28)
|
||||
#define DCSR_EBREAKM (1<<15)
|
||||
#define DCSR_EBREAKH (1<<14)
|
||||
#define DCSR_EBREAKS (1<<13)
|
||||
#define DCSR_EBREAKU (1<<12)
|
||||
#define DCSR_STOPCYCLE (1<<10)
|
||||
#define DCSR_STOPTIME (1<<9)
|
||||
#define DCSR_CAUSE (7<<6)
|
||||
#define DCSR_DEBUGINT (1<<5)
|
||||
#define DCSR_HALT (1<<3)
|
||||
#define DCSR_STEP (1<<2)
|
||||
#define DCSR_PRV (3<<0)
|
||||
|
||||
#define DCSR_CAUSE_NONE 0
|
||||
#define DCSR_CAUSE_SWBP 1
|
||||
#define DCSR_CAUSE_HWBP 2
|
||||
#define DCSR_CAUSE_DEBUGINT 3
|
||||
#define DCSR_CAUSE_STEP 4
|
||||
#define DCSR_CAUSE_HALT 5
|
||||
|
||||
#define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4))
|
||||
#define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5))
|
||||
#define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11))
|
||||
|
||||
#define MCONTROL_SELECT (1<<19)
|
||||
#define MCONTROL_TIMING (1<<18)
|
||||
#define MCONTROL_ACTION (0x3f<<12)
|
||||
#define MCONTROL_CHAIN (1<<11)
|
||||
#define MCONTROL_MATCH (0xf<<7)
|
||||
#define MCONTROL_M (1<<6)
|
||||
#define MCONTROL_H (1<<5)
|
||||
#define MCONTROL_S (1<<4)
|
||||
#define MCONTROL_U (1<<3)
|
||||
#define MCONTROL_EXECUTE (1<<2)
|
||||
#define MCONTROL_STORE (1<<1)
|
||||
#define MCONTROL_LOAD (1<<0)
|
||||
|
||||
#define MCONTROL_TYPE_NONE 0
|
||||
#define MCONTROL_TYPE_MATCH 2
|
||||
|
||||
#define MCONTROL_ACTION_DEBUG_EXCEPTION 0
|
||||
#define MCONTROL_ACTION_DEBUG_MODE 1
|
||||
#define MCONTROL_ACTION_TRACE_START 2
|
||||
#define MCONTROL_ACTION_TRACE_STOP 3
|
||||
#define MCONTROL_ACTION_TRACE_EMIT 4
|
||||
|
||||
#define MCONTROL_MATCH_EQUAL 0
|
||||
#define MCONTROL_MATCH_NAPOT 1
|
||||
#define MCONTROL_MATCH_GE 2
|
||||
#define MCONTROL_MATCH_LT 3
|
||||
#define MCONTROL_MATCH_MASK_LOW 4
|
||||
#define MCONTROL_MATCH_MASK_HIGH 5
|
||||
#define HSTATUS_VTSR _UL(0x00400000)
|
||||
#define HSTATUS_VTVM _UL(0x00100000)
|
||||
#define HSTATUS_SP2V _UL(0x00000200)
|
||||
#define HSTATUS_SP2P _UL(0x00000100)
|
||||
#define HSTATUS_SPV _UL(0x00000080)
|
||||
#define HSTATUS_SPRV _UL(0x00000001)
|
||||
|
||||
#define IRQ_S_SOFT 1
|
||||
#define IRQ_H_SOFT 2
|
||||
#define IRQ_VS_SOFT 2
|
||||
#define IRQ_M_SOFT 3
|
||||
#define IRQ_S_TIMER 5
|
||||
#define IRQ_H_TIMER 6
|
||||
#define IRQ_VS_TIMER 6
|
||||
#define IRQ_M_TIMER 7
|
||||
#define IRQ_S_EXT 9
|
||||
#define IRQ_H_EXT 10
|
||||
#define IRQ_VS_EXT 10
|
||||
#define IRQ_M_EXT 11
|
||||
#define IRQ_COP 12
|
||||
#define IRQ_HOST 13
|
||||
#define IRQ_S_GEXT 12
|
||||
|
||||
#define MIP_SSIP (1 << IRQ_S_SOFT)
|
||||
#define MIP_HSIP (1 << IRQ_H_SOFT)
|
||||
#define MIP_MSIP (1 << IRQ_M_SOFT)
|
||||
#define MIP_STIP (1 << IRQ_S_TIMER)
|
||||
#define MIP_HTIP (1 << IRQ_H_TIMER)
|
||||
#define MIP_MTIP (1 << IRQ_M_TIMER)
|
||||
#define MIP_SEIP (1 << IRQ_S_EXT)
|
||||
#define MIP_HEIP (1 << IRQ_H_EXT)
|
||||
#define MIP_MEIP (1 << IRQ_M_EXT)
|
||||
#define MIP_SSIP (_UL(1) << IRQ_S_SOFT)
|
||||
#define MIP_VSSIP (_UL(1) << IRQ_VS_SOFT)
|
||||
#define MIP_MSIP (_UL(1) << IRQ_M_SOFT)
|
||||
#define MIP_STIP (_UL(1) << IRQ_S_TIMER)
|
||||
#define MIP_VSTIP (_UL(1) << IRQ_VS_TIMER)
|
||||
#define MIP_MTIP (_UL(1) << IRQ_M_TIMER)
|
||||
#define MIP_SEIP (_UL(1) << IRQ_S_EXT)
|
||||
#define MIP_VSEIP (_UL(1) << IRQ_VS_EXT)
|
||||
#define MIP_MEIP (_UL(1) << IRQ_M_EXT)
|
||||
#define MIP_SGEIP (_UL(1) << IRQ_S_GEXT)
|
||||
|
||||
#define SIP_SSIP MIP_SSIP
|
||||
#define SIP_STIP MIP_STIP
|
||||
|
||||
#define PRV_U 0
|
||||
#define PRV_S 1
|
||||
#define PRV_H 2
|
||||
#define PRV_M 3
|
||||
#define PRV_U _UL(0)
|
||||
#define PRV_S _UL(1)
|
||||
#define PRV_M _UL(3)
|
||||
|
||||
#define SATP32_MODE 0x80000000
|
||||
#define SATP32_ASID 0x7FC00000
|
||||
#define SATP32_PPN 0x003FFFFF
|
||||
#define SATP64_MODE 0xF000000000000000
|
||||
#define SATP64_ASID 0x0FFFF00000000000
|
||||
#define SATP64_PPN 0x00000FFFFFFFFFFF
|
||||
#define SATP32_MODE _UL(0x80000000)
|
||||
#define SATP32_ASID _UL(0x7FC00000)
|
||||
#define SATP32_PPN _UL(0x003FFFFF)
|
||||
#define SATP64_MODE _ULL(0xF000000000000000)
|
||||
#define SATP64_ASID _ULL(0x0FFFF00000000000)
|
||||
#define SATP64_PPN _ULL(0x00000FFFFFFFFFFF)
|
||||
|
||||
#define SATP_MODE_OFF 0
|
||||
#define SATP_MODE_SV32 1
|
||||
#define SATP_MODE_SV39 8
|
||||
#define SATP_MODE_SV48 9
|
||||
#define SATP_MODE_SV57 10
|
||||
#define SATP_MODE_SV64 11
|
||||
#define SATP_MODE_OFF _UL(0)
|
||||
#define SATP_MODE_SV32 _UL(1)
|
||||
#define SATP_MODE_SV39 _UL(8)
|
||||
#define SATP_MODE_SV48 _UL(9)
|
||||
#define SATP_MODE_SV57 _UL(10)
|
||||
#define SATP_MODE_SV64 _UL(11)
|
||||
|
||||
#define PMP_R 0x01
|
||||
#define PMP_W 0x02
|
||||
#define PMP_X 0x04
|
||||
#define PMP_A 0x18
|
||||
#define PMP_A_TOR 0x08
|
||||
#define PMP_A_NA4 0x10
|
||||
#define PMP_A_NAPOT 0x18
|
||||
#define PMP_L 0x80
|
||||
#define PMP_R _UL(0x01)
|
||||
#define PMP_W _UL(0x02)
|
||||
#define PMP_X _UL(0x04)
|
||||
#define PMP_A _UL(0x18)
|
||||
#define PMP_A_TOR _UL(0x08)
|
||||
#define PMP_A_NA4 _UL(0x10)
|
||||
#define PMP_A_NAPOT _UL(0x18)
|
||||
#define PMP_L _UL(0x80)
|
||||
|
||||
#define PMP_SHIFT 2
|
||||
#define PMP_COUNT 16
|
||||
|
||||
/* page table entry (PTE) fields */
|
||||
#define PTE_V 0x001 /* Valid */
|
||||
#define PTE_R 0x002 /* Read */
|
||||
#define PTE_W 0x004 /* Write */
|
||||
#define PTE_X 0x008 /* Execute */
|
||||
#define PTE_U 0x010 /* User */
|
||||
#define PTE_G 0x020 /* Global */
|
||||
#define PTE_A 0x040 /* Accessed */
|
||||
#define PTE_D 0x080 /* Dirty */
|
||||
#define PTE_SOFT 0x300 /* Reserved for Software */
|
||||
#define PTE_V _UL(0x001) /* Valid */
|
||||
#define PTE_R _UL(0x002) /* Read */
|
||||
#define PTE_W _UL(0x004) /* Write */
|
||||
#define PTE_X _UL(0x008) /* Execute */
|
||||
#define PTE_U _UL(0x010) /* User */
|
||||
#define PTE_G _UL(0x020) /* Global */
|
||||
#define PTE_A _UL(0x040) /* Accessed */
|
||||
#define PTE_D _UL(0x080) /* Dirty */
|
||||
#define PTE_SOFT _UL(0x300) /* Reserved for Software */
|
||||
|
||||
#define PTE_PPN_SHIFT 10
|
||||
|
||||
@@ -249,6 +204,31 @@
|
||||
#define CSR_STVAL 0x143
|
||||
#define CSR_SIP 0x144
|
||||
#define CSR_SATP 0x180
|
||||
|
||||
#define CSR_HSTATUS 0x600
|
||||
#define CSR_HEDELEG 0x602
|
||||
#define CSR_HIDELEG 0x603
|
||||
#define CSR_HIE 0x604
|
||||
#define CSR_HTIMEDELTA 0x605
|
||||
#define CSR_HTIMEDELTAH 0x615
|
||||
#define CSR_HCOUNTERNEN 0x606
|
||||
#define CSR_HGEIE 0x607
|
||||
#define CSR_HTVAL 0x643
|
||||
#define CSR_HIP 0x644
|
||||
#define CSR_HTINST 0x64a
|
||||
#define CSR_HGATP 0x680
|
||||
#define CSR_HGEIP 0xe07
|
||||
|
||||
#define CSR_VSSTATUS 0x200
|
||||
#define CSR_VSIE 0x204
|
||||
#define CSR_VSTVEC 0x205
|
||||
#define CSR_VSSCRATCH 0x240
|
||||
#define CSR_VSEPC 0x241
|
||||
#define CSR_VSCAUSE 0x242
|
||||
#define CSR_VSTVAL 0x243
|
||||
#define CSR_VSIP 0x244
|
||||
#define CSR_VSATP 0x280
|
||||
|
||||
#define CSR_MSTATUS 0x300
|
||||
#define CSR_MISA 0x301
|
||||
#define CSR_MEDELEG 0x302
|
||||
@@ -256,11 +236,14 @@
|
||||
#define CSR_MIE 0x304
|
||||
#define CSR_MTVEC 0x305
|
||||
#define CSR_MCOUNTEREN 0x306
|
||||
#define CSR_MSTATUSH 0x310
|
||||
#define CSR_MSCRATCH 0x340
|
||||
#define CSR_MEPC 0x341
|
||||
#define CSR_MCAUSE 0x342
|
||||
#define CSR_MTVAL 0x343
|
||||
#define CSR_MIP 0x344
|
||||
#define CSR_MTINST 0x34a
|
||||
#define CSR_MTVAL2 0x34b
|
||||
#define CSR_PMPCFG0 0x3a0
|
||||
#define CSR_PMPCFG1 0x3a1
|
||||
#define CSR_PMPCFG2 0x3a2
|
||||
@@ -288,6 +271,7 @@
|
||||
#define CSR_DCSR 0x7b0
|
||||
#define CSR_DPC 0x7b1
|
||||
#define CSR_DSCRATCH 0x7b2
|
||||
|
||||
#define CSR_MCYCLE 0xb00
|
||||
#define CSR_MINSTRET 0xb02
|
||||
#define CSR_MHPMCOUNTER3 0xb03
|
||||
@@ -431,6 +415,9 @@
|
||||
#define CAUSE_FETCH_PAGE_FAULT 0xc
|
||||
#define CAUSE_LOAD_PAGE_FAULT 0xd
|
||||
#define CAUSE_STORE_PAGE_FAULT 0xf
|
||||
#define CAUSE_FETCH_GUEST_PAGE_FAULT 0x14
|
||||
#define CAUSE_LOAD_GUEST_PAGE_FAULT 0x15
|
||||
#define CAUSE_STORE_GUEST_PAGE_FAULT 0x17
|
||||
|
||||
#define INSN_MATCH_LB 0x3
|
||||
#define INSN_MASK_LB 0x707f
|
||||
@@ -502,7 +489,19 @@
|
||||
#define INSN_MATCH_C_FSWSP 0xe002
|
||||
#define INSN_MASK_C_FSWSP 0xe003
|
||||
|
||||
#define INSN_LEN(insn) ((((insn) & 0x3) < 0x3) ? 2 : 4)
|
||||
#define INSN_MASK_WFI 0xffffff00
|
||||
#define INSN_MATCH_WFI 0x10500000
|
||||
|
||||
#define INSN_16BIT_MASK 0x3
|
||||
#define INSN_32BIT_MASK 0x1c
|
||||
|
||||
#define INSN_IS_16BIT(insn) \
|
||||
(((insn) & INSN_16BIT_MASK) != INSN_16BIT_MASK)
|
||||
#define INSN_IS_32BIT(insn) \
|
||||
(((insn) & INSN_16BIT_MASK) == INSN_16BIT_MASK && \
|
||||
((insn) & INSN_32BIT_MASK) != INSN_32BIT_MASK)
|
||||
|
||||
#define INSN_LEN(insn) (INSN_IS_16BIT(insn) ? 2 : 4)
|
||||
|
||||
#if __riscv_xlen == 64
|
||||
#define LOG_REGBYTES 3
|
||||
|
@@ -73,10 +73,6 @@
|
||||
|
||||
#define SET_FS_DIRTY() ((void)0)
|
||||
|
||||
#else
|
||||
#error "Floating point emulation not supported.\n"
|
||||
#endif
|
||||
|
||||
#define GET_F32_RS1(insn, regs) (GET_F32_REG(insn, 15, regs))
|
||||
#define GET_F32_RS2(insn, regs) (GET_F32_REG(insn, 20, regs))
|
||||
#define GET_F32_RS3(insn, regs) (GET_F32_REG(insn, 27, regs))
|
||||
@@ -94,3 +90,5 @@
|
||||
#define GET_F64_RS2S(insn, regs) (GET_F64_REG(RVC_RS2S(insn), 0, regs))
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@@ -95,4 +95,78 @@ static inline int __ffs(unsigned long word)
|
||||
*/
|
||||
#define ffz(x) __ffs(~(x))
|
||||
|
||||
/**
|
||||
* fls - find last (most-significant) bit set
|
||||
* @x: the word to search
|
||||
*
|
||||
* This is defined the same way as ffs.
|
||||
* Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
|
||||
*/
|
||||
|
||||
static inline int fls(int x)
|
||||
{
|
||||
int r = 32;
|
||||
|
||||
if (!x)
|
||||
return 0;
|
||||
if (!(x & 0xffff0000u)) {
|
||||
x <<= 16;
|
||||
r -= 16;
|
||||
}
|
||||
if (!(x & 0xff000000u)) {
|
||||
x <<= 8;
|
||||
r -= 8;
|
||||
}
|
||||
if (!(x & 0xf0000000u)) {
|
||||
x <<= 4;
|
||||
r -= 4;
|
||||
}
|
||||
if (!(x & 0xc0000000u)) {
|
||||
x <<= 2;
|
||||
r -= 2;
|
||||
}
|
||||
if (!(x & 0x80000000u)) {
|
||||
x <<= 1;
|
||||
r -= 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* __fls - find last (most-significant) set bit in a long word
|
||||
* @word: the word to search
|
||||
*
|
||||
* Undefined if no set bit exists, so code should check against 0 first.
|
||||
*/
|
||||
static inline unsigned long __fls(unsigned long word)
|
||||
{
|
||||
int num = BITS_PER_LONG - 1;
|
||||
|
||||
#if BITS_PER_LONG == 64
|
||||
if (!(word & (~0ul << 32))) {
|
||||
num -= 32;
|
||||
word <<= 32;
|
||||
}
|
||||
#endif
|
||||
if (!(word & (~0ul << (BITS_PER_LONG-16)))) {
|
||||
num -= 16;
|
||||
word <<= 16;
|
||||
}
|
||||
if (!(word & (~0ul << (BITS_PER_LONG-8)))) {
|
||||
num -= 8;
|
||||
word <<= 8;
|
||||
}
|
||||
if (!(word & (~0ul << (BITS_PER_LONG-4)))) {
|
||||
num -= 4;
|
||||
word <<= 4;
|
||||
}
|
||||
if (!(word & (~0ul << (BITS_PER_LONG-2)))) {
|
||||
num -= 2;
|
||||
word <<= 2;
|
||||
}
|
||||
if (!(word & (~0ul << (BITS_PER_LONG-1))))
|
||||
num -= 1;
|
||||
return num;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -10,23 +10,10 @@
|
||||
#ifndef __SBI_BITS_H__
|
||||
#define __SBI_BITS_H__
|
||||
|
||||
#define likely(x) __builtin_expect((x), 1)
|
||||
#define unlikely(x) __builtin_expect((x), 0)
|
||||
|
||||
#define ROUNDUP(a, b) ((((a)-1) / (b) + 1) * (b))
|
||||
#define ROUNDDOWN(a, b) ((a) / (b) * (b))
|
||||
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define CLAMP(a, lo, hi) MIN(MAX(a, lo), hi)
|
||||
|
||||
#define EXTRACT_FIELD(val, which) (((val) & (which)) / ((which) & ~((which)-1)))
|
||||
#define INSERT_FIELD(val, which, fieldval) \
|
||||
(((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1))))
|
||||
|
||||
#define STR(x) XSTR(x)
|
||||
#define XSTR(x) #x
|
||||
|
||||
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
|
||||
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
|
||||
#endif
|
||||
|
@@ -31,6 +31,10 @@ int __printf(3, 4) sbi_snprintf(char *out, u32 out_sz, const char *format, ...);
|
||||
int __printf(1, 2) sbi_printf(const char *format, ...);
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
int __printf(2, 3) sbi_dprintf(struct sbi_scratch *scratch,
|
||||
const char *format, ...);
|
||||
|
||||
int sbi_console_init(struct sbi_scratch *scratch);
|
||||
|
||||
#endif
|
||||
|
@@ -11,15 +11,48 @@
|
||||
#define __SBI_ECALL_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
#include <sbi/sbi_list.h>
|
||||
|
||||
#define SBI_ECALL_VERSION_MAJOR 0
|
||||
#define SBI_ECALL_VERSION_MINOR 2
|
||||
#define SBI_OPENSBI_IMPID 1
|
||||
|
||||
struct sbi_trap_regs;
|
||||
struct sbi_trap_info;
|
||||
struct sbi_scratch;
|
||||
|
||||
struct sbi_ecall_extension {
|
||||
struct sbi_dlist head;
|
||||
unsigned long extid_start;
|
||||
unsigned long extid_end;
|
||||
int (* probe)(struct sbi_scratch *scratch,
|
||||
unsigned long extid, unsigned long *out_val);
|
||||
int (* handle)(struct sbi_scratch *scratch,
|
||||
unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap);
|
||||
};
|
||||
|
||||
extern struct sbi_ecall_extension ecall_base;
|
||||
extern struct sbi_ecall_extension ecall_legacy;
|
||||
extern struct sbi_ecall_extension ecall_time;
|
||||
extern struct sbi_ecall_extension ecall_rfence;
|
||||
extern struct sbi_ecall_extension ecall_ipi;
|
||||
extern struct sbi_ecall_extension ecall_vendor;
|
||||
|
||||
u16 sbi_ecall_version_major(void);
|
||||
|
||||
u16 sbi_ecall_version_minor(void);
|
||||
|
||||
struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid);
|
||||
|
||||
int sbi_ecall_register_extension(struct sbi_ecall_extension *ext);
|
||||
|
||||
void sbi_ecall_unregister_extension(struct sbi_ecall_extension *ext);
|
||||
|
||||
int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch);
|
||||
|
||||
int sbi_ecall_init(void);
|
||||
|
||||
#endif
|
||||
|
@@ -12,41 +12,50 @@
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#define SBI_ECALL_SET_TIMER 0
|
||||
#define SBI_ECALL_CONSOLE_PUTCHAR 1
|
||||
#define SBI_ECALL_CONSOLE_GETCHAR 2
|
||||
#define SBI_ECALL_CLEAR_IPI 3
|
||||
#define SBI_ECALL_SEND_IPI 4
|
||||
#define SBI_ECALL_REMOTE_FENCE_I 5
|
||||
#define SBI_ECALL_REMOTE_SFENCE_VMA 6
|
||||
#define SBI_ECALL_REMOTE_SFENCE_VMA_ASID 7
|
||||
#define SBI_ECALL_SHUTDOWN 8
|
||||
/* SBI Extension IDs */
|
||||
#define SBI_EXT_0_1_SET_TIMER 0x0
|
||||
#define SBI_EXT_0_1_CONSOLE_PUTCHAR 0x1
|
||||
#define SBI_EXT_0_1_CONSOLE_GETCHAR 0x2
|
||||
#define SBI_EXT_0_1_CLEAR_IPI 0x3
|
||||
#define SBI_EXT_0_1_SEND_IPI 0x4
|
||||
#define SBI_EXT_0_1_REMOTE_FENCE_I 0x5
|
||||
#define SBI_EXT_0_1_REMOTE_SFENCE_VMA 0x6
|
||||
#define SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID 0x7
|
||||
#define SBI_EXT_0_1_SHUTDOWN 0x8
|
||||
#define SBI_EXT_BASE 0x10
|
||||
#define SBI_EXT_TIME 0x54494D45
|
||||
#define SBI_EXT_IPI 0x735049
|
||||
#define SBI_EXT_RFENCE 0x52464E43
|
||||
|
||||
/* SBI function IDs for BASE extension*/
|
||||
#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
|
||||
#define SBI_EXT_BASE_GET_IMP_ID 0x1
|
||||
#define SBI_EXT_BASE_GET_IMP_VERSION 0x2
|
||||
#define SBI_EXT_BASE_PROBE_EXT 0x3
|
||||
#define SBI_EXT_BASE_GET_MVENDORID 0x4
|
||||
#define SBI_EXT_BASE_GET_MARCHID 0x5
|
||||
#define SBI_EXT_BASE_GET_MIMPID 0x6
|
||||
|
||||
/* SBI function IDs for TIME extension*/
|
||||
#define SBI_EXT_TIME_SET_TIMER 0x0
|
||||
|
||||
/* SBI function IDs for IPI extension*/
|
||||
#define SBI_EXT_IPI_SEND_IPI 0x0
|
||||
|
||||
/* SBI function IDs for RFENCE extension*/
|
||||
#define SBI_EXT_RFENCE_REMOTE_FENCE_I 0x0
|
||||
#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA 0x1
|
||||
#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID 0x2
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA 0x3
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID 0x4
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA 0x5
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID 0x6
|
||||
|
||||
#define SBI_SPEC_VERSION_MAJOR_OFFSET 24
|
||||
#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f
|
||||
#define SBI_SPEC_VERSION_MINOR_MASK 0xffffff
|
||||
#define SBI_EXT_VENDOR_START 0x09000000
|
||||
#define SBI_EXT_VENDOR_END 0x09FFFFFF
|
||||
/* clang-format on */
|
||||
|
||||
#define SBI_ECALL(__num, __a0, __a1, __a2) \
|
||||
({ \
|
||||
register unsigned long a0 asm("a0") = (unsigned long)(__a0); \
|
||||
register unsigned long a1 asm("a1") = (unsigned long)(__a1); \
|
||||
register unsigned long a2 asm("a2") = (unsigned long)(__a2); \
|
||||
register unsigned long a7 asm("a7") = (unsigned long)(__num); \
|
||||
asm volatile("ecall" \
|
||||
: "+r"(a0) \
|
||||
: "r"(a1), "r"(a2), "r"(a7) \
|
||||
: "memory"); \
|
||||
a0; \
|
||||
})
|
||||
|
||||
#define SBI_ECALL_0(__num) SBI_ECALL(__num, 0, 0, 0)
|
||||
#define SBI_ECALL_1(__num, __a0) SBI_ECALL(__num, __a0, 0, 0)
|
||||
#define SBI_ECALL_2(__num, __a0, __a1) SBI_ECALL(__num, __a0, __a1, 0)
|
||||
|
||||
#define sbi_ecall_console_putc(c) SBI_ECALL_1(SBI_ECALL_CONSOLE_PUTCHAR, (c));
|
||||
|
||||
static inline void sbi_ecall_console_puts(const char *str)
|
||||
{
|
||||
while (str && *str)
|
||||
sbi_ecall_console_putc(*str++);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -12,12 +12,13 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
struct sbi_trap_regs;
|
||||
struct sbi_scratch;
|
||||
|
||||
int sbi_emulate_csr_read(int csr_num, u32 hartid, ulong mstatus,
|
||||
int sbi_emulate_csr_read(int csr_num, u32 hartid, struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch, ulong *csr_val);
|
||||
|
||||
int sbi_emulate_csr_write(int csr_num, u32 hartid, ulong mstatus,
|
||||
int sbi_emulate_csr_write(int csr_num, u32 hartid, struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch, ulong csr_val);
|
||||
|
||||
#endif
|
||||
|
@@ -13,11 +13,11 @@
|
||||
/* clang-format off */
|
||||
|
||||
#define SBI_OK 0
|
||||
#define SBI_EUNKNOWN -1
|
||||
#define SBI_EFAIL -2
|
||||
#define SBI_EFAIL -1
|
||||
#define SBI_ENOTSUPP -2
|
||||
#define SBI_EINVAL -3
|
||||
#define SBI_ENOENT -4
|
||||
#define SBI_ENOTSUPP -5
|
||||
#define SBI_DENIED -4
|
||||
#define SBI_INVALID_ADDR -5
|
||||
#define SBI_ENODEV -6
|
||||
#define SBI_ENOSYS -7
|
||||
#define SBI_ETIMEDOUT -8
|
||||
@@ -26,6 +26,8 @@
|
||||
#define SBI_ENOSPC -11
|
||||
#define SBI_ENOMEM -12
|
||||
#define SBI_ETRAP -13
|
||||
#define SBI_EUNKNOWN -14
|
||||
#define SBI_ENOENT -15
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
|
@@ -26,7 +26,6 @@ struct sbi_fifo {
|
||||
enum sbi_fifo_inplace_update_types {
|
||||
SBI_FIFO_SKIP,
|
||||
SBI_FIFO_UPDATED,
|
||||
SBI_FIFO_RESET,
|
||||
SBI_FIFO_UNCHANGED,
|
||||
};
|
||||
|
||||
|
@@ -20,13 +20,15 @@ void *sbi_hart_get_trap_info(struct sbi_scratch *scratch);
|
||||
|
||||
void sbi_hart_set_trap_info(struct sbi_scratch *scratch, void *data);
|
||||
|
||||
void sbi_hart_delegation_dump(struct sbi_scratch *scratch);
|
||||
void sbi_hart_pmp_dump(struct sbi_scratch *scratch);
|
||||
|
||||
void __attribute__((noreturn)) sbi_hart_hang(void);
|
||||
|
||||
void __attribute__((noreturn))
|
||||
sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
|
||||
unsigned long next_addr, unsigned long next_mode);
|
||||
unsigned long next_addr, unsigned long next_mode,
|
||||
bool next_virt);
|
||||
|
||||
void sbi_hart_mark_available(u32 hartid);
|
||||
|
||||
|
36
include/sbi/sbi_hfence.h
Normal file
36
include/sbi/sbi_hfence.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Atish Patra <atish.patra@wdc.com>
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __SBI_FENCE_H__
|
||||
#define __SBI_FENCE_H__
|
||||
/** Invalidate Stage2 TLBs for given VMID and guest physical address */
|
||||
void __sbi_hfence_gvma_vmid_gpa(unsigned long vmid, unsigned long gpa);
|
||||
|
||||
/** Invalidate Stage2 TLBs for given VMID */
|
||||
void __sbi_hfence_gvma_vmid(unsigned long vmid);
|
||||
|
||||
/** Invalidate Stage2 TLBs for given guest physical address */
|
||||
void __sbi_hfence_gvma_gpa(unsigned long gpa);
|
||||
|
||||
/** Invalidate all possible Stage2 TLBs */
|
||||
void __sbi_hfence_gvma_all(void);
|
||||
|
||||
/** Invalidate unified TLB entries for given asid and guest virtual address */
|
||||
void __sbi_hfence_vvma_asid_va(unsigned long asid, unsigned long va);
|
||||
|
||||
/** Invalidate unified TLB entries for given ASID for a guest*/
|
||||
void __sbi_hfence_vvma_asid(unsigned long asid);
|
||||
|
||||
/** Invalidate unified TLB entries for a given guest virtual address */
|
||||
void __sbi_hfence_vvma_va(unsigned long va);
|
||||
|
||||
/** Invalidate all possible Stage2 TLBs */
|
||||
void __sbi_hfence_vvma_all(void);
|
||||
#endif
|
@@ -15,7 +15,7 @@
|
||||
struct sbi_trap_regs;
|
||||
struct sbi_scratch;
|
||||
|
||||
int sbi_illegal_insn_handler(u32 hartid, ulong mcause,
|
||||
int sbi_illegal_insn_handler(u32 hartid, ulong mcause, ulong insn,
|
||||
struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch);
|
||||
|
||||
|
@@ -16,4 +16,8 @@ struct sbi_scratch;
|
||||
|
||||
void __noreturn sbi_init(struct sbi_scratch *scratch);
|
||||
|
||||
unsigned long sbi_init_count(u32 hartid);
|
||||
|
||||
void __noreturn sbi_exit(struct sbi_scratch *scratch);
|
||||
|
||||
#endif
|
||||
|
@@ -10,32 +10,59 @@
|
||||
#ifndef __SBI_IPI_H__
|
||||
#define __SBI_IPI_H__
|
||||
|
||||
#include <sbi/riscv_unpriv.h>
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#define SBI_IPI_EVENT_SOFT 0x1
|
||||
#define SBI_IPI_EVENT_FENCE_I 0x2
|
||||
#define SBI_IPI_EVENT_SFENCE_VMA 0x4
|
||||
#define SBI_IPI_EVENT_SFENCE_VMA_ASID 0x8
|
||||
#define SBI_IPI_EVENT_HALT 0x10
|
||||
#define SBI_IPI_EVENT_MAX __riscv_xlen
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
struct sbi_ipi_data {
|
||||
unsigned long ipi_type;
|
||||
/** IPI event operations or callbacks */
|
||||
struct sbi_ipi_event_ops {
|
||||
/** Name of the IPI event operations */
|
||||
char name[32];
|
||||
|
||||
/** Update callback to save/enqueue data for remote HART
|
||||
* Note: This is an optional callback and it is called just before
|
||||
* triggering IPI to remote HART.
|
||||
*/
|
||||
int (* update)(struct sbi_scratch *scratch,
|
||||
struct sbi_scratch *remote_scratch,
|
||||
u32 remote_hartid, void *data);
|
||||
|
||||
/** Sync callback to wait for remote HART
|
||||
* Note: This is an optional callback and it is called just after
|
||||
* triggering IPI to remote HART.
|
||||
*/
|
||||
void (* sync)(struct sbi_scratch *scratch);
|
||||
|
||||
/** Process callback to handle IPI event
|
||||
* Note: This is a mandatory callback and it is called on the
|
||||
* remote HART after IPI is triggered.
|
||||
*/
|
||||
void (* process)(struct sbi_scratch *scratch);
|
||||
};
|
||||
|
||||
int sbi_ipi_send_many(struct sbi_scratch *scratch, struct unpriv_trap *uptrap,
|
||||
ulong *pmask, u32 event, void *data);
|
||||
int sbi_ipi_send_many(struct sbi_scratch *scratch, ulong hmask,
|
||||
ulong hbase, u32 event, void *data);
|
||||
|
||||
int sbi_ipi_event_create(const struct sbi_ipi_event_ops *ops);
|
||||
|
||||
void sbi_ipi_event_destroy(u32 event);
|
||||
|
||||
int sbi_ipi_send_smode(struct sbi_scratch *scratch, ulong hmask, ulong hbase);
|
||||
|
||||
void sbi_ipi_clear_smode(struct sbi_scratch *scratch);
|
||||
|
||||
int sbi_ipi_send_halt(struct sbi_scratch *scratch, ulong hmask, ulong hbase);
|
||||
|
||||
void sbi_ipi_process(struct sbi_scratch *scratch);
|
||||
|
||||
int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||
|
||||
void sbi_ipi_exit(struct sbi_scratch *scratch);
|
||||
|
||||
#endif
|
||||
|
152
include/sbi/sbi_list.h
Normal file
152
include/sbi/sbi_list.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Simple doubly-linked list library.
|
||||
*
|
||||
* Adapted from Xvisor source file libs/include/libs/list.h
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __SBI_LIST_H__
|
||||
#define __SBI_LIST_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
#define SBI_LIST_POISON_PREV 0xDEADBEEF
|
||||
#define SBI_LIST_POISON_NEXT 0xFADEBABE
|
||||
|
||||
struct sbi_dlist {
|
||||
struct sbi_dlist *next, *prev;
|
||||
};
|
||||
|
||||
#define SBI_LIST_HEAD_INIT(__lname) { &(__lname), &(__lname) }
|
||||
|
||||
#define SBI_LIST_HEAD(_lname) \
|
||||
struct sbi_dlist _lname = SBI_LIST_HEAD_INIT(_lname)
|
||||
|
||||
#define SBI_INIT_LIST_HEAD(ptr) \
|
||||
do { \
|
||||
(ptr)->next = ptr; (ptr)->prev = ptr; \
|
||||
} while (0);
|
||||
|
||||
static inline void __sbi_list_add(struct sbi_dlist *new,
|
||||
struct sbi_dlist *prev,
|
||||
struct sbi_dlist *next)
|
||||
{
|
||||
new->prev = prev;
|
||||
new->next = next;
|
||||
prev->next = new;
|
||||
next->prev = new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the new node after the given head.
|
||||
* @param new New node that needs to be added to list.
|
||||
* @param head List head after which the "new" node should be added.
|
||||
* Note: the new node is added after the head.
|
||||
*/
|
||||
static inline void sbi_list_add(struct sbi_dlist *new, struct sbi_dlist *head)
|
||||
{
|
||||
__sbi_list_add(new, head, head->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a node at the tail where tnode points to tail node.
|
||||
* @param new The new node to be added before tail.
|
||||
* @param tnode The current tail node.
|
||||
* Note: the new node is added before tail node.
|
||||
*/
|
||||
static inline void sbi_list_add_tail(struct sbi_dlist *new,
|
||||
struct sbi_dlist *tnode)
|
||||
{
|
||||
__sbi_list_add(new, tnode->prev, tnode);
|
||||
}
|
||||
|
||||
static inline void __sbi_list_del(struct sbi_dlist *prev,
|
||||
struct sbi_dlist *next)
|
||||
{
|
||||
prev->next = next;
|
||||
next->prev = prev;
|
||||
}
|
||||
|
||||
static inline void __sbi_list_del_entry(struct sbi_dlist *entry)
|
||||
{
|
||||
__sbi_list_del(entry->prev, entry->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a given entry from list.
|
||||
* @param node Node to be deleted.
|
||||
*/
|
||||
static inline void sbi_list_del(struct sbi_dlist *entry)
|
||||
{
|
||||
__sbi_list_del(entry->prev, entry->next);
|
||||
entry->next = (void *)SBI_LIST_POISON_NEXT;
|
||||
entry->prev = (void *)SBI_LIST_POISON_PREV;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes entry from list and reinitialize it.
|
||||
* @param entry the element to delete from the list.
|
||||
*/
|
||||
static inline void sbi_list_del_init(struct sbi_dlist *entry)
|
||||
{
|
||||
__sbi_list_del_entry(entry);
|
||||
SBI_INIT_LIST_HEAD(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the struct for this entry
|
||||
* @param ptr the &struct list_head pointer.
|
||||
* @param type the type of the struct this is embedded in.
|
||||
* @param member the name of the list_struct within the struct.
|
||||
*/
|
||||
#define sbi_list_entry(ptr, type, member) \
|
||||
container_of(ptr, type, member)
|
||||
|
||||
/**
|
||||
* Get the first element from a list
|
||||
* @param ptr the list head to take the element from.
|
||||
* @param type the type of the struct this is embedded in.
|
||||
* @param member the name of the list_struct within the struct.
|
||||
*
|
||||
* Note: that list is expected to be not empty.
|
||||
*/
|
||||
#define sbi_list_first_entry(ptr, type, member) \
|
||||
sbi_list_entry((ptr)->next, type, member)
|
||||
|
||||
/**
|
||||
* Get the last element from a list
|
||||
* @param ptr the list head to take the element from.
|
||||
* @param type the type of the struct this is embedded in.
|
||||
* @param member the name of the list_head within the struct.
|
||||
*
|
||||
* Note: that list is expected to be not empty.
|
||||
*/
|
||||
#define sbi_list_last_entry(ptr, type, member) \
|
||||
sbi_list_entry((ptr)->prev, type, member)
|
||||
|
||||
/**
|
||||
* Iterate over a list
|
||||
* @param pos the &struct list_head to use as a loop cursor.
|
||||
* @param head the head for your list.
|
||||
*/
|
||||
#define sbi_list_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||
|
||||
/**
|
||||
* Iterate over list of given type
|
||||
* @param pos the type * to use as a loop cursor.
|
||||
* @param head the head for your list.
|
||||
* @param member the name of the list_struct within the struct.
|
||||
*/
|
||||
#define sbi_list_for_each_entry(pos, head, member) \
|
||||
for (pos = sbi_list_entry((head)->next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = sbi_list_entry(pos->member.next, typeof(*pos), member))
|
||||
|
||||
#endif
|
@@ -16,10 +16,12 @@ struct sbi_trap_regs;
|
||||
struct sbi_scratch;
|
||||
|
||||
int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
|
||||
ulong addr, ulong tval2, ulong tinst,
|
||||
struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch);
|
||||
|
||||
int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
|
||||
ulong addr, ulong tval2, ulong tinst,
|
||||
struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch);
|
||||
|
||||
|
@@ -35,10 +35,15 @@
|
||||
/** Offset of firmware_context in struct sbi_platform */
|
||||
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x60 + __SIZEOF_POINTER__)
|
||||
|
||||
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT (1UL << 12)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <sbi/sbi_version.h>
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
#include <sbi/sbi_version.h>
|
||||
|
||||
/** Possible feature flags of a platform */
|
||||
enum sbi_platform_features {
|
||||
@@ -69,6 +74,21 @@ struct sbi_platform_operations {
|
||||
/** Platform final initialization */
|
||||
int (*final_init)(bool cold_boot);
|
||||
|
||||
/** Platform early exit */
|
||||
void (*early_exit)(void);
|
||||
/** Platform final exit */
|
||||
void (*final_exit)(void);
|
||||
|
||||
/** For platforms that do not implement misa, non-standard
|
||||
* methods are needed to determine cpu extension.
|
||||
*/
|
||||
int (*misa_check_extension)(char ext);
|
||||
|
||||
/** For platforms that do not implement misa, non-standard
|
||||
* methods are needed to get MXL field of misa.
|
||||
*/
|
||||
int (*misa_get_xlen)(void);
|
||||
|
||||
/** Get number of PMP regions for given HART */
|
||||
u32 (*pmp_region_count)(u32 hartid);
|
||||
/**
|
||||
@@ -87,15 +107,20 @@ struct sbi_platform_operations {
|
||||
|
||||
/** Initialize the platform interrupt controller for current HART */
|
||||
int (*irqchip_init)(bool cold_boot);
|
||||
/** Exit the platform interrupt controller for current HART */
|
||||
void (*irqchip_exit)(void);
|
||||
|
||||
/** Send IPI to a target HART */
|
||||
void (*ipi_send)(u32 target_hart);
|
||||
/** Wait for target HART to acknowledge IPI */
|
||||
void (*ipi_sync)(u32 target_hart);
|
||||
/** Clear IPI for a target HART */
|
||||
void (*ipi_clear)(u32 target_hart);
|
||||
/** Initialize IPI for current HART */
|
||||
int (*ipi_init)(bool cold_boot);
|
||||
/** Exit IPI for current HART */
|
||||
void (*ipi_exit)(void);
|
||||
|
||||
/** Get tlb flush limit value **/
|
||||
u64 (*get_tlbr_flush_limit)(void);
|
||||
|
||||
/** Get platform timer value */
|
||||
u64 (*timer_value)(void);
|
||||
@@ -105,11 +130,21 @@ struct sbi_platform_operations {
|
||||
void (*timer_event_stop)(void);
|
||||
/** Initialize platform timer for current HART */
|
||||
int (*timer_init)(bool cold_boot);
|
||||
/** Exit platform timer for current HART */
|
||||
void (*timer_exit)(void);
|
||||
|
||||
/** Reboot the platform */
|
||||
int (*system_reboot)(u32 type);
|
||||
/** Shutdown or poweroff the platform */
|
||||
int (*system_shutdown)(u32 type);
|
||||
|
||||
/** platform specific SBI extension implementation probe function */
|
||||
int (*vendor_ext_check)(long extid);
|
||||
/** platform specific SBI extension implementation provider */
|
||||
int (*vendor_ext_provider)(long extid, long funcid,
|
||||
unsigned long *args,
|
||||
unsigned long *out_value,
|
||||
struct sbi_trap_info *out_trap);
|
||||
} __packed;
|
||||
|
||||
/** Representation of a platform */
|
||||
@@ -175,13 +210,13 @@ struct sbi_platform {
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*
|
||||
* @return pointer to platform name on success and NULL on failure
|
||||
* @return pointer to platform name on success and "Unknown" on failure
|
||||
*/
|
||||
static inline const char *sbi_platform_name(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat)
|
||||
return plat->name;
|
||||
return NULL;
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -200,6 +235,22 @@ static inline bool sbi_platform_hart_disabled(const struct sbi_platform *plat,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get platform specific tlb range flush maximum value. Any request with size
|
||||
* higher than this is upgraded to a full flush.
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*
|
||||
* @return tlb range flush limit value. Returns a default (page size) if not
|
||||
* defined by platform.
|
||||
*/
|
||||
static inline u64 sbi_platform_tlbr_flush_limit(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->get_tlbr_flush_limit)
|
||||
return sbi_platform_ops(plat)->get_tlbr_flush_limit();
|
||||
return SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get total number of HARTs supported by the platform
|
||||
*
|
||||
@@ -260,6 +311,58 @@ static inline int sbi_platform_final_init(const struct sbi_platform *plat,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Early exit for current HART
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*/
|
||||
static inline void sbi_platform_early_exit(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->early_exit)
|
||||
sbi_platform_ops(plat)->early_exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Final exit for current HART
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*/
|
||||
static inline void sbi_platform_final_exit(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->final_exit)
|
||||
sbi_platform_ops(plat)->final_exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check CPU extension in MISA
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param ext shorthand letter for CPU extensions
|
||||
*
|
||||
* @return zero for not-supported and non-zero for supported
|
||||
*/
|
||||
static inline int sbi_platform_misa_extension(const struct sbi_platform *plat,
|
||||
char ext)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->misa_check_extension)
|
||||
return sbi_platform_ops(plat)->misa_check_extension(ext);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get MXL field of MISA
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*
|
||||
* @return 1/2/3 on success and error code on failure
|
||||
*/
|
||||
static inline int sbi_platform_misa_xlen(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->misa_get_xlen)
|
||||
return sbi_platform_ops(plat)->misa_get_xlen();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of PMP regions of a HART
|
||||
*
|
||||
@@ -357,6 +460,17 @@ static inline int sbi_platform_irqchip_init(const struct sbi_platform *plat,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit the platform interrupt controller for current HART
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*/
|
||||
static inline void sbi_platform_irqchip_exit(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->irqchip_exit)
|
||||
sbi_platform_ops(plat)->irqchip_exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send IPI to a target HART
|
||||
*
|
||||
@@ -370,19 +484,6 @@ static inline void sbi_platform_ipi_send(const struct sbi_platform *plat,
|
||||
sbi_platform_ops(plat)->ipi_send(target_hart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for target HART to acknowledge IPI
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param target_hart HART ID of IPI target
|
||||
*/
|
||||
static inline void sbi_platform_ipi_sync(const struct sbi_platform *plat,
|
||||
u32 target_hart)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->ipi_sync)
|
||||
sbi_platform_ops(plat)->ipi_sync(target_hart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear IPI for a target HART
|
||||
*
|
||||
@@ -412,12 +513,23 @@ static inline int sbi_platform_ipi_init(const struct sbi_platform *plat,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit the platform IPI support for current HART
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*/
|
||||
static inline void sbi_platform_ipi_exit(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->ipi_exit)
|
||||
sbi_platform_ops(plat)->ipi_exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get platform timer value
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*
|
||||
* @return 64bit timer value
|
||||
* @return 64-bit timer value
|
||||
*/
|
||||
static inline u64 sbi_platform_timer_value(const struct sbi_platform *plat)
|
||||
{
|
||||
@@ -467,6 +579,17 @@ static inline int sbi_platform_timer_init(const struct sbi_platform *plat,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit the platform timer for current HART
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*/
|
||||
static inline void sbi_platform_timer_exit(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->timer_exit)
|
||||
sbi_platform_ops(plat)->timer_exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reboot the platform
|
||||
*
|
||||
@@ -499,6 +622,52 @@ static inline int sbi_platform_system_shutdown(const struct sbi_platform *plat,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a vendor extension is implemented or not.
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param extid vendor SBI extension id
|
||||
*
|
||||
* @return 0 if extid is not implemented and 1 if implemented
|
||||
*/
|
||||
static inline int sbi_platform_vendor_ext_check(const struct sbi_platform *plat,
|
||||
long extid)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->vendor_ext_check)
|
||||
return sbi_platform_ops(plat)->vendor_ext_check(extid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke platform specific vendor SBI extension implementation.
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param extid vendor SBI extension id
|
||||
* @param funcid SBI function id within the extension id
|
||||
* @param args pointer to arguments passed by the caller
|
||||
* @param out_value output value that can be filled by the callee
|
||||
* @param out_trap trap info that can be filled by the callee
|
||||
*
|
||||
* @return 0 on success and negative error code on failure
|
||||
*/
|
||||
static inline int sbi_platform_vendor_ext_provider(
|
||||
const struct sbi_platform *plat,
|
||||
long extid, long funcid,
|
||||
unsigned long *args,
|
||||
unsigned long *out_value,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->vendor_ext_provider) {
|
||||
return sbi_platform_ops(plat)->vendor_ext_provider(extid,
|
||||
funcid, args,
|
||||
out_value,
|
||||
out_trap);
|
||||
}
|
||||
|
||||
return SBI_ENOTSUPP;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@@ -36,7 +36,7 @@
|
||||
#define SBI_SCRATCH_OPTIONS_OFFSET (9 * __SIZEOF_POINTER__)
|
||||
/** Offset of extra space in sbi_scratch */
|
||||
#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (10 * __SIZEOF_POINTER__)
|
||||
/** Maximum size of sbi_scratch and sbi_ipi_data */
|
||||
/** Maximum size of sbi_scratch */
|
||||
#define SBI_SCRATCH_SIZE (64 * __SIZEOF_POINTER__)
|
||||
|
||||
/* clang-format on */
|
||||
@@ -44,7 +44,6 @@
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
#include <sbi/sbi_ipi.h>
|
||||
|
||||
/** Representation of per-HART scratch space */
|
||||
struct sbi_scratch {
|
||||
@@ -74,6 +73,8 @@ struct sbi_scratch {
|
||||
enum sbi_scratch_options {
|
||||
/** Disable prints during boot */
|
||||
SBI_SCRATCH_NO_BOOT_PRINTS = (1 << 0),
|
||||
/** Enable runtime debug prints */
|
||||
SBI_SCRATCH_DEBUG_PRINTS = (1 << 1),
|
||||
};
|
||||
|
||||
/** Get pointer to sbi_scratch for current HART */
|
||||
|
@@ -18,10 +18,12 @@ int sbi_system_early_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||
|
||||
int sbi_system_final_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||
|
||||
void __attribute__((noreturn))
|
||||
sbi_system_reboot(struct sbi_scratch *scratch, u32 type);
|
||||
void sbi_system_early_exit(struct sbi_scratch *scratch);
|
||||
|
||||
void __attribute__((noreturn))
|
||||
sbi_system_shutdown(struct sbi_scratch *scratch, u32 type);
|
||||
void sbi_system_final_exit(struct sbi_scratch *scratch);
|
||||
|
||||
void __noreturn sbi_system_reboot(struct sbi_scratch *scratch, u32 type);
|
||||
|
||||
void __noreturn sbi_system_shutdown(struct sbi_scratch *scratch, u32 type);
|
||||
|
||||
#endif
|
||||
|
@@ -16,7 +16,13 @@ struct sbi_scratch;
|
||||
|
||||
u64 sbi_timer_value(struct sbi_scratch *scratch);
|
||||
|
||||
void sbi_timer_event_stop(struct sbi_scratch *scratch);
|
||||
u64 sbi_timer_virt_value(struct sbi_scratch *scratch);
|
||||
|
||||
u64 sbi_timer_get_delta(struct sbi_scratch *scratch);
|
||||
|
||||
void sbi_timer_set_delta(struct sbi_scratch *scratch, ulong delta);
|
||||
|
||||
void sbi_timer_set_delta_upper(struct sbi_scratch *scratch, ulong delta_upper);
|
||||
|
||||
void sbi_timer_event_start(struct sbi_scratch *scratch, u64 next_event);
|
||||
|
||||
@@ -24,4 +30,6 @@ void sbi_timer_process(struct sbi_scratch *scratch);
|
||||
|
||||
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||
|
||||
void sbi_timer_exit(struct sbi_scratch *scratch);
|
||||
|
||||
#endif
|
||||
|
@@ -16,16 +16,19 @@
|
||||
/* clang-format off */
|
||||
|
||||
#define SBI_TLB_FLUSH_ALL ((unsigned long)-1)
|
||||
#define SBI_TLB_FLUSH_MAX_SIZE (1UL << 30)
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
#define SBI_TLB_FIFO_NUM_ENTRIES 4
|
||||
#define SBI_TLB_FIFO_NUM_ENTRIES 8
|
||||
|
||||
enum sbi_tlb_info_types {
|
||||
SBI_TLB_FLUSH_VMA,
|
||||
SBI_TLB_FLUSH_VMA_ASID,
|
||||
SBI_TLB_FLUSH_VMA_VMID
|
||||
SBI_TLB_FLUSH_GVMA,
|
||||
SBI_TLB_FLUSH_GVMA_VMID,
|
||||
SBI_TLB_FLUSH_VVMA,
|
||||
SBI_TLB_FLUSH_VVMA_ASID,
|
||||
SBI_ITLB_FLUSH
|
||||
};
|
||||
|
||||
struct sbi_scratch;
|
||||
@@ -35,14 +38,14 @@ struct sbi_tlb_info {
|
||||
unsigned long size;
|
||||
unsigned long asid;
|
||||
unsigned long type;
|
||||
unsigned long shart_mask;
|
||||
};
|
||||
|
||||
#define SBI_TLB_INFO_SIZE sizeof(struct sbi_tlb_info)
|
||||
|
||||
int sbi_tlb_fifo_update(struct sbi_scratch *scratch, u32 event, void *data);
|
||||
int sbi_tlb_request(struct sbi_scratch *scratch, ulong hmask,
|
||||
ulong hbase, struct sbi_tlb_info *tinfo);
|
||||
|
||||
void sbi_tlb_fifo_process(struct sbi_scratch *scratch, u32 event);
|
||||
|
||||
int sbi_tlb_fifo_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||
int sbi_tlb_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||
|
||||
#endif
|
||||
|
@@ -80,8 +80,10 @@
|
||||
#define SBI_TRAP_REGS_mepc 32
|
||||
/** Index of mstatus member in sbi_trap_regs */
|
||||
#define SBI_TRAP_REGS_mstatus 33
|
||||
/** Index of mstatusH member in sbi_trap_regs */
|
||||
#define SBI_TRAP_REGS_mstatusH 34
|
||||
/** Last member index in sbi_trap_regs */
|
||||
#define SBI_TRAP_REGS_last 34
|
||||
#define SBI_TRAP_REGS_last 35
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
@@ -164,14 +166,32 @@ struct sbi_trap_regs {
|
||||
unsigned long mepc;
|
||||
/** mstatus register state */
|
||||
unsigned long mstatus;
|
||||
/** mstatusH register state (only for 32-bit) */
|
||||
unsigned long mstatusH;
|
||||
} __packed;
|
||||
|
||||
/** Representation of trap details */
|
||||
struct sbi_trap_info {
|
||||
/** epc Trap program counter */
|
||||
unsigned long epc;
|
||||
/** cause Trap exception cause */
|
||||
unsigned long cause;
|
||||
/** tval Trap value */
|
||||
unsigned long tval;
|
||||
/** tval2 Trap value 2 */
|
||||
unsigned long tval2;
|
||||
/** tinst Trap instruction */
|
||||
unsigned long tinst;
|
||||
};
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch,
|
||||
ulong epc, ulong cause, ulong tval);
|
||||
int sbi_trap_redirect(struct sbi_trap_regs *regs,
|
||||
struct sbi_trap_info *trap,
|
||||
struct sbi_scratch *scratch);
|
||||
|
||||
void sbi_trap_handler(struct sbi_trap_regs *regs, struct sbi_scratch *scratch);
|
||||
void sbi_trap_handler(struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch);
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -10,6 +10,8 @@
|
||||
#ifndef __SBI_TYPES_H__
|
||||
#define __SBI_TYPES_H__
|
||||
|
||||
#ifndef OPENSBI_EXTERNAL_SBI_TYPES
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
typedef char s8;
|
||||
@@ -60,6 +62,43 @@ typedef unsigned long physical_size_t;
|
||||
#define __packed __attribute__((packed))
|
||||
#define __noreturn __attribute__((noreturn))
|
||||
|
||||
#define likely(x) __builtin_expect((x), 1)
|
||||
#define unlikely(x) __builtin_expect((x), 0)
|
||||
|
||||
#undef offsetof
|
||||
#ifdef __compiler_offsetof
|
||||
#define offsetof(TYPE, MEMBER) __compiler_offsetof(TYPE,MEMBER)
|
||||
#else
|
||||
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||
#endif
|
||||
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
const typeof(((type *)0)->member) * __mptr = (ptr); \
|
||||
(type *)((char *)__mptr - offsetof(type, member)); })
|
||||
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define CLAMP(a, lo, hi) MIN(MAX(a, lo), hi)
|
||||
|
||||
#define STR(x) XSTR(x)
|
||||
#define XSTR(x) #x
|
||||
|
||||
#define ROUNDUP(a, b) ((((a)-1) / (b) + 1) * (b))
|
||||
#define ROUNDDOWN(a, b) ((a) / (b) * (b))
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
#else
|
||||
/* OPENSBI_EXTERNAL_SBI_TYPES could be defined in CFLAGS for using the
|
||||
* external definitions of data types and common macros.
|
||||
* OPENSBI_EXTERNAL_SBI_TYPES is the file name to external header file,
|
||||
* the external build system should address the additional include
|
||||
* directory ccordingly.
|
||||
*/
|
||||
|
||||
#define XSTR(x) #x
|
||||
#define STR(x) XSTR(x)
|
||||
#include STR(OPENSBI_EXTERNAL_SBI_TYPES)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@@ -7,28 +7,23 @@
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __RISCV_UNPRIV_H__
|
||||
#define __RISCV_UNPRIV_H__
|
||||
#ifndef __SBI_UNPRIV_H__
|
||||
#define __SBI_UNPRIV_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
struct unpriv_trap {
|
||||
unsigned long ilen;
|
||||
unsigned long cause;
|
||||
unsigned long tval;
|
||||
};
|
||||
struct sbi_trap_info;
|
||||
|
||||
#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type) \
|
||||
type load_##type(const type *addr, \
|
||||
type sbi_load_##type(const type *addr, \
|
||||
struct sbi_scratch *scratch, \
|
||||
struct unpriv_trap *trap);
|
||||
struct sbi_trap_info *trap);
|
||||
|
||||
#define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type) \
|
||||
void store_##type(type *addr, type val, \
|
||||
void sbi_store_##type(type *addr, type val, \
|
||||
struct sbi_scratch *scratch, \
|
||||
struct unpriv_trap *trap);
|
||||
struct sbi_trap_info *trap);
|
||||
|
||||
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u8)
|
||||
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u16)
|
||||
@@ -43,6 +38,7 @@ DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u64)
|
||||
DECLARE_UNPRIVILEGED_STORE_FUNCTION(u64)
|
||||
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong)
|
||||
|
||||
ulong get_insn(ulong mepc, ulong *mstatus);
|
||||
ulong sbi_get_insn(ulong mepc, struct sbi_scratch *scratch,
|
||||
struct sbi_trap_info *trap);
|
||||
|
||||
#endif
|
@@ -11,7 +11,7 @@
|
||||
#define __SBI_VERSION_H__
|
||||
|
||||
#define OPENSBI_VERSION_MAJOR 0
|
||||
#define OPENSBI_VERSION_MINOR 4
|
||||
#define OPENSBI_VERSION_MINOR 6
|
||||
|
||||
/**
|
||||
* OpenSBI 32-bit version with:
|
||||
|
@@ -30,6 +30,7 @@ void clint_timer_event_start(u64 next_event);
|
||||
|
||||
int clint_warm_timer_init(void);
|
||||
|
||||
int clint_cold_timer_init(unsigned long base, u32 hart_count);
|
||||
int clint_cold_timer_init(unsigned long base, u32 hart_count,
|
||||
bool has_64bit_mmio);
|
||||
|
||||
#endif
|
||||
|
19
include/sbi_utils/sys/htif.h
Normal file
19
include/sbi_utils/sys/htif.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (c) 2010-2020, The Regents of the University of California
|
||||
* (Regents). All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef __SYS_HTIF_H__
|
||||
#define __SYS_HTIF_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
void htif_putc(char ch);
|
||||
|
||||
int htif_getc(void);
|
||||
|
||||
int htif_system_down(u32 type);
|
||||
|
||||
#endif
|
@@ -11,12 +11,16 @@ libsbi-objs-y += riscv_asm.o
|
||||
libsbi-objs-y += riscv_atomic.o
|
||||
libsbi-objs-y += riscv_hardfp.o
|
||||
libsbi-objs-y += riscv_locks.o
|
||||
libsbi-objs-y += riscv_unpriv.o
|
||||
|
||||
libsbi-objs-y += sbi_console.o
|
||||
libsbi-objs-y += sbi_ecall.o
|
||||
libsbi-objs-y += sbi_ecall_base.o
|
||||
libsbi-objs-y += sbi_ecall_legacy.o
|
||||
libsbi-objs-y += sbi_ecall_replace.o
|
||||
libsbi-objs-y += sbi_ecall_vendor.o
|
||||
libsbi-objs-y += sbi_emulate_csr.o
|
||||
libsbi-objs-y += sbi_fifo.o
|
||||
libsbi-objs-y += sbi_hfence.o
|
||||
libsbi-objs-y += sbi_hart.o
|
||||
libsbi-objs-y += sbi_illegal_insn.o
|
||||
libsbi-objs-y += sbi_init.o
|
||||
@@ -28,3 +32,4 @@ libsbi-objs-y += sbi_timer.o
|
||||
libsbi-objs-y += sbi_tlb.o
|
||||
libsbi-objs-y += sbi_trap.o
|
||||
libsbi-objs-y += sbi_string.o
|
||||
libsbi-objs-y += sbi_unpriv.o
|
||||
|
@@ -10,6 +10,39 @@
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
|
||||
/* determine CPU extension, return non-zero support */
|
||||
int misa_extension_imp(char ext)
|
||||
{
|
||||
unsigned long misa = csr_read(CSR_MISA);
|
||||
|
||||
if (misa)
|
||||
return misa & (1 << (ext - 'A'));
|
||||
|
||||
return sbi_platform_misa_extension(sbi_platform_thishart_ptr(), ext);
|
||||
}
|
||||
|
||||
int misa_xlen(void)
|
||||
{
|
||||
long r;
|
||||
|
||||
if (csr_read(CSR_MISA) == 0)
|
||||
return sbi_platform_misa_xlen(sbi_platform_thishart_ptr());
|
||||
|
||||
__asm__ __volatile__(
|
||||
"csrr t0, misa\n\t"
|
||||
"slti t1, t0, 0\n\t"
|
||||
"slli t1, t1, 1\n\t"
|
||||
"slli t0, t0, 1\n\t"
|
||||
"slti t0, t0, 0\n\t"
|
||||
"add %0, t0, t1"
|
||||
: "=r"(r)
|
||||
:
|
||||
: "t0", "t1");
|
||||
|
||||
return r ? r : -1;
|
||||
}
|
||||
|
||||
unsigned long csr_read_num(int csr_num)
|
||||
{
|
||||
|
@@ -50,6 +50,39 @@ long atomic_sub_return(atomic_t *atom, long value)
|
||||
return ret - value;
|
||||
}
|
||||
|
||||
#define __axchg(ptr, new, size) \
|
||||
({ \
|
||||
__typeof__(ptr) __ptr = (ptr); \
|
||||
__typeof__(new) __new = (new); \
|
||||
__typeof__(*(ptr)) __ret; \
|
||||
switch (size) { \
|
||||
case 4: \
|
||||
__asm__ __volatile__ ( \
|
||||
" amoswap.w.aqrl %0, %2, %1\n" \
|
||||
: "=r" (__ret), "+A" (*__ptr) \
|
||||
: "r" (__new) \
|
||||
: "memory"); \
|
||||
break; \
|
||||
case 8: \
|
||||
__asm__ __volatile__ ( \
|
||||
" amoswap.d.aqrl %0, %2, %1\n" \
|
||||
: "=r" (__ret), "+A" (*__ptr) \
|
||||
: "r" (__new) \
|
||||
: "memory"); \
|
||||
break; \
|
||||
default: \
|
||||
break; \
|
||||
} \
|
||||
__ret; \
|
||||
})
|
||||
|
||||
#define axchg(ptr, x) \
|
||||
({ \
|
||||
__typeof__(*(ptr)) _x_ = (x); \
|
||||
(__typeof__(*(ptr))) __axchg((ptr), _x_, sizeof(*(ptr))); \
|
||||
})
|
||||
|
||||
|
||||
#define __xchg(ptr, new, size) \
|
||||
({ \
|
||||
__typeof__(ptr) __ptr = (ptr); \
|
||||
@@ -148,12 +181,7 @@ long arch_atomic_xchg(atomic_t *atom, long newval)
|
||||
{
|
||||
/* Atomically set new value and return old value. */
|
||||
#ifdef __riscv_atomic
|
||||
/*
|
||||
* The name of GCC built-in macro __sync_lock_test_and_set()
|
||||
* is misleading. A more appropriate name for GCC built-in
|
||||
* macro would be __sync_val_exchange().
|
||||
*/
|
||||
return __sync_lock_test_and_set(&atom->counter, newval);
|
||||
return axchg(&atom->counter, newval);
|
||||
#else
|
||||
return xchg(&atom->counter, newval);
|
||||
#endif
|
||||
@@ -164,12 +192,18 @@ unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
|
||||
{
|
||||
/* Atomically set new value and return old value. */
|
||||
#ifdef __riscv_atomic
|
||||
/*
|
||||
* The name of GCC built-in macro __sync_lock_test_and_set()
|
||||
* is misleading. A more appropriate name for GCC built-in
|
||||
* macro would be __sync_val_exchange().
|
||||
*/
|
||||
return __sync_lock_test_and_set(ptr, newval);
|
||||
return axchg(ptr, newval);
|
||||
#else
|
||||
return xchg(ptr, newval);
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned long atomic_raw_xchg_ulong(volatile unsigned long *ptr,
|
||||
unsigned long newval)
|
||||
{
|
||||
/* Atomically set new value and return old value. */
|
||||
#ifdef __riscv_atomic
|
||||
return axchg(ptr, newval);
|
||||
#else
|
||||
return xchg(ptr, newval);
|
||||
#endif
|
||||
|
@@ -1,145 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include <sbi/riscv_unpriv.h>
|
||||
#include <sbi/sbi_bits.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
|
||||
#define DEFINE_UNPRIVILEGED_LOAD_FUNCTION(type, insn, insnlen) \
|
||||
type load_##type(const type *addr, \
|
||||
struct sbi_scratch *scratch, \
|
||||
struct unpriv_trap *trap) \
|
||||
{ \
|
||||
register ulong __mstatus asm("a2"); \
|
||||
type val = 0; \
|
||||
trap->ilen = insnlen; \
|
||||
trap->cause = 0; \
|
||||
trap->tval = 0; \
|
||||
sbi_hart_set_trap_info(scratch, trap); \
|
||||
asm volatile( \
|
||||
"csrrs %0, " STR(CSR_MSTATUS) ", %3\n" \
|
||||
#insn " %1, %2\n" \
|
||||
"csrw " STR(CSR_MSTATUS) ", %0" \
|
||||
: "+&r"(__mstatus), "=&r"(val) \
|
||||
: "m"(*addr), "r"(MSTATUS_MPRV)); \
|
||||
sbi_hart_set_trap_info(scratch, NULL); \
|
||||
return val; \
|
||||
}
|
||||
|
||||
#define DEFINE_UNPRIVILEGED_STORE_FUNCTION(type, insn, insnlen) \
|
||||
void store_##type(type *addr, type val, \
|
||||
struct sbi_scratch *scratch, \
|
||||
struct unpriv_trap *trap) \
|
||||
{ \
|
||||
register ulong __mstatus asm("a3"); \
|
||||
trap->ilen = insnlen; \
|
||||
trap->cause = 0; \
|
||||
trap->tval = 0; \
|
||||
sbi_hart_set_trap_info(scratch, trap); \
|
||||
asm volatile( \
|
||||
"csrrs %0, " STR(CSR_MSTATUS) ", %3\n" \
|
||||
#insn " %1, %2\n" \
|
||||
"csrw " STR(CSR_MSTATUS) ", %0" \
|
||||
: "+&r"(__mstatus) \
|
||||
: "r"(val), "m"(*addr), "r"(MSTATUS_MPRV)); \
|
||||
sbi_hart_set_trap_info(scratch, NULL); \
|
||||
}
|
||||
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu, 4)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u16, lhu, 4)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s8, lb, 4)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s16, lh, 4)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s32, lw, 2)
|
||||
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u8, sb, 4)
|
||||
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u16, sh, 4)
|
||||
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u32, sw, 2)
|
||||
#if __riscv_xlen == 64
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu, 4)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld, 2)
|
||||
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u64, sd, 2)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld, 2)
|
||||
#else
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw, 2)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw, 2)
|
||||
|
||||
u64 load_u64(const u64 *addr,
|
||||
struct sbi_scratch *scratch, struct unpriv_trap *trap)
|
||||
{
|
||||
u64 ret = load_u32((u32 *)addr, scratch, trap);
|
||||
|
||||
if (trap->cause)
|
||||
return 0;
|
||||
ret |= ((u64)load_u32((u32 *)addr + 1, scratch, trap) << 32);
|
||||
if (trap->cause)
|
||||
return 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void store_u64(u64 *addr, u64 val,
|
||||
struct sbi_scratch *scratch, struct unpriv_trap *trap)
|
||||
{
|
||||
store_u32((u32 *)addr, val, scratch, trap);
|
||||
if (trap->cause)
|
||||
return;
|
||||
|
||||
store_u32((u32 *)addr + 1, val >> 32, scratch, trap);
|
||||
if (trap->cause)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
ulong get_insn(ulong mepc, ulong *mstatus)
|
||||
{
|
||||
register ulong __mepc asm("a2") = mepc;
|
||||
register ulong __mstatus asm("a3");
|
||||
ulong val;
|
||||
#ifndef __riscv_compressed
|
||||
asm("csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n"
|
||||
#if __riscv_xlen == 64
|
||||
STR(LWU) " %[insn], (%[addr])\n"
|
||||
#else
|
||||
STR(LW) " %[insn], (%[addr])\n"
|
||||
#endif
|
||||
"csrw " STR(CSR_MSTATUS) ", %[mstatus]"
|
||||
: [mstatus] "+&r"(__mstatus), [insn] "=&r"(val)
|
||||
: [mprv] "r"(MSTATUS_MPRV | MSTATUS_MXR), [addr] "r"(__mepc));
|
||||
#else
|
||||
ulong rvc_mask = 3, tmp;
|
||||
asm("csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n"
|
||||
"and %[tmp], %[addr], 2\n"
|
||||
"bnez %[tmp], 1f\n"
|
||||
#if __riscv_xlen == 64
|
||||
STR(LWU) " %[insn], (%[addr])\n"
|
||||
#else
|
||||
STR(LW) " %[insn], (%[addr])\n"
|
||||
#endif
|
||||
"and %[tmp], %[insn], %[rvc_mask]\n"
|
||||
"beq %[tmp], %[rvc_mask], 2f\n"
|
||||
"sll %[insn], %[insn], %[xlen_minus_16]\n"
|
||||
"srl %[insn], %[insn], %[xlen_minus_16]\n"
|
||||
"j 2f\n"
|
||||
"1:\n"
|
||||
"lhu %[insn], (%[addr])\n"
|
||||
"and %[tmp], %[insn], %[rvc_mask]\n"
|
||||
"bne %[tmp], %[rvc_mask], 2f\n"
|
||||
"lhu %[tmp], 2(%[addr])\n"
|
||||
"sll %[tmp], %[tmp], 16\n"
|
||||
"add %[insn], %[insn], %[tmp]\n"
|
||||
"2: csrw " STR(CSR_MSTATUS) ", %[mstatus]"
|
||||
: [mstatus] "+&r"(__mstatus), [insn] "=&r"(val), [tmp] "=&r"(tmp)
|
||||
: [mprv] "r"(MSTATUS_MPRV | MSTATUS_MXR), [addr] "r"(__mepc),
|
||||
[rvc_mask] "r"(rvc_mask), [xlen_minus_16] "i"(__riscv_xlen - 16));
|
||||
#endif
|
||||
if (mstatus)
|
||||
*mstatus = __mstatus;
|
||||
return val;
|
||||
}
|
@@ -375,6 +375,19 @@ int sbi_printf(const char *format, ...)
|
||||
return retval;
|
||||
}
|
||||
|
||||
int sbi_dprintf(struct sbi_scratch *scratch, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int retval = 0;
|
||||
|
||||
va_start(args, format);
|
||||
if (scratch->options & SBI_SCRATCH_DEBUG_PRINTS)
|
||||
retval = print(NULL, NULL, format, args);
|
||||
va_end(args);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int sbi_console_init(struct sbi_scratch *scratch)
|
||||
{
|
||||
console_plat = sbi_platform_ptr(scratch);
|
||||
|
@@ -7,19 +7,11 @@
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_ipi.h>
|
||||
#include <sbi/sbi_system.h>
|
||||
#include <sbi/sbi_timer.h>
|
||||
#include <sbi/sbi_tlb.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
|
||||
#define SBI_ECALL_VERSION_MAJOR 0
|
||||
#define SBI_ECALL_VERSION_MINOR 1
|
||||
|
||||
u16 sbi_ecall_version_major(void)
|
||||
{
|
||||
return SBI_ECALL_VERSION_MAJOR;
|
||||
@@ -30,78 +22,128 @@ u16 sbi_ecall_version_minor(void)
|
||||
return SBI_ECALL_VERSION_MINOR;
|
||||
}
|
||||
|
||||
int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch)
|
||||
static SBI_LIST_HEAD(ecall_exts_list);
|
||||
|
||||
struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
|
||||
{
|
||||
int ret = SBI_ENOTSUPP;
|
||||
struct unpriv_trap uptrap;
|
||||
struct sbi_tlb_info tlb_info;
|
||||
struct sbi_ecall_extension *t, *ret = NULL;
|
||||
|
||||
switch (regs->a7) {
|
||||
case SBI_ECALL_SET_TIMER:
|
||||
#if __riscv_xlen == 32
|
||||
sbi_timer_event_start(scratch,
|
||||
(((u64)regs->a1 << 32) | (u64)regs->a0));
|
||||
#else
|
||||
sbi_timer_event_start(scratch, (u64)regs->a0);
|
||||
#endif
|
||||
ret = 0;
|
||||
sbi_list_for_each_entry(t, &ecall_exts_list, head) {
|
||||
if (t->extid_start <= extid && extid <= t->extid_end) {
|
||||
ret = t;
|
||||
break;
|
||||
case SBI_ECALL_CONSOLE_PUTCHAR:
|
||||
sbi_putc(regs->a0);
|
||||
ret = 0;
|
||||
break;
|
||||
case SBI_ECALL_CONSOLE_GETCHAR:
|
||||
regs->a0 = sbi_getc();
|
||||
ret = 0;
|
||||
break;
|
||||
case SBI_ECALL_CLEAR_IPI:
|
||||
sbi_ipi_clear_smode(scratch);
|
||||
ret = 0;
|
||||
break;
|
||||
case SBI_ECALL_SEND_IPI:
|
||||
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)regs->a0,
|
||||
SBI_IPI_EVENT_SOFT, NULL);
|
||||
break;
|
||||
case SBI_ECALL_REMOTE_FENCE_I:
|
||||
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)regs->a0,
|
||||
SBI_IPI_EVENT_FENCE_I, NULL);
|
||||
break;
|
||||
case SBI_ECALL_REMOTE_SFENCE_VMA:
|
||||
tlb_info.start = (unsigned long)regs->a1;
|
||||
tlb_info.size = (unsigned long)regs->a2;
|
||||
tlb_info.type = SBI_TLB_FLUSH_VMA;
|
||||
|
||||
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)regs->a0,
|
||||
SBI_IPI_EVENT_SFENCE_VMA, &tlb_info);
|
||||
break;
|
||||
case SBI_ECALL_REMOTE_SFENCE_VMA_ASID:
|
||||
tlb_info.start = (unsigned long)regs->a1;
|
||||
tlb_info.size = (unsigned long)regs->a2;
|
||||
tlb_info.asid = (unsigned long)regs->a3;
|
||||
tlb_info.type = SBI_TLB_FLUSH_VMA_ASID;
|
||||
|
||||
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)regs->a0,
|
||||
SBI_IPI_EVENT_SFENCE_VMA_ASID,
|
||||
&tlb_info);
|
||||
break;
|
||||
case SBI_ECALL_SHUTDOWN:
|
||||
sbi_system_shutdown(scratch, 0);
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
regs->a0 = SBI_ENOTSUPP;
|
||||
ret = 0;
|
||||
break;
|
||||
};
|
||||
|
||||
if (!ret) {
|
||||
regs->mepc += 4;
|
||||
} else if (ret == SBI_ETRAP) {
|
||||
ret = 0;
|
||||
sbi_trap_redirect(regs, scratch, regs->mepc,
|
||||
uptrap.cause, uptrap.tval);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)
|
||||
{
|
||||
if (!ext || (ext->extid_end < ext->extid_start) || !ext->handle)
|
||||
return SBI_EINVAL;
|
||||
if (sbi_ecall_find_extension(ext->extid_start) ||
|
||||
sbi_ecall_find_extension(ext->extid_end))
|
||||
return SBI_EINVAL;
|
||||
|
||||
SBI_INIT_LIST_HEAD(&ext->head);
|
||||
sbi_list_add_tail(&ext->head, &ecall_exts_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sbi_ecall_unregister_extension(struct sbi_ecall_extension *ext)
|
||||
{
|
||||
bool found = FALSE;
|
||||
struct sbi_ecall_extension *t;
|
||||
|
||||
if (!ext)
|
||||
return;
|
||||
|
||||
sbi_list_for_each_entry(t, &ecall_exts_list, head) {
|
||||
if (t == ext) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
sbi_list_del_init(&ext->head);
|
||||
}
|
||||
|
||||
int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch)
|
||||
{
|
||||
int ret = 0;
|
||||
struct sbi_ecall_extension *ext;
|
||||
unsigned long extension_id = regs->a7;
|
||||
unsigned long func_id = regs->a6;
|
||||
struct sbi_trap_info trap = {0};
|
||||
unsigned long out_val = 0;
|
||||
bool is_0_1_spec = 0;
|
||||
unsigned long args[6];
|
||||
|
||||
args[0] = regs->a0;
|
||||
args[1] = regs->a1;
|
||||
args[2] = regs->a2;
|
||||
args[3] = regs->a3;
|
||||
args[4] = regs->a4;
|
||||
args[5] = regs->a5;
|
||||
|
||||
ext = sbi_ecall_find_extension(extension_id);
|
||||
if (ext && ext->handle) {
|
||||
ret = ext->handle(scratch, extension_id, func_id,
|
||||
args, &out_val, &trap);
|
||||
if (extension_id >= SBI_EXT_0_1_SET_TIMER &&
|
||||
extension_id <= SBI_EXT_0_1_SHUTDOWN)
|
||||
is_0_1_spec = 1;
|
||||
} else {
|
||||
ret = SBI_ENOTSUPP;
|
||||
}
|
||||
|
||||
if (ret == SBI_ETRAP) {
|
||||
trap.epc = regs->mepc;
|
||||
sbi_trap_redirect(regs, &trap, scratch);
|
||||
} else {
|
||||
/* This function should return non-zero value only in case of
|
||||
* fatal error. However, there is no good way to distinguish
|
||||
* between a fatal and non-fatal errors yet. That's why we treat
|
||||
* every return value except ETRAP as non-fatal and just return
|
||||
* accordingly for now. Once fatal errors are defined, that
|
||||
* case should be handled differently.
|
||||
*/
|
||||
regs->mepc += 4;
|
||||
regs->a0 = ret;
|
||||
if (!is_0_1_spec)
|
||||
regs->a1 = out_val;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sbi_ecall_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* The order of below registrations is performance optimized */
|
||||
ret = sbi_ecall_register_extension(&ecall_time);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = sbi_ecall_register_extension(&ecall_rfence);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = sbi_ecall_register_extension(&ecall_ipi);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = sbi_ecall_register_extension(&ecall_base);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = sbi_ecall_register_extension(&ecall_legacy);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = sbi_ecall_register_extension(&ecall_vendor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
80
lib/sbi/sbi_ecall_base.c
Normal file
80
lib/sbi/sbi_ecall_base.c
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
* Atish Patra <atish.patra@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_version.h>
|
||||
#include <sbi/riscv_asm.h>
|
||||
|
||||
static int sbi_ecall_base_probe(struct sbi_scratch *scratch,
|
||||
unsigned long extid,
|
||||
unsigned long *out_val)
|
||||
{
|
||||
struct sbi_ecall_extension *ext;
|
||||
|
||||
ext = sbi_ecall_find_extension(extid);
|
||||
if (!ext) {
|
||||
*out_val = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ext->probe)
|
||||
return ext->probe(scratch, extid, out_val);
|
||||
|
||||
*out_val = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sbi_ecall_base_handler(struct sbi_scratch *scratch,
|
||||
unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (funcid) {
|
||||
case SBI_EXT_BASE_GET_SPEC_VERSION:
|
||||
*out_val = (SBI_ECALL_VERSION_MAJOR <<
|
||||
SBI_SPEC_VERSION_MAJOR_OFFSET) &
|
||||
(SBI_SPEC_VERSION_MAJOR_MASK <<
|
||||
SBI_SPEC_VERSION_MAJOR_OFFSET);
|
||||
*out_val = *out_val | SBI_ECALL_VERSION_MINOR;
|
||||
break;
|
||||
case SBI_EXT_BASE_GET_IMP_ID:
|
||||
*out_val = SBI_OPENSBI_IMPID;
|
||||
break;
|
||||
case SBI_EXT_BASE_GET_IMP_VERSION:
|
||||
*out_val = OPENSBI_VERSION;
|
||||
break;
|
||||
case SBI_EXT_BASE_GET_MVENDORID:
|
||||
*out_val = csr_read(CSR_MVENDORID);
|
||||
break;
|
||||
case SBI_EXT_BASE_GET_MARCHID:
|
||||
*out_val = csr_read(CSR_MARCHID);
|
||||
break;
|
||||
case SBI_EXT_BASE_GET_MIMPID:
|
||||
*out_val = csr_read(CSR_MIMPID);
|
||||
break;
|
||||
case SBI_EXT_BASE_PROBE_EXT:
|
||||
ret = sbi_ecall_base_probe(scratch, args[0], out_val);
|
||||
break;
|
||||
default:
|
||||
ret = SBI_ENOTSUPP;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct sbi_ecall_extension ecall_base = {
|
||||
.extid_start = SBI_EXT_BASE,
|
||||
.extid_end = SBI_EXT_BASE,
|
||||
.handle = sbi_ecall_base_handler,
|
||||
};
|
119
lib/sbi/sbi_ecall_legacy.c
Normal file
119
lib/sbi/sbi_ecall_legacy.c
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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_console.h>
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_ipi.h>
|
||||
#include <sbi/sbi_system.h>
|
||||
#include <sbi/sbi_timer.h>
|
||||
#include <sbi/sbi_tlb.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
#include <sbi/sbi_unpriv.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
|
||||
static int sbi_load_hart_mask_unpriv(struct sbi_scratch *scratch,
|
||||
ulong *pmask, ulong *hmask,
|
||||
struct sbi_trap_info *uptrap)
|
||||
{
|
||||
ulong mask = 0;
|
||||
|
||||
if (pmask) {
|
||||
mask = sbi_load_ulong(pmask, scratch, uptrap);
|
||||
if (uptrap->cause)
|
||||
return SBI_ETRAP;
|
||||
} else {
|
||||
mask = sbi_hart_available_mask();
|
||||
}
|
||||
*hmask = mask;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sbi_ecall_legacy_handler(struct sbi_scratch *scratch,
|
||||
unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
int ret = 0;
|
||||
struct sbi_tlb_info tlb_info;
|
||||
u32 source_hart = sbi_current_hartid();
|
||||
ulong hmask = 0;
|
||||
|
||||
switch (extid) {
|
||||
case SBI_EXT_0_1_SET_TIMER:
|
||||
#if __riscv_xlen == 32
|
||||
sbi_timer_event_start(scratch,
|
||||
(((u64)args[1] << 32) | (u64)args[0]));
|
||||
#else
|
||||
sbi_timer_event_start(scratch, (u64)args[0]);
|
||||
#endif
|
||||
break;
|
||||
case SBI_EXT_0_1_CONSOLE_PUTCHAR:
|
||||
sbi_putc(args[0]);
|
||||
break;
|
||||
case SBI_EXT_0_1_CONSOLE_GETCHAR:
|
||||
ret = sbi_getc();
|
||||
break;
|
||||
case SBI_EXT_0_1_CLEAR_IPI:
|
||||
sbi_ipi_clear_smode(scratch);
|
||||
break;
|
||||
case SBI_EXT_0_1_SEND_IPI:
|
||||
ret = sbi_load_hart_mask_unpriv(scratch, (ulong *)args[0],
|
||||
&hmask, out_trap);
|
||||
if (ret != SBI_ETRAP)
|
||||
ret = sbi_ipi_send_smode(scratch, hmask, 0);
|
||||
break;
|
||||
case SBI_EXT_0_1_REMOTE_FENCE_I:
|
||||
tlb_info.start = 0;
|
||||
tlb_info.size = 0;
|
||||
tlb_info.type = SBI_ITLB_FLUSH;
|
||||
tlb_info.shart_mask = 1UL << source_hart;
|
||||
ret = sbi_load_hart_mask_unpriv(scratch, (ulong *)args[0],
|
||||
&hmask, out_trap);
|
||||
if (ret != SBI_ETRAP)
|
||||
ret = sbi_tlb_request(scratch, hmask, 0, &tlb_info);
|
||||
break;
|
||||
case SBI_EXT_0_1_REMOTE_SFENCE_VMA:
|
||||
tlb_info.start = (unsigned long)args[1];
|
||||
tlb_info.size = (unsigned long)args[2];
|
||||
tlb_info.type = SBI_TLB_FLUSH_VMA;
|
||||
tlb_info.shart_mask = 1UL << source_hart;
|
||||
ret = sbi_load_hart_mask_unpriv(scratch, (ulong *)args[0],
|
||||
&hmask, out_trap);
|
||||
if (ret != SBI_ETRAP)
|
||||
ret = sbi_tlb_request(scratch, hmask, 0, &tlb_info);
|
||||
break;
|
||||
case SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID:
|
||||
tlb_info.start = (unsigned long)args[1];
|
||||
tlb_info.size = (unsigned long)args[2];
|
||||
tlb_info.asid = (unsigned long)args[3];
|
||||
tlb_info.type = SBI_TLB_FLUSH_VMA_ASID;
|
||||
tlb_info.shart_mask = 1UL << source_hart;
|
||||
ret = sbi_load_hart_mask_unpriv(scratch, (ulong *)args[0],
|
||||
&hmask, out_trap);
|
||||
if (ret != SBI_ETRAP)
|
||||
ret = sbi_tlb_request(scratch, hmask, 0, &tlb_info);
|
||||
break;
|
||||
case SBI_EXT_0_1_SHUTDOWN:
|
||||
sbi_system_shutdown(scratch, 0);
|
||||
break;
|
||||
default:
|
||||
ret = SBI_ENOTSUPP;
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct sbi_ecall_extension ecall_legacy = {
|
||||
.extid_start = SBI_EXT_0_1_SET_TIMER,
|
||||
.extid_end = SBI_EXT_0_1_SHUTDOWN,
|
||||
.handle = sbi_ecall_legacy_handler,
|
||||
};
|
146
lib/sbi/sbi_ecall_replace.c
Normal file
146
lib/sbi/sbi_ecall_replace.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
* Atish Patra <atish.patra@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_ipi.h>
|
||||
#include <sbi/sbi_timer.h>
|
||||
#include <sbi/sbi_tlb.h>
|
||||
#include <sbi/riscv_asm.h>
|
||||
|
||||
static int sbi_ecall_time_handler(struct sbi_scratch *scratch,
|
||||
unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (funcid == SBI_EXT_TIME_SET_TIMER) {
|
||||
#if __riscv_xlen == 32
|
||||
sbi_timer_event_start(scratch,
|
||||
(((u64)args[1] << 32) | (u64)args[0]));
|
||||
#else
|
||||
sbi_timer_event_start(scratch, (u64)args[0]);
|
||||
#endif
|
||||
} else
|
||||
ret = SBI_ENOTSUPP;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct sbi_ecall_extension ecall_time = {
|
||||
.extid_start = SBI_EXT_TIME,
|
||||
.extid_end = SBI_EXT_TIME,
|
||||
.handle = sbi_ecall_time_handler,
|
||||
};
|
||||
|
||||
static int sbi_ecall_rfence_handler(struct sbi_scratch *scratch,
|
||||
unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
int ret = 0;
|
||||
struct sbi_tlb_info tlb_info;
|
||||
u32 source_hart = sbi_current_hartid();
|
||||
|
||||
if (funcid >= SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA &&
|
||||
funcid <= SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID)
|
||||
if (!misa_extension('H'))
|
||||
return SBI_ENOTSUPP;
|
||||
|
||||
switch (funcid) {
|
||||
case SBI_EXT_RFENCE_REMOTE_FENCE_I:
|
||||
tlb_info.start = 0;
|
||||
tlb_info.size = 0;
|
||||
tlb_info.type = SBI_ITLB_FLUSH;
|
||||
tlb_info.shart_mask = 1UL << source_hart;
|
||||
ret = sbi_tlb_request(scratch, args[0], args[1], &tlb_info);
|
||||
break;
|
||||
case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA:
|
||||
tlb_info.start = (unsigned long)args[2];
|
||||
tlb_info.size = (unsigned long)args[3];
|
||||
tlb_info.type = SBI_TLB_FLUSH_GVMA;
|
||||
tlb_info.shart_mask = 1UL << source_hart;
|
||||
ret = sbi_tlb_request(scratch, args[0], args[1], &tlb_info);
|
||||
break;
|
||||
case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID:
|
||||
tlb_info.start = (unsigned long)args[2];
|
||||
tlb_info.size = (unsigned long)args[3];
|
||||
tlb_info.asid = (unsigned long)args[4];
|
||||
tlb_info.type = SBI_TLB_FLUSH_GVMA_VMID;
|
||||
tlb_info.shart_mask = 1UL << source_hart;
|
||||
ret = sbi_tlb_request(scratch, args[0], args[1], &tlb_info);
|
||||
break;
|
||||
case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA:
|
||||
tlb_info.start = (unsigned long)args[2];
|
||||
tlb_info.size = (unsigned long)args[3];
|
||||
tlb_info.type = SBI_TLB_FLUSH_VVMA;
|
||||
tlb_info.shart_mask = 1UL << source_hart;
|
||||
ret = sbi_tlb_request(scratch, args[0], args[1], &tlb_info);
|
||||
break;
|
||||
case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID:
|
||||
tlb_info.start = (unsigned long)args[2];
|
||||
tlb_info.size = (unsigned long)args[3];
|
||||
tlb_info.asid = (unsigned long)args[4];
|
||||
tlb_info.type = SBI_TLB_FLUSH_VVMA_ASID;
|
||||
tlb_info.shart_mask = 1UL << source_hart;
|
||||
ret = sbi_tlb_request(scratch, args[0], args[1], &tlb_info);
|
||||
break;
|
||||
case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA:
|
||||
tlb_info.start = (unsigned long)args[2];
|
||||
tlb_info.size = (unsigned long)args[3];
|
||||
tlb_info.type = SBI_TLB_FLUSH_VMA;
|
||||
tlb_info.shart_mask = 1UL << source_hart;
|
||||
ret = sbi_tlb_request(scratch, args[0], args[1], &tlb_info);
|
||||
break;
|
||||
case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID:
|
||||
tlb_info.start = (unsigned long)args[2];
|
||||
tlb_info.size = (unsigned long)args[3];
|
||||
tlb_info.asid = (unsigned long)args[4];
|
||||
tlb_info.type = SBI_TLB_FLUSH_VMA_ASID;
|
||||
tlb_info.shart_mask = 1UL << source_hart;
|
||||
ret = sbi_tlb_request(scratch, args[0], args[1], &tlb_info);
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = SBI_ENOTSUPP;
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct sbi_ecall_extension ecall_rfence = {
|
||||
.extid_start = SBI_EXT_RFENCE,
|
||||
.extid_end = SBI_EXT_RFENCE,
|
||||
.handle = sbi_ecall_rfence_handler,
|
||||
};
|
||||
|
||||
static int sbi_ecall_ipi_handler(struct sbi_scratch *scratch,
|
||||
unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (funcid == SBI_EXT_IPI_SEND_IPI)
|
||||
ret = sbi_ipi_send_smode(scratch, args[0], args[1]);
|
||||
else
|
||||
ret = SBI_ENOTSUPP;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct sbi_ecall_extension ecall_ipi = {
|
||||
.extid_start = SBI_EXT_IPI,
|
||||
.extid_end = SBI_EXT_IPI,
|
||||
.handle = sbi_ecall_ipi_handler,
|
||||
};
|
40
lib/sbi/sbi_ecall_vendor.c
Normal file
40
lib/sbi/sbi_ecall_vendor.c
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
* Atish Patra <atish.patra@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
|
||||
static int sbi_ecall_vendor_probe(struct sbi_scratch *scratch,
|
||||
unsigned long extid,
|
||||
unsigned long *out_val)
|
||||
{
|
||||
*out_val = sbi_platform_vendor_ext_check(sbi_platform_ptr(scratch),
|
||||
extid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sbi_ecall_vendor_handler(struct sbi_scratch *scratch,
|
||||
unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
return sbi_platform_vendor_ext_provider(sbi_platform_ptr(scratch),
|
||||
extid, funcid, args,
|
||||
out_val, out_trap);
|
||||
}
|
||||
|
||||
struct sbi_ecall_extension ecall_vendor = {
|
||||
.extid_start = SBI_EXT_VENDOR_START,
|
||||
.extid_end = SBI_EXT_VENDOR_END,
|
||||
.probe = sbi_ecall_vendor_probe,
|
||||
.handle = sbi_ecall_vendor_handler,
|
||||
};
|
@@ -14,16 +14,30 @@
|
||||
#include <sbi/sbi_emulate_csr.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_timer.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
|
||||
int sbi_emulate_csr_read(int csr_num, u32 hartid, ulong mstatus,
|
||||
int sbi_emulate_csr_read(int csr_num, u32 hartid, struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch, ulong *csr_val)
|
||||
{
|
||||
int ret = 0;
|
||||
ulong cen = -1UL;
|
||||
ulong prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
|
||||
#if __riscv_xlen == 32
|
||||
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
|
||||
#else
|
||||
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
|
||||
#endif
|
||||
|
||||
if (EXTRACT_FIELD(mstatus, MSTATUS_MPP) == PRV_U)
|
||||
if (prev_mode == PRV_U)
|
||||
cen = csr_read(CSR_SCOUNTEREN);
|
||||
|
||||
switch (csr_num) {
|
||||
case CSR_HTIMEDELTA:
|
||||
if (prev_mode == PRV_S && !virt)
|
||||
*csr_val = sbi_timer_get_delta(scratch);
|
||||
else
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
case CSR_CYCLE:
|
||||
if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1))
|
||||
return -1;
|
||||
@@ -32,7 +46,8 @@ int sbi_emulate_csr_read(int csr_num, u32 hartid, ulong mstatus,
|
||||
case CSR_TIME:
|
||||
if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1))
|
||||
return -1;
|
||||
*csr_val = sbi_timer_value(scratch);
|
||||
*csr_val = (virt) ? sbi_timer_virt_value(scratch):
|
||||
sbi_timer_value(scratch);
|
||||
break;
|
||||
case CSR_INSTRET:
|
||||
if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
|
||||
@@ -50,6 +65,12 @@ int sbi_emulate_csr_read(int csr_num, u32 hartid, ulong mstatus,
|
||||
*csr_val = csr_read(CSR_MHPMCOUNTER4);
|
||||
break;
|
||||
#if __riscv_xlen == 32
|
||||
case CSR_HTIMEDELTAH:
|
||||
if (prev_mode == PRV_S && !virt)
|
||||
*csr_val = sbi_timer_get_delta(scratch) >> 32;
|
||||
else
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
case CSR_CYCLEH:
|
||||
if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1))
|
||||
return -1;
|
||||
@@ -58,7 +79,8 @@ int sbi_emulate_csr_read(int csr_num, u32 hartid, ulong mstatus,
|
||||
case CSR_TIMEH:
|
||||
if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1))
|
||||
return -1;
|
||||
*csr_val = sbi_timer_value(scratch) >> 32;
|
||||
*csr_val = (virt) ? sbi_timer_virt_value(scratch) >> 32:
|
||||
sbi_timer_value(scratch) >> 32;
|
||||
break;
|
||||
case CSR_INSTRETH:
|
||||
if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
|
||||
@@ -83,18 +105,35 @@ int sbi_emulate_csr_read(int csr_num, u32 hartid, ulong mstatus,
|
||||
*csr_val = csr_read(CSR_MHPMEVENT4);
|
||||
break;
|
||||
default:
|
||||
sbi_printf("%s: hartid%d: invalid csr_num=0x%x\n", __func__,
|
||||
hartid, csr_num);
|
||||
return SBI_ENOTSUPP;
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
};
|
||||
|
||||
return 0;
|
||||
if (ret)
|
||||
sbi_dprintf(scratch, "%s: hartid%d: invalid csr_num=0x%x\n",
|
||||
__func__, hartid, csr_num);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sbi_emulate_csr_write(int csr_num, u32 hartid, ulong mstatus,
|
||||
int sbi_emulate_csr_write(int csr_num, u32 hartid, struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch, ulong csr_val)
|
||||
{
|
||||
int ret = 0;
|
||||
ulong prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
|
||||
#if __riscv_xlen == 32
|
||||
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
|
||||
#else
|
||||
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
|
||||
#endif
|
||||
|
||||
switch (csr_num) {
|
||||
case CSR_HTIMEDELTA:
|
||||
if (prev_mode == PRV_S && !virt)
|
||||
sbi_timer_set_delta(scratch, csr_val);
|
||||
else
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
case CSR_CYCLE:
|
||||
csr_write(CSR_MCYCLE, csr_val);
|
||||
break;
|
||||
@@ -108,6 +147,12 @@ int sbi_emulate_csr_write(int csr_num, u32 hartid, ulong mstatus,
|
||||
csr_write(CSR_MHPMCOUNTER4, csr_val);
|
||||
break;
|
||||
#if __riscv_xlen == 32
|
||||
case CSR_HTIMEDELTAH:
|
||||
if (prev_mode == PRV_S && !virt)
|
||||
sbi_timer_set_delta_upper(scratch, csr_val);
|
||||
else
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
case CSR_CYCLEH:
|
||||
csr_write(CSR_MCYCLEH, csr_val);
|
||||
break;
|
||||
@@ -128,10 +173,13 @@ int sbi_emulate_csr_write(int csr_num, u32 hartid, ulong mstatus,
|
||||
csr_write(CSR_MHPMEVENT4, csr_val);
|
||||
break;
|
||||
default:
|
||||
sbi_printf("%s: hartid%d: invalid csr_num=0x%x\n", __func__,
|
||||
hartid, csr_num);
|
||||
return SBI_ENOTSUPP;
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
};
|
||||
|
||||
return 0;
|
||||
if (ret)
|
||||
sbi_dprintf(scratch, "%s: hartid%d: invalid csr_num=0x%x\n",
|
||||
__func__, hartid, csr_num);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@@ -20,7 +20,7 @@ void sbi_fifo_init(struct sbi_fifo *fifo, void *queue_mem, u16 entries,
|
||||
fifo->entry_size = entry_size;
|
||||
SPIN_LOCK_INIT(&fifo->qlock);
|
||||
fifo->avail = fifo->tail = 0;
|
||||
sbi_memset(fifo->queue, 0, entries * entry_size);
|
||||
sbi_memset(fifo->queue, 0, (size_t)entries * entry_size);
|
||||
}
|
||||
|
||||
/* Note: must be called with fifo->qlock held */
|
||||
@@ -54,6 +54,21 @@ bool sbi_fifo_is_full(struct sbi_fifo *fifo)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Note: must be called with fifo->qlock held */
|
||||
static inline void __sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data)
|
||||
{
|
||||
u32 head;
|
||||
|
||||
head = (u32)fifo->tail + fifo->avail;
|
||||
if (head >= fifo->num_entries)
|
||||
head = head - fifo->num_entries;
|
||||
|
||||
sbi_memcpy(fifo->queue + head * fifo->entry_size, data, fifo->entry_size);
|
||||
|
||||
fifo->avail++;
|
||||
}
|
||||
|
||||
|
||||
/* Note: must be called with fifo->qlock held */
|
||||
static inline bool __sbi_fifo_is_empty(struct sbi_fifo *fifo)
|
||||
{
|
||||
@@ -74,9 +89,11 @@ bool sbi_fifo_is_empty(struct sbi_fifo *fifo)
|
||||
/* Note: must be called with fifo->qlock held */
|
||||
static inline void __sbi_fifo_reset(struct sbi_fifo *fifo)
|
||||
{
|
||||
size_t size = (size_t)fifo->num_entries * fifo->entry_size;
|
||||
|
||||
fifo->avail = 0;
|
||||
fifo->tail = 0;
|
||||
sbi_memset(fifo->queue, 0, fifo->num_entries * fifo->entry_size);
|
||||
sbi_memset(fifo->queue, 0, size);
|
||||
}
|
||||
|
||||
bool sbi_fifo_reset(struct sbi_fifo *fifo)
|
||||
@@ -107,7 +124,9 @@ int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
|
||||
|
||||
if (!fifo || !in)
|
||||
return ret;
|
||||
|
||||
spin_lock(&fifo->qlock);
|
||||
|
||||
if (__sbi_fifo_is_empty(fifo)) {
|
||||
spin_unlock(&fifo->qlock);
|
||||
return ret;
|
||||
@@ -119,11 +138,9 @@ int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
|
||||
index = index - fifo->num_entries;
|
||||
entry = (void *)fifo->queue + (u32)index * fifo->entry_size;
|
||||
ret = fptr(in, entry);
|
||||
|
||||
if (ret == SBI_FIFO_SKIP || ret == SBI_FIFO_UPDATED) {
|
||||
break;
|
||||
} else if (ret == SBI_FIFO_RESET) {
|
||||
__sbi_fifo_reset(fifo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(&fifo->qlock);
|
||||
@@ -133,8 +150,6 @@ int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
|
||||
|
||||
int sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data)
|
||||
{
|
||||
u32 head;
|
||||
|
||||
if (!fifo || !data)
|
||||
return SBI_EINVAL;
|
||||
|
||||
@@ -144,14 +159,7 @@ int sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data)
|
||||
spin_unlock(&fifo->qlock);
|
||||
return SBI_ENOSPC;
|
||||
}
|
||||
|
||||
head = (u32)fifo->tail + fifo->avail;
|
||||
if (head >= fifo->num_entries)
|
||||
head = head - fifo->num_entries;
|
||||
|
||||
sbi_memcpy(fifo->queue + head * fifo->entry_size, data, fifo->entry_size);
|
||||
|
||||
fifo->avail++;
|
||||
__sbi_fifo_enqueue(fifo, data);
|
||||
|
||||
spin_unlock(&fifo->qlock);
|
||||
|
||||
|
@@ -52,8 +52,6 @@ static int fp_init(u32 hartid)
|
||||
{
|
||||
#ifdef __riscv_flen
|
||||
int i;
|
||||
#else
|
||||
unsigned long fd_mask;
|
||||
#endif
|
||||
|
||||
if (!misa_extension('D') && !misa_extension('F'))
|
||||
@@ -66,11 +64,6 @@ static int fp_init(u32 hartid)
|
||||
for (i = 0; i < 32; i++)
|
||||
init_fp_reg(i);
|
||||
csr_write(CSR_FCSR, 0);
|
||||
#else
|
||||
fd_mask = (1 << ('F' - 'A')) | (1 << ('D' - 'A'));
|
||||
csr_clear(CSR_MISA, fd_mask);
|
||||
if (csr_read(CSR_MISA) & fd_mask)
|
||||
return SBI_ENOTSUPP;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
@@ -94,17 +87,37 @@ static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
|
||||
(1U << CAUSE_LOAD_PAGE_FAULT) |
|
||||
(1U << CAUSE_STORE_PAGE_FAULT);
|
||||
|
||||
/*
|
||||
* If hypervisor extension available then we only handle hypervisor
|
||||
* calls (i.e. ecalls from HS-mode) in M-mode.
|
||||
*
|
||||
* The HS-mode will additionally handle supervisor calls (i.e. ecalls
|
||||
* from VS-mode), Guest page faults and Virtual interrupts.
|
||||
*/
|
||||
if (misa_extension('H')) {
|
||||
exceptions |= (1U << CAUSE_SUPERVISOR_ECALL);
|
||||
exceptions |= (1U << CAUSE_FETCH_GUEST_PAGE_FAULT);
|
||||
exceptions |= (1U << CAUSE_LOAD_GUEST_PAGE_FAULT);
|
||||
exceptions |= (1U << CAUSE_STORE_GUEST_PAGE_FAULT);
|
||||
}
|
||||
|
||||
csr_write(CSR_MIDELEG, interrupts);
|
||||
csr_write(CSR_MEDELEG, exceptions);
|
||||
|
||||
if (csr_read(CSR_MIDELEG) != interrupts)
|
||||
return SBI_EFAIL;
|
||||
if (csr_read(CSR_MEDELEG) != exceptions)
|
||||
return SBI_EFAIL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sbi_hart_delegation_dump(struct sbi_scratch *scratch)
|
||||
{
|
||||
#if __riscv_xlen == 32
|
||||
sbi_printf("MIDELEG : 0x%08lx\n", csr_read(CSR_MIDELEG));
|
||||
sbi_printf("MEDELEG : 0x%08lx\n", csr_read(CSR_MEDELEG));
|
||||
#else
|
||||
sbi_printf("MIDELEG : 0x%016lx\n", csr_read(CSR_MIDELEG));
|
||||
sbi_printf("MEDELEG : 0x%016lx\n", csr_read(CSR_MEDELEG));
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned long log2roundup(unsigned long x)
|
||||
{
|
||||
unsigned long ret = 0;
|
||||
@@ -240,9 +253,14 @@ void __attribute__((noreturn)) sbi_hart_hang(void)
|
||||
|
||||
void __attribute__((noreturn))
|
||||
sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
|
||||
unsigned long next_addr, unsigned long next_mode)
|
||||
unsigned long next_addr, unsigned long next_mode,
|
||||
bool next_virt)
|
||||
{
|
||||
#if __riscv_xlen == 32
|
||||
unsigned long val, valH;
|
||||
#else
|
||||
unsigned long val;
|
||||
#endif
|
||||
|
||||
switch (next_mode) {
|
||||
case PRV_M:
|
||||
@@ -262,7 +280,23 @@ sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
|
||||
val = csr_read(CSR_MSTATUS);
|
||||
val = INSERT_FIELD(val, MSTATUS_MPP, next_mode);
|
||||
val = INSERT_FIELD(val, MSTATUS_MPIE, 0);
|
||||
|
||||
#if __riscv_xlen == 32
|
||||
if (misa_extension('H')) {
|
||||
valH = csr_read(CSR_MSTATUSH);
|
||||
if (next_virt)
|
||||
valH = INSERT_FIELD(valH, MSTATUSH_MPV, 1);
|
||||
else
|
||||
valH = INSERT_FIELD(valH, MSTATUSH_MPV, 0);
|
||||
csr_write(CSR_MSTATUSH, valH);
|
||||
}
|
||||
#else
|
||||
if (misa_extension('H')) {
|
||||
if (next_virt)
|
||||
val = INSERT_FIELD(val, MSTATUS_MPV, 1);
|
||||
else
|
||||
val = INSERT_FIELD(val, MSTATUS_MPV, 0);
|
||||
}
|
||||
#endif
|
||||
csr_write(CSR_MSTATUS, val);
|
||||
csr_write(CSR_MEPC, next_addr);
|
||||
|
||||
@@ -320,35 +354,49 @@ struct sbi_scratch *sbi_hart_id_to_scratch(struct sbi_scratch *scratch,
|
||||
}
|
||||
|
||||
#define COLDBOOT_WAIT_BITMAP_SIZE __riscv_xlen
|
||||
static spinlock_t coldboot_wait_bitmap_lock = SPIN_LOCK_INITIALIZER;
|
||||
static spinlock_t coldboot_lock = SPIN_LOCK_INITIALIZER;
|
||||
static unsigned long coldboot_done = 0;
|
||||
static unsigned long coldboot_wait_bitmap = 0;
|
||||
|
||||
void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
unsigned long mipval;
|
||||
unsigned long saved_mie;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
if ((sbi_platform_hart_count(plat) <= hartid) ||
|
||||
(COLDBOOT_WAIT_BITMAP_SIZE <= hartid))
|
||||
sbi_hart_hang();
|
||||
|
||||
/* Save MIE CSR */
|
||||
saved_mie = csr_read(CSR_MIE);
|
||||
|
||||
/* Set MSIE bit to receive IPI */
|
||||
csr_set(CSR_MIE, MIP_MSIP);
|
||||
|
||||
do {
|
||||
spin_lock(&coldboot_wait_bitmap_lock);
|
||||
/* Acquire coldboot lock */
|
||||
spin_lock(&coldboot_lock);
|
||||
|
||||
/* Mark current HART as waiting */
|
||||
coldboot_wait_bitmap |= (1UL << hartid);
|
||||
spin_unlock(&coldboot_wait_bitmap_lock);
|
||||
|
||||
/* Wait for coldboot to finish using WFI */
|
||||
while (!coldboot_done) {
|
||||
spin_unlock(&coldboot_lock);
|
||||
wfi();
|
||||
mipval = csr_read(CSR_MIP);
|
||||
spin_lock(&coldboot_lock);
|
||||
};
|
||||
|
||||
spin_lock(&coldboot_wait_bitmap_lock);
|
||||
/* Unmark current HART as waiting */
|
||||
coldboot_wait_bitmap &= ~(1UL << hartid);
|
||||
spin_unlock(&coldboot_wait_bitmap_lock);
|
||||
} while (!(mipval && MIP_MSIP));
|
||||
|
||||
csr_clear(CSR_MIP, MIP_MSIP);
|
||||
/* Release coldboot lock */
|
||||
spin_unlock(&coldboot_lock);
|
||||
|
||||
/* Restore MIE CSR */
|
||||
csr_write(CSR_MIE, saved_mie);
|
||||
|
||||
/* Clear current HART IPI */
|
||||
sbi_platform_ipi_clear(plat, hartid);
|
||||
}
|
||||
|
||||
void sbi_hart_wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
|
||||
@@ -356,11 +404,18 @@ void sbi_hart_wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
int max_hart = sbi_platform_hart_count(plat);
|
||||
|
||||
/* Acquire coldboot lock */
|
||||
spin_lock(&coldboot_lock);
|
||||
|
||||
/* Mark coldboot done */
|
||||
coldboot_done = 1;
|
||||
|
||||
/* Send an IPI to all HARTs waiting for coldboot */
|
||||
for (int i = 0; i < max_hart; i++) {
|
||||
/* send an IPI to every other hart */
|
||||
spin_lock(&coldboot_wait_bitmap_lock);
|
||||
if ((i != hartid) && (coldboot_wait_bitmap & (1UL << i)))
|
||||
sbi_platform_ipi_send(plat, i);
|
||||
spin_unlock(&coldboot_wait_bitmap_lock);
|
||||
}
|
||||
|
||||
/* Release coldboot lock */
|
||||
spin_unlock(&coldboot_lock);
|
||||
}
|
||||
|
75
lib/sbi/sbi_hfence.S
Normal file
75
lib/sbi/sbi_hfence.S
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
* Atish Patra <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Instruction encoding of hfence.gvma is:
|
||||
* 0110001 rs2(5) rs1(5) 000 00000 1110011
|
||||
*/
|
||||
|
||||
.align 3
|
||||
.global __sbi_hfence_gvma_vmid_gpa
|
||||
__sbi_hfence_gvma_vmid_gpa:
|
||||
/* hfence.gvma a1, a0 */
|
||||
.word 0x62a60073
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.global __sbi_hfence_gvma_vmid
|
||||
__sbi_hfence_gvma_vmid:
|
||||
/* hfence.gvma zero, a0 */
|
||||
.word 0x62a00073
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.global __sbi_hfence_gvma_gpa
|
||||
__sbi_hfence_gvma_gpa:
|
||||
/* hfence.gvma a0 */
|
||||
.word 0x62050073
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.global __sbi_hfence_gvma_all
|
||||
__sbi_hfence_gvma_all:
|
||||
/* hfence.gvma */
|
||||
.word 0x62000073
|
||||
ret
|
||||
|
||||
/*
|
||||
* Instruction encoding of hfence.bvma is:
|
||||
* 0010001 rs2(5) rs1(5) 000 00000 1110011
|
||||
*/
|
||||
|
||||
.align 3
|
||||
.global __sbi_hfence_vvma_asid_va
|
||||
__sbi_hfence_vvma_asid_va:
|
||||
/* hfence.bvma a1, a0 */
|
||||
.word 0x22a60073
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.global __sbi_hfence_vvma_asid
|
||||
__sbi_hfence_vvma_asid:
|
||||
/* hfence.bvma zero, a0 */
|
||||
.word 0x22a00073
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.global __sbi_hfence_vvma_va
|
||||
__sbi_hfence_vvma_va:
|
||||
/* hfence.bvma a0 */
|
||||
.word 0x22050073
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.global __sbi_hfence_vvma_all
|
||||
__sbi_hfence_vvma_all:
|
||||
/* hfence.bvma */
|
||||
.word 0x22000073
|
||||
ret
|
@@ -9,12 +9,12 @@
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include <sbi/riscv_unpriv.h>
|
||||
#include <sbi/sbi_bits.h>
|
||||
#include <sbi/sbi_emulate_csr.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_illegal_insn.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
#include <sbi/sbi_unpriv.h>
|
||||
|
||||
typedef int (*illegal_insn_func)(ulong insn, u32 hartid, ulong mcause,
|
||||
struct sbi_trap_regs *regs,
|
||||
@@ -24,7 +24,15 @@ static int truly_illegal_insn(ulong insn, u32 hartid, ulong mcause,
|
||||
struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch)
|
||||
{
|
||||
return sbi_trap_redirect(regs, scratch, regs->mepc, mcause, insn);
|
||||
struct sbi_trap_info trap;
|
||||
|
||||
trap.epc = regs->mepc;
|
||||
trap.cause = mcause;
|
||||
trap.tval = insn;
|
||||
trap.tval2 = 0;
|
||||
trap.tinst = 0;
|
||||
|
||||
return sbi_trap_redirect(regs, &trap, scratch);
|
||||
}
|
||||
|
||||
static int system_opcode_insn(ulong insn, u32 hartid, ulong mcause,
|
||||
@@ -36,9 +44,22 @@ static int system_opcode_insn(ulong insn, u32 hartid, ulong mcause,
|
||||
int csr_num = (u32)insn >> 20;
|
||||
ulong csr_val, new_csr_val;
|
||||
|
||||
if (sbi_emulate_csr_read(csr_num, hartid, regs->mstatus, scratch,
|
||||
&csr_val))
|
||||
return truly_illegal_insn(insn, hartid, mcause, regs, scratch);
|
||||
/*
|
||||
* WFI always traps as illegal instruction when executed from
|
||||
* VS/VU mode so we just forward it to HS-mode.
|
||||
*/
|
||||
#if __riscv_xlen == 32
|
||||
if ((regs->mstatusH & MSTATUSH_MPV) &&
|
||||
#else
|
||||
if ((regs->mstatus & MSTATUS_MPV) &&
|
||||
#endif
|
||||
(insn & INSN_MASK_WFI) == INSN_MATCH_WFI)
|
||||
return truly_illegal_insn(insn, hartid, mcause,
|
||||
regs, scratch);
|
||||
|
||||
if (sbi_emulate_csr_read(csr_num, hartid, regs, scratch, &csr_val))
|
||||
return truly_illegal_insn(insn, hartid, mcause,
|
||||
regs, scratch);
|
||||
|
||||
do_write = rs1_num;
|
||||
switch (GET_RM(insn)) {
|
||||
@@ -66,7 +87,7 @@ static int system_opcode_insn(ulong insn, u32 hartid, ulong mcause,
|
||||
return truly_illegal_insn(insn, hartid, mcause, regs, scratch);
|
||||
};
|
||||
|
||||
if (do_write && sbi_emulate_csr_write(csr_num, hartid, regs->mstatus,
|
||||
if (do_write && sbi_emulate_csr_write(csr_num, hartid, regs,
|
||||
scratch, new_csr_val))
|
||||
return truly_illegal_insn(insn, hartid, mcause, regs, scratch);
|
||||
|
||||
@@ -112,15 +133,21 @@ static illegal_insn_func illegal_insn_table[32] = {
|
||||
truly_illegal_insn /* 31 */
|
||||
};
|
||||
|
||||
int sbi_illegal_insn_handler(u32 hartid, ulong mcause,
|
||||
int sbi_illegal_insn_handler(u32 hartid, ulong mcause, ulong insn,
|
||||
struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch)
|
||||
{
|
||||
ulong insn = csr_read(mbadaddr);
|
||||
struct sbi_trap_info uptrap;
|
||||
|
||||
if (unlikely((insn & 3) != 3)) {
|
||||
if (insn == 0)
|
||||
insn = get_insn(regs->mepc, NULL);
|
||||
if (insn == 0) {
|
||||
insn = sbi_get_insn(regs->mepc, scratch, &uptrap);
|
||||
if (uptrap.cause) {
|
||||
uptrap.epc = regs->mepc;
|
||||
return sbi_trap_redirect(regs, &uptrap,
|
||||
scratch);
|
||||
}
|
||||
}
|
||||
if ((insn & 3) != 3)
|
||||
return truly_illegal_insn(insn, hartid, mcause, regs,
|
||||
scratch);
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_system.h>
|
||||
#include <sbi/sbi_timer.h>
|
||||
#include <sbi/sbi_tlb.h>
|
||||
#include <sbi/sbi_version.h>
|
||||
|
||||
#define BANNER \
|
||||
@@ -30,18 +31,31 @@
|
||||
|
||||
static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
int xlen;
|
||||
char str[64];
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
misa_string(str, sizeof(str));
|
||||
sbi_printf("\nOpenSBI v%d.%d (%s %s)\n", OPENSBI_VERSION_MAJOR,
|
||||
OPENSBI_VERSION_MINOR, __DATE__, __TIME__);
|
||||
#ifdef OPENSBI_VERSION_GIT
|
||||
sbi_printf("\nOpenSBI %s\n", OPENSBI_VERSION_GIT);
|
||||
#else
|
||||
sbi_printf("\nOpenSBI v%d.%d\n", OPENSBI_VERSION_MAJOR,
|
||||
OPENSBI_VERSION_MINOR);
|
||||
#endif
|
||||
|
||||
sbi_printf(BANNER);
|
||||
|
||||
/* Determine MISA XLEN and MISA string */
|
||||
xlen = misa_xlen();
|
||||
if (xlen < 1) {
|
||||
sbi_printf("Error %d getting MISA XLEN\n", xlen);
|
||||
sbi_hart_hang();
|
||||
}
|
||||
xlen = 16 * (1 << xlen);
|
||||
misa_string(str, sizeof(str));
|
||||
|
||||
/* Platform details */
|
||||
sbi_printf("Platform Name : %s\n", sbi_platform_name(plat));
|
||||
sbi_printf("Platform HART Features : RV%d%s\n", misa_xlen(), str);
|
||||
sbi_printf("Platform HART Features : RV%d%s\n", xlen, str);
|
||||
sbi_printf("Platform Max HARTs : %d\n",
|
||||
sbi_platform_hart_count(plat));
|
||||
sbi_printf("Current Hart : %u\n", hartid);
|
||||
@@ -54,14 +68,23 @@ static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
|
||||
sbi_ecall_version_major(), sbi_ecall_version_minor());
|
||||
sbi_printf("\n");
|
||||
|
||||
sbi_hart_delegation_dump(scratch);
|
||||
sbi_hart_pmp_dump(scratch);
|
||||
}
|
||||
|
||||
static unsigned long init_count_offset;
|
||||
|
||||
static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
int rc;
|
||||
unsigned long *init_count;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
init_count_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__,
|
||||
"INIT_COUNT");
|
||||
if (!init_count_offset)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_system_early_init(scratch, TRUE);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
@@ -82,10 +105,18 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_tlb_init(scratch, TRUE);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_timer_init(scratch, TRUE);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_ecall_init();
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_system_final_init(scratch, TRUE);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
@@ -93,22 +124,26 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
if (!(scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS))
|
||||
sbi_boot_prints(scratch, hartid);
|
||||
|
||||
if (!sbi_platform_has_hart_hotplug(plat))
|
||||
sbi_hart_wake_coldboot_harts(scratch, hartid);
|
||||
|
||||
sbi_hart_mark_available(hartid);
|
||||
|
||||
init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
|
||||
(*init_count)++;
|
||||
|
||||
sbi_hart_switch_mode(hartid, scratch->next_arg1, scratch->next_addr,
|
||||
scratch->next_mode);
|
||||
scratch->next_mode, FALSE);
|
||||
}
|
||||
|
||||
static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
int rc;
|
||||
unsigned long *init_count;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
if (!sbi_platform_has_hart_hotplug(plat))
|
||||
sbi_hart_wait_for_coldboot(scratch, hartid);
|
||||
|
||||
if (sbi_platform_hart_disabled(plat, hartid))
|
||||
if (!init_count_offset)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_system_early_init(scratch, FALSE);
|
||||
@@ -127,6 +162,10 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_tlb_init(scratch, FALSE);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_timer_init(scratch, FALSE);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
@@ -137,12 +176,12 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
|
||||
sbi_hart_mark_available(hartid);
|
||||
|
||||
if (sbi_platform_has_hart_hotplug(plat))
|
||||
/* TODO: To be implemented in-future. */
|
||||
sbi_hart_hang();
|
||||
else
|
||||
init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
|
||||
(*init_count)++;
|
||||
|
||||
sbi_hart_switch_mode(hartid, scratch->next_arg1,
|
||||
scratch->next_addr, scratch->next_mode);
|
||||
scratch->next_addr,
|
||||
scratch->next_mode, FALSE);
|
||||
}
|
||||
|
||||
static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);
|
||||
@@ -176,3 +215,50 @@ void __noreturn sbi_init(struct sbi_scratch *scratch)
|
||||
else
|
||||
init_warmboot(scratch, hartid);
|
||||
}
|
||||
|
||||
unsigned long sbi_init_count(u32 hartid)
|
||||
{
|
||||
struct sbi_scratch *scratch;
|
||||
unsigned long *init_count;
|
||||
|
||||
if (sbi_platform_hart_count(sbi_platform_thishart_ptr()) <= hartid ||
|
||||
!init_count_offset)
|
||||
return 0;
|
||||
|
||||
scratch = sbi_hart_id_to_scratch(sbi_scratch_thishart_ptr(), hartid);
|
||||
init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
|
||||
|
||||
return *init_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit OpenSBI library for current HART and stop HART
|
||||
*
|
||||
* The function expects following:
|
||||
* 1. The 'mscratch' CSR is pointing to sbi_scratch of current HART
|
||||
* 2. Stack pointer (SP) is setup for current HART
|
||||
*
|
||||
* @param scratch pointer to sbi_scratch of current HART
|
||||
*/
|
||||
void __noreturn sbi_exit(struct sbi_scratch *scratch)
|
||||
{
|
||||
u32 hartid = sbi_current_hartid();
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
if (sbi_platform_hart_disabled(plat, hartid))
|
||||
sbi_hart_hang();
|
||||
|
||||
sbi_hart_unmark_available(hartid);
|
||||
|
||||
sbi_platform_early_exit(plat);
|
||||
|
||||
sbi_timer_exit(scratch);
|
||||
|
||||
sbi_ipi_exit(scratch);
|
||||
|
||||
sbi_platform_irqchip_exit(plat);
|
||||
|
||||
sbi_platform_final_exit(plat);
|
||||
|
||||
sbi_hart_hang();
|
||||
}
|
||||
|
@@ -9,90 +9,170 @@
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/riscv_barrier.h>
|
||||
#include <sbi/riscv_atomic.h>
|
||||
#include <sbi/riscv_unpriv.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/riscv_barrier.h>
|
||||
#include <sbi/sbi_bitops.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_init.h>
|
||||
#include <sbi/sbi_ipi.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_timer.h>
|
||||
#include <sbi/sbi_tlb.h>
|
||||
|
||||
struct sbi_ipi_data {
|
||||
unsigned long ipi_type;
|
||||
};
|
||||
|
||||
static unsigned long ipi_data_off;
|
||||
|
||||
static int sbi_ipi_send(struct sbi_scratch *scratch, u32 hartid, u32 event,
|
||||
void *data)
|
||||
static const struct sbi_ipi_event_ops *ipi_ops_array[SBI_IPI_EVENT_MAX];
|
||||
|
||||
static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid,
|
||||
u32 event, void *data)
|
||||
{
|
||||
int ret;
|
||||
struct sbi_scratch *remote_scratch = NULL;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
struct sbi_ipi_data *ipi_data;
|
||||
const struct sbi_ipi_event_ops *ipi_ops;
|
||||
|
||||
if (sbi_platform_hart_disabled(plat, hartid))
|
||||
return -1;
|
||||
if ((SBI_IPI_EVENT_MAX <= event) ||
|
||||
!ipi_ops_array[event] ||
|
||||
sbi_platform_hart_disabled(plat, remote_hartid))
|
||||
return SBI_EINVAL;
|
||||
ipi_ops = ipi_ops_array[event];
|
||||
|
||||
/*
|
||||
* Set IPI type on remote hart's scratch area and
|
||||
* trigger the interrupt
|
||||
*/
|
||||
remote_scratch = sbi_hart_id_to_scratch(scratch, hartid);
|
||||
remote_scratch = sbi_hart_id_to_scratch(scratch, remote_hartid);
|
||||
ipi_data = sbi_scratch_offset_ptr(remote_scratch, ipi_data_off);
|
||||
if (event == SBI_IPI_EVENT_SFENCE_VMA ||
|
||||
event == SBI_IPI_EVENT_SFENCE_VMA_ASID) {
|
||||
ret = sbi_tlb_fifo_update(remote_scratch, event, data);
|
||||
if (ret > 0)
|
||||
goto done;
|
||||
else if (ret < 0)
|
||||
|
||||
if (ipi_ops->update) {
|
||||
ret = ipi_ops->update(scratch, remote_scratch,
|
||||
remote_hartid, data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
atomic_raw_set_bit(event, &ipi_data->ipi_type);
|
||||
mb();
|
||||
sbi_platform_ipi_send(plat, hartid);
|
||||
if (event != SBI_IPI_EVENT_SOFT)
|
||||
sbi_platform_ipi_sync(plat, hartid);
|
||||
|
||||
done:
|
||||
atomic_raw_set_bit(event, &ipi_data->ipi_type);
|
||||
smp_wmb();
|
||||
sbi_platform_ipi_send(plat, remote_hartid);
|
||||
|
||||
if (ipi_ops->sync)
|
||||
ipi_ops->sync(scratch);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sbi_ipi_send_many(struct sbi_scratch *scratch, struct unpriv_trap *uptrap,
|
||||
ulong *pmask, u32 event, void *data)
|
||||
/**
|
||||
* As this this function only handlers scalar values of hart mask, it must be
|
||||
* set to all online harts if the intention is to send IPIs to all the harts.
|
||||
* If hmask is zero, no IPIs will be sent.
|
||||
*/
|
||||
int sbi_ipi_send_many(struct sbi_scratch *scratch, ulong hmask, ulong hbase,
|
||||
u32 event, void *data)
|
||||
{
|
||||
ulong i, m;
|
||||
ulong mask = sbi_hart_available_mask();
|
||||
u32 hartid = sbi_current_hartid();
|
||||
ulong tempmask;
|
||||
unsigned long last_bit = __fls(mask);
|
||||
|
||||
if (pmask) {
|
||||
mask &= load_ulong(pmask, scratch, uptrap);
|
||||
if (uptrap->cause)
|
||||
return SBI_ETRAP;
|
||||
if (hbase != -1UL) {
|
||||
if (hbase > last_bit)
|
||||
/* hart base is not available */
|
||||
return SBI_EINVAL;
|
||||
/**
|
||||
* FIXME: This check is valid only ULONG size. This is okay for
|
||||
* now as avaialble hart mask can support upto ULONG size only.
|
||||
*/
|
||||
tempmask = hmask << hbase;
|
||||
tempmask = ~mask & tempmask;
|
||||
if (tempmask)
|
||||
/* at least one of the hart in hmask is not available */
|
||||
return SBI_EINVAL;
|
||||
|
||||
mask &= (hmask << hbase);
|
||||
}
|
||||
|
||||
/* send IPIs to every other hart on the set */
|
||||
/* Send IPIs to every other hart on the set */
|
||||
for (i = 0, m = mask; m; i++, m >>= 1)
|
||||
if ((m & 1UL) && (i != hartid))
|
||||
if (m & 1UL)
|
||||
sbi_ipi_send(scratch, i, event, data);
|
||||
|
||||
/* If the current hart is on the set, send an IPI
|
||||
* to it as well
|
||||
*/
|
||||
if (mask & (1UL << hartid))
|
||||
sbi_ipi_send(scratch, hartid, event, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sbi_ipi_event_create(const struct sbi_ipi_event_ops *ops)
|
||||
{
|
||||
int i, ret = SBI_ENOSPC;
|
||||
|
||||
if (!ops || !ops->process)
|
||||
return SBI_EINVAL;
|
||||
|
||||
for (i = 0; i < SBI_IPI_EVENT_MAX; i++) {
|
||||
if (!ipi_ops_array[i]) {
|
||||
ret = i;
|
||||
ipi_ops_array[i] = ops;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void sbi_ipi_event_destroy(u32 event)
|
||||
{
|
||||
if (SBI_IPI_EVENT_MAX <= event)
|
||||
return;
|
||||
|
||||
ipi_ops_array[event] = NULL;
|
||||
}
|
||||
|
||||
static void sbi_ipi_process_smode(struct sbi_scratch *scratch)
|
||||
{
|
||||
csr_set(CSR_MIP, MIP_SSIP);
|
||||
}
|
||||
|
||||
static struct sbi_ipi_event_ops ipi_smode_ops = {
|
||||
.name = "IPI_SMODE",
|
||||
.process = sbi_ipi_process_smode,
|
||||
};
|
||||
|
||||
static u32 ipi_smode_event = SBI_IPI_EVENT_MAX;
|
||||
|
||||
int sbi_ipi_send_smode(struct sbi_scratch *scratch, ulong hmask, ulong hbase)
|
||||
{
|
||||
return sbi_ipi_send_many(scratch, hmask, hbase, ipi_smode_event, NULL);
|
||||
}
|
||||
|
||||
void sbi_ipi_clear_smode(struct sbi_scratch *scratch)
|
||||
{
|
||||
csr_clear(CSR_MIP, MIP_SSIP);
|
||||
}
|
||||
|
||||
static void sbi_ipi_process_halt(struct sbi_scratch *scratch)
|
||||
{
|
||||
sbi_exit(scratch);
|
||||
}
|
||||
|
||||
static struct sbi_ipi_event_ops ipi_halt_ops = {
|
||||
.name = "IPI_HALT",
|
||||
.process = sbi_ipi_process_halt,
|
||||
};
|
||||
|
||||
static u32 ipi_halt_event = SBI_IPI_EVENT_MAX;
|
||||
|
||||
int sbi_ipi_send_halt(struct sbi_scratch *scratch, ulong hmask, ulong hbase)
|
||||
{
|
||||
return sbi_ipi_send_many(scratch, hmask, hbase, ipi_halt_event, NULL);
|
||||
}
|
||||
|
||||
void sbi_ipi_process(struct sbi_scratch *scratch)
|
||||
{
|
||||
volatile unsigned long ipi_type;
|
||||
unsigned long ipi_type;
|
||||
unsigned int ipi_event;
|
||||
const struct sbi_ipi_event_ops *ipi_ops;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
struct sbi_ipi_data *ipi_data =
|
||||
sbi_scratch_offset_ptr(scratch, ipi_data_off);
|
||||
@@ -100,27 +180,20 @@ void sbi_ipi_process(struct sbi_scratch *scratch)
|
||||
u32 hartid = sbi_current_hartid();
|
||||
sbi_platform_ipi_clear(plat, hartid);
|
||||
|
||||
do {
|
||||
ipi_type = ipi_data->ipi_type;
|
||||
rmb();
|
||||
ipi_event = __ffs(ipi_type);
|
||||
switch (ipi_event) {
|
||||
case SBI_IPI_EVENT_SOFT:
|
||||
csr_set(CSR_MIP, MIP_SSIP);
|
||||
break;
|
||||
case SBI_IPI_EVENT_FENCE_I:
|
||||
__asm__ __volatile("fence.i");
|
||||
break;
|
||||
case SBI_IPI_EVENT_SFENCE_VMA:
|
||||
case SBI_IPI_EVENT_SFENCE_VMA_ASID:
|
||||
sbi_tlb_fifo_process(scratch, ipi_event);
|
||||
break;
|
||||
case SBI_IPI_EVENT_HALT:
|
||||
sbi_hart_hang();
|
||||
break;
|
||||
ipi_type = atomic_raw_xchg_ulong(&ipi_data->ipi_type, 0);
|
||||
ipi_event = 0;
|
||||
while (ipi_type) {
|
||||
if (!(ipi_type & 1UL))
|
||||
goto skip;
|
||||
|
||||
ipi_ops = ipi_ops_array[ipi_event];
|
||||
if (ipi_ops && ipi_ops->process)
|
||||
ipi_ops->process(scratch);
|
||||
|
||||
skip:
|
||||
ipi_type = ipi_type >> 1;
|
||||
ipi_event++;
|
||||
};
|
||||
ipi_type = atomic_raw_clear_bit(ipi_event, &ipi_data->ipi_type);
|
||||
} while (ipi_type > 0);
|
||||
}
|
||||
|
||||
int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||
@@ -133,20 +206,44 @@ int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||
"IPI_DATA");
|
||||
if (!ipi_data_off)
|
||||
return SBI_ENOMEM;
|
||||
ret = sbi_ipi_event_create(&ipi_smode_ops);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ipi_smode_event = ret;
|
||||
ret = sbi_ipi_event_create(&ipi_halt_ops);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ipi_halt_event = ret;
|
||||
} else {
|
||||
if (!ipi_data_off)
|
||||
return SBI_ENOMEM;
|
||||
if (SBI_IPI_EVENT_MAX <= ipi_smode_event ||
|
||||
SBI_IPI_EVENT_MAX <= ipi_halt_event)
|
||||
return SBI_ENOSPC;
|
||||
}
|
||||
|
||||
ipi_data = sbi_scratch_offset_ptr(scratch, ipi_data_off);
|
||||
ipi_data->ipi_type = 0x00;
|
||||
|
||||
ret = sbi_tlb_fifo_init(scratch, cold_boot);
|
||||
/* Platform init */
|
||||
ret = sbi_platform_ipi_init(sbi_platform_ptr(scratch), cold_boot);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enable software interrupts */
|
||||
csr_set(CSR_MIE, MIP_MSIP);
|
||||
|
||||
return sbi_platform_ipi_init(sbi_platform_ptr(scratch), cold_boot);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sbi_ipi_exit(struct sbi_scratch *scratch)
|
||||
{
|
||||
/* Disable software interrupts */
|
||||
csr_clear(CSR_MIE, MIP_MSIP);
|
||||
|
||||
/* Process pending IPIs */
|
||||
sbi_ipi_process(scratch);
|
||||
|
||||
/* Platform exit */
|
||||
sbi_platform_ipi_exit(sbi_platform_ptr(scratch));
|
||||
}
|
||||
|
@@ -9,11 +9,11 @@
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include <sbi/riscv_unpriv.h>
|
||||
#include <sbi/riscv_fp.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_misaligned_ldst.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
#include <sbi/sbi_unpriv.h>
|
||||
|
||||
union reg_data {
|
||||
u8 data_bytes[8];
|
||||
@@ -22,15 +22,33 @@ union reg_data {
|
||||
};
|
||||
|
||||
int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
|
||||
ulong addr, ulong tval2, ulong tinst,
|
||||
struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch)
|
||||
{
|
||||
ulong insn;
|
||||
union reg_data val;
|
||||
struct unpriv_trap uptrap;
|
||||
ulong insn = get_insn(regs->mepc, NULL);
|
||||
ulong addr = csr_read(CSR_MTVAL);
|
||||
struct sbi_trap_info uptrap;
|
||||
int i, fp = 0, shift = 0, len = 0;
|
||||
|
||||
if (tinst & 0x1) {
|
||||
/*
|
||||
* Bit[0] == 1 implies trapped instruction value is
|
||||
* transformed instruction or custom instruction.
|
||||
*/
|
||||
insn = tinst | INSN_16BIT_MASK;
|
||||
} else {
|
||||
/*
|
||||
* Bit[0] == 0 implies trapped instruction value is
|
||||
* zero or special value.
|
||||
*/
|
||||
insn = sbi_get_insn(regs->mepc, scratch, &uptrap);
|
||||
if (uptrap.cause) {
|
||||
uptrap.epc = regs->mepc;
|
||||
return sbi_trap_redirect(regs, &uptrap, scratch);
|
||||
}
|
||||
}
|
||||
|
||||
if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) {
|
||||
len = 4;
|
||||
shift = 8 * (sizeof(ulong) - len);
|
||||
@@ -41,12 +59,14 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
|
||||
} else if ((insn & INSN_MASK_LWU) == INSN_MATCH_LWU) {
|
||||
len = 4;
|
||||
#endif
|
||||
#ifdef __riscv_flen
|
||||
} else if ((insn & INSN_MASK_FLD) == INSN_MATCH_FLD) {
|
||||
fp = 1;
|
||||
len = 8;
|
||||
} else if ((insn & INSN_MASK_FLW) == INSN_MATCH_FLW) {
|
||||
fp = 1;
|
||||
len = 4;
|
||||
#endif
|
||||
} else if ((insn & INSN_MASK_LH) == INSN_MATCH_LH) {
|
||||
len = 2;
|
||||
shift = 8 * (sizeof(ulong) - len);
|
||||
@@ -71,6 +91,7 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
|
||||
((insn >> SH_RD) & 0x1f)) {
|
||||
len = 4;
|
||||
shift = 8 * (sizeof(ulong) - len);
|
||||
#ifdef __riscv_flen
|
||||
} else if ((insn & INSN_MASK_C_FLD) == INSN_MATCH_C_FLD) {
|
||||
fp = 1;
|
||||
len = 8;
|
||||
@@ -88,26 +109,34 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
|
||||
len = 4;
|
||||
#endif
|
||||
#endif
|
||||
} else
|
||||
return SBI_EILL;
|
||||
#endif
|
||||
} else {
|
||||
uptrap.epc = regs->mepc;
|
||||
uptrap.cause = mcause;
|
||||
uptrap.tval = addr;
|
||||
uptrap.tval2 = tval2;
|
||||
uptrap.tinst = tinst;
|
||||
return sbi_trap_redirect(regs, &uptrap, scratch);
|
||||
}
|
||||
|
||||
val.data_u64 = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
val.data_bytes[i] = load_u8((void *)(addr + i),
|
||||
val.data_bytes[i] = sbi_load_u8((void *)(addr + i),
|
||||
scratch, &uptrap);
|
||||
if (uptrap.cause) {
|
||||
sbi_trap_redirect(regs, scratch, regs->mepc,
|
||||
uptrap.cause, uptrap.tval);
|
||||
return 0;
|
||||
uptrap.epc = regs->mepc;
|
||||
return sbi_trap_redirect(regs, &uptrap, scratch);
|
||||
}
|
||||
}
|
||||
|
||||
if (!fp)
|
||||
SET_RD(insn, regs, val.data_ulong << shift >> shift);
|
||||
#ifdef __riscv_flen
|
||||
else if (len == 8)
|
||||
SET_F64_RD(insn, regs, val.data_u64);
|
||||
else
|
||||
SET_F32_RD(insn, regs, val.data_ulong);
|
||||
#endif
|
||||
|
||||
regs->mepc += INSN_LEN(insn);
|
||||
|
||||
@@ -115,15 +144,33 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
|
||||
}
|
||||
|
||||
int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
|
||||
ulong addr, ulong tval2, ulong tinst,
|
||||
struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch)
|
||||
{
|
||||
ulong insn;
|
||||
union reg_data val;
|
||||
struct unpriv_trap uptrap;
|
||||
ulong insn = get_insn(regs->mepc, NULL);
|
||||
ulong addr = csr_read(CSR_MTVAL);
|
||||
struct sbi_trap_info uptrap;
|
||||
int i, len = 0;
|
||||
|
||||
if (tinst & 0x1) {
|
||||
/*
|
||||
* Bit[0] == 1 implies trapped instruction value is
|
||||
* transformed instruction or custom instruction.
|
||||
*/
|
||||
insn = tinst | INSN_16BIT_MASK;
|
||||
} else {
|
||||
/*
|
||||
* Bit[0] == 0 implies trapped instruction value is
|
||||
* zero or special value.
|
||||
*/
|
||||
insn = sbi_get_insn(regs->mepc, scratch, &uptrap);
|
||||
if (uptrap.cause) {
|
||||
uptrap.epc = regs->mepc;
|
||||
return sbi_trap_redirect(regs, &uptrap, scratch);
|
||||
}
|
||||
}
|
||||
|
||||
val.data_ulong = GET_RS2(insn, regs);
|
||||
|
||||
if ((insn & INSN_MASK_SW) == INSN_MATCH_SW) {
|
||||
@@ -132,12 +179,14 @@ int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
|
||||
} else if ((insn & INSN_MASK_SD) == INSN_MATCH_SD) {
|
||||
len = 8;
|
||||
#endif
|
||||
#ifdef __riscv_flen
|
||||
} else if ((insn & INSN_MASK_FSD) == INSN_MATCH_FSD) {
|
||||
len = 8;
|
||||
val.data_u64 = GET_F64_RS2(insn, regs);
|
||||
} else if ((insn & INSN_MASK_FSW) == INSN_MATCH_FSW) {
|
||||
len = 4;
|
||||
val.data_ulong = GET_F32_RS2(insn, regs);
|
||||
#endif
|
||||
} else if ((insn & INSN_MASK_SH) == INSN_MATCH_SH) {
|
||||
len = 2;
|
||||
#ifdef __riscv_compressed
|
||||
@@ -157,6 +206,7 @@ int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
|
||||
((insn >> SH_RD) & 0x1f)) {
|
||||
len = 4;
|
||||
val.data_ulong = GET_RS2C(insn, regs);
|
||||
#ifdef __riscv_flen
|
||||
} else if ((insn & INSN_MASK_C_FSD) == INSN_MATCH_C_FSD) {
|
||||
len = 8;
|
||||
val.data_u64 = GET_F64_RS2S(insn, regs);
|
||||
@@ -172,16 +222,22 @@ int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
|
||||
val.data_ulong = GET_F32_RS2C(insn, regs);
|
||||
#endif
|
||||
#endif
|
||||
} else
|
||||
return SBI_EILL;
|
||||
#endif
|
||||
} else {
|
||||
uptrap.epc = regs->mepc;
|
||||
uptrap.cause = mcause;
|
||||
uptrap.tval = addr;
|
||||
uptrap.tval2 = tval2;
|
||||
uptrap.tinst = tinst;
|
||||
return sbi_trap_redirect(regs, &uptrap, scratch);
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
store_u8((void *)(addr + i), val.data_bytes[i],
|
||||
sbi_store_u8((void *)(addr + i), val.data_bytes[i],
|
||||
scratch, &uptrap);
|
||||
if (uptrap.cause) {
|
||||
sbi_trap_redirect(regs, scratch, regs->mepc,
|
||||
uptrap.cause, uptrap.tval);
|
||||
return 0;
|
||||
uptrap.epc = regs->mepc;
|
||||
return sbi_trap_redirect(regs, &uptrap, scratch);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -8,14 +8,21 @@
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_locks.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/sbi_string.h>
|
||||
|
||||
static spinlock_t extra_lock = SPIN_LOCK_INITIALIZER;
|
||||
static unsigned long extra_offset = SBI_SCRATCH_EXTRA_SPACE_OFFSET;
|
||||
|
||||
unsigned long sbi_scratch_alloc_offset(unsigned long size, const char *owner)
|
||||
{
|
||||
u32 i;
|
||||
void *ptr;
|
||||
unsigned long ret = 0;
|
||||
struct sbi_scratch *scratch, *rscratch;
|
||||
const struct sbi_platform *plat;
|
||||
|
||||
/*
|
||||
* We have a simple brain-dead allocator which never expects
|
||||
@@ -29,8 +36,8 @@ unsigned long sbi_scratch_alloc_offset(unsigned long size, const char *owner)
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
while (size & (__SIZEOF_POINTER__ - 1))
|
||||
size++;
|
||||
if (size & (__SIZEOF_POINTER__ - 1))
|
||||
size = (size & ~(__SIZEOF_POINTER__ - 1)) + __SIZEOF_POINTER__;
|
||||
|
||||
spin_lock(&extra_lock);
|
||||
|
||||
@@ -43,6 +50,16 @@ unsigned long sbi_scratch_alloc_offset(unsigned long size, const char *owner)
|
||||
done:
|
||||
spin_unlock(&extra_lock);
|
||||
|
||||
if (ret) {
|
||||
scratch = sbi_scratch_thishart_ptr();
|
||||
plat = sbi_platform_ptr(scratch);
|
||||
for (i = 0; i < sbi_platform_hart_count(plat); i++) {
|
||||
rscratch = sbi_hart_id_to_scratch(scratch, i);
|
||||
ptr = sbi_scratch_offset_ptr(rscratch, ret);
|
||||
sbi_memset(ptr, 0, size);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_system.h>
|
||||
#include <sbi/sbi_ipi.h>
|
||||
#include <sbi/sbi_init.h>
|
||||
|
||||
int sbi_system_early_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||
{
|
||||
@@ -23,23 +24,42 @@ int sbi_system_final_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||
return sbi_platform_final_init(sbi_platform_ptr(scratch), cold_boot);
|
||||
}
|
||||
|
||||
void __attribute__((noreturn))
|
||||
sbi_system_reboot(struct sbi_scratch *scratch, u32 type)
|
||||
|
||||
void sbi_system_early_exit(struct sbi_scratch *scratch)
|
||||
{
|
||||
sbi_platform_system_reboot(sbi_platform_ptr(scratch), type);
|
||||
sbi_hart_hang();
|
||||
sbi_platform_early_exit(sbi_platform_ptr(scratch));
|
||||
}
|
||||
|
||||
void __attribute__((noreturn))
|
||||
sbi_system_shutdown(struct sbi_scratch *scratch, u32 type)
|
||||
void sbi_system_final_exit(struct sbi_scratch *scratch)
|
||||
{
|
||||
/* First try the platform-specific method */
|
||||
sbi_platform_final_exit(sbi_platform_ptr(scratch));
|
||||
}
|
||||
|
||||
void __noreturn sbi_system_reboot(struct sbi_scratch *scratch, u32 type)
|
||||
{
|
||||
u32 current_hartid_mask = 1UL << sbi_current_hartid();
|
||||
|
||||
/* Send HALT IPI to every hart other than the current hart */
|
||||
sbi_ipi_send_halt(scratch,
|
||||
sbi_hart_available_mask() & ~current_hartid_mask, 0);
|
||||
|
||||
/* Platform specific reooot */
|
||||
sbi_platform_system_reboot(sbi_platform_ptr(scratch), type);
|
||||
|
||||
/* If platform specific reboot did not work then do sbi_exit() */
|
||||
sbi_exit(scratch);
|
||||
}
|
||||
|
||||
void __noreturn sbi_system_shutdown(struct sbi_scratch *scratch, u32 type)
|
||||
{
|
||||
u32 current_hartid_mask = 1UL << sbi_current_hartid();
|
||||
|
||||
/* Send HALT IPI to every hart other than the current hart */
|
||||
sbi_ipi_send_halt(scratch,
|
||||
sbi_hart_available_mask() & ~current_hartid_mask, 0);
|
||||
|
||||
/* Platform specific shutdown */
|
||||
sbi_platform_system_shutdown(sbi_platform_ptr(scratch), type);
|
||||
|
||||
/* If that fails (or is not implemented) send an IPI on every
|
||||
* hart to hang and then hang the current hart */
|
||||
sbi_ipi_send_many(scratch, NULL, NULL, SBI_IPI_EVENT_HALT, NULL);
|
||||
|
||||
sbi_hart_hang();
|
||||
/* If platform specific shutdown did not work then do sbi_exit() */
|
||||
sbi_exit(scratch);
|
||||
}
|
||||
|
@@ -9,9 +9,12 @@
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_timer.h>
|
||||
|
||||
static unsigned long time_delta_off;
|
||||
|
||||
#if __riscv_xlen == 32
|
||||
u64 get_ticks(void)
|
||||
{
|
||||
@@ -44,9 +47,33 @@ u64 sbi_timer_value(struct sbi_scratch *scratch)
|
||||
return get_ticks();
|
||||
}
|
||||
|
||||
void sbi_timer_event_stop(struct sbi_scratch *scratch)
|
||||
u64 sbi_timer_virt_value(struct sbi_scratch *scratch)
|
||||
{
|
||||
sbi_platform_timer_event_stop(sbi_platform_ptr(scratch));
|
||||
u64 *time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
|
||||
|
||||
return sbi_timer_value(scratch) + *time_delta;
|
||||
}
|
||||
|
||||
u64 sbi_timer_get_delta(struct sbi_scratch *scratch)
|
||||
{
|
||||
u64 *time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
|
||||
|
||||
return *time_delta;
|
||||
}
|
||||
|
||||
void sbi_timer_set_delta(struct sbi_scratch *scratch, ulong delta)
|
||||
{
|
||||
u64 *time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
|
||||
|
||||
*time_delta = (u64)delta;
|
||||
}
|
||||
|
||||
void sbi_timer_set_delta_upper(struct sbi_scratch *scratch, ulong delta_upper)
|
||||
{
|
||||
u64 *time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
|
||||
|
||||
*time_delta &= 0xffffffffULL;
|
||||
*time_delta |= ((u64)delta_upper << 32);
|
||||
}
|
||||
|
||||
void sbi_timer_event_start(struct sbi_scratch *scratch, u64 next_event)
|
||||
@@ -64,5 +91,30 @@ void sbi_timer_process(struct sbi_scratch *scratch)
|
||||
|
||||
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||
{
|
||||
u64 *time_delta;
|
||||
|
||||
if (cold_boot) {
|
||||
time_delta_off = sbi_scratch_alloc_offset(sizeof(*time_delta),
|
||||
"TIME_DELTA");
|
||||
if (!time_delta_off)
|
||||
return SBI_ENOMEM;
|
||||
} else {
|
||||
if (!time_delta_off)
|
||||
return SBI_ENOMEM;
|
||||
}
|
||||
|
||||
time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
|
||||
*time_delta = 0;
|
||||
|
||||
return sbi_platform_timer_init(sbi_platform_ptr(scratch), cold_boot);
|
||||
}
|
||||
|
||||
void sbi_timer_exit(struct sbi_scratch *scratch)
|
||||
{
|
||||
sbi_platform_timer_event_stop(sbi_platform_ptr(scratch));
|
||||
|
||||
csr_clear(CSR_MIP, MIP_STIP);
|
||||
csr_clear(CSR_MIE, MIP_MTIP);
|
||||
|
||||
sbi_platform_timer_exit(sbi_platform_ptr(scratch));
|
||||
}
|
||||
|
@@ -9,129 +9,62 @@
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/riscv_atomic.h>
|
||||
#include <sbi/riscv_barrier.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_fifo.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_bitops.h>
|
||||
#include <sbi/sbi_ipi.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/sbi_tlb.h>
|
||||
#include <sbi/sbi_hfence.h>
|
||||
#include <sbi/sbi_string.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
|
||||
static unsigned long ipi_tlb_fifo_off;
|
||||
static unsigned long ipi_tlb_fifo_mem_off;
|
||||
|
||||
static inline int __sbi_tlb_fifo_range_check(struct sbi_tlb_info *curr,
|
||||
struct sbi_tlb_info *next)
|
||||
{
|
||||
unsigned long curr_end;
|
||||
unsigned long next_end;
|
||||
int ret = SBI_FIFO_UNCHANGED;
|
||||
|
||||
if (!curr || !next)
|
||||
return ret;
|
||||
|
||||
next_end = next->start + next->size;
|
||||
curr_end = curr->start + curr->size;
|
||||
if (next->start <= curr->start && next_end > curr_end) {
|
||||
curr->start = next->start;
|
||||
curr->size = next->size;
|
||||
ret = SBI_FIFO_UPDATED;
|
||||
} else if (next->start >= curr->start && next_end <= curr_end) {
|
||||
ret = SBI_FIFO_SKIP;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call back to decide if an inplace fifo update is required or next entry can
|
||||
* can be skipped. Here are the different cases that are being handled.
|
||||
*
|
||||
* Case1:
|
||||
* if next flush request range lies within one of the existing entry, skip
|
||||
* the next entry.
|
||||
* Case2:
|
||||
* if flush request range in current fifo entry lies within next flush
|
||||
* request, update the current entry.
|
||||
* Case3:
|
||||
if a complete vma flush is requested, then all entries can be deleted
|
||||
and new request can be enqueued. This will not be done for ASID case
|
||||
as that means we have to iterate again in the fifo to figure out which
|
||||
entries belong to that ASID.
|
||||
*/
|
||||
static int sbi_tlb_fifo_update_cb(void *in, void *data)
|
||||
{
|
||||
struct sbi_tlb_info *curr;
|
||||
struct sbi_tlb_info *next;
|
||||
int ret = SBI_FIFO_UNCHANGED;
|
||||
|
||||
if (!in && !!data)
|
||||
return ret;
|
||||
|
||||
curr = (struct sbi_tlb_info *)data;
|
||||
next = (struct sbi_tlb_info *)in;
|
||||
if (next->type == SBI_TLB_FLUSH_VMA_ASID &&
|
||||
curr->type == SBI_TLB_FLUSH_VMA_ASID) {
|
||||
if (next->asid == curr->asid)
|
||||
ret = __sbi_tlb_fifo_range_check(curr, next);
|
||||
} else if (next->type == SBI_TLB_FLUSH_VMA &&
|
||||
curr->type == SBI_TLB_FLUSH_VMA) {
|
||||
if (next->size == SBI_TLB_FLUSH_ALL)
|
||||
ret = SBI_FIFO_RESET;
|
||||
else
|
||||
ret = __sbi_tlb_fifo_range_check(curr, next);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sbi_tlb_fifo_update(struct sbi_scratch *scratch, u32 event, void *data)
|
||||
{
|
||||
int ret;
|
||||
struct sbi_fifo *ipi_tlb_fifo;
|
||||
struct sbi_tlb_info *tinfo = data;
|
||||
|
||||
ipi_tlb_fifo = sbi_scratch_offset_ptr(scratch,
|
||||
ipi_tlb_fifo_off);
|
||||
/*
|
||||
* If address range to flush is too big then simply
|
||||
* upgrade it to flush all because we can only flush
|
||||
* 4KB at a time.
|
||||
*/
|
||||
if (tinfo->size >= SBI_TLB_FLUSH_MAX_SIZE) {
|
||||
tinfo->start = 0;
|
||||
tinfo->size = SBI_TLB_FLUSH_ALL;
|
||||
}
|
||||
|
||||
ret = sbi_fifo_inplace_update(ipi_tlb_fifo, data,
|
||||
sbi_tlb_fifo_update_cb);
|
||||
if (ret == SBI_FIFO_SKIP || ret == SBI_FIFO_UPDATED) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (sbi_fifo_enqueue(ipi_tlb_fifo, data) < 0) {
|
||||
/**
|
||||
* For now, Busy loop until there is space in the fifo.
|
||||
* There may be case where target hart is also
|
||||
* enqueue in source hart's fifo. Both hart may busy
|
||||
* loop leading to a deadlock.
|
||||
* TODO: Introduce a wait/wakeup event mechansim to handle
|
||||
* this properly.
|
||||
*/
|
||||
__asm__ __volatile("nop");
|
||||
__asm__ __volatile("nop");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static unsigned long tlb_sync_off;
|
||||
static unsigned long tlb_fifo_off;
|
||||
static unsigned long tlb_fifo_mem_off;
|
||||
static unsigned long tlb_range_flush_limit;
|
||||
|
||||
static void sbi_tlb_flush_all(void)
|
||||
{
|
||||
__asm__ __volatile("sfence.vma");
|
||||
}
|
||||
|
||||
static void sbi_tlb_fifo_sfence_vma(struct sbi_tlb_info *tinfo)
|
||||
static void sbi_tlb_hfence_vvma(struct sbi_tlb_info *tinfo)
|
||||
{
|
||||
unsigned long start = tinfo->start;
|
||||
unsigned long size = tinfo->size;
|
||||
unsigned long i;
|
||||
|
||||
if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
|
||||
__sbi_hfence_vvma_all();
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i += PAGE_SIZE) {
|
||||
__sbi_hfence_vvma_va(start+i);
|
||||
}
|
||||
}
|
||||
|
||||
static void sbi_tlb_hfence_gvma(struct sbi_tlb_info *tinfo)
|
||||
{
|
||||
unsigned long start = tinfo->start;
|
||||
unsigned long size = tinfo->size;
|
||||
unsigned long i;
|
||||
|
||||
if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
|
||||
__sbi_hfence_gvma_all();
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i += PAGE_SIZE) {
|
||||
__sbi_hfence_gvma_gpa(start+i);
|
||||
}
|
||||
}
|
||||
|
||||
static void sbi_tlb_sfence_vma(struct sbi_tlb_info *tinfo)
|
||||
{
|
||||
unsigned long start = tinfo->start;
|
||||
unsigned long size = tinfo->size;
|
||||
@@ -150,7 +83,51 @@ static void sbi_tlb_fifo_sfence_vma(struct sbi_tlb_info *tinfo)
|
||||
}
|
||||
}
|
||||
|
||||
static void sbi_tlb_fifo_sfence_vma_asid(struct sbi_tlb_info *tinfo)
|
||||
static void sbi_tlb_hfence_vvma_asid(struct sbi_tlb_info *tinfo)
|
||||
{
|
||||
unsigned long start = tinfo->start;
|
||||
unsigned long size = tinfo->size;
|
||||
unsigned long asid = tinfo->asid;
|
||||
unsigned long i;
|
||||
|
||||
if (start == 0 && size == 0) {
|
||||
__sbi_hfence_vvma_all();
|
||||
return;
|
||||
}
|
||||
|
||||
if (size == SBI_TLB_FLUSH_ALL) {
|
||||
__sbi_hfence_vvma_asid(asid);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i += PAGE_SIZE) {
|
||||
__sbi_hfence_vvma_asid_va(asid, start + i);
|
||||
}
|
||||
}
|
||||
|
||||
static void sbi_tlb_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
|
||||
{
|
||||
unsigned long start = tinfo->start;
|
||||
unsigned long size = tinfo->size;
|
||||
unsigned long vmid = tinfo->asid;
|
||||
unsigned long i;
|
||||
|
||||
if (start == 0 && size == 0) {
|
||||
__sbi_hfence_gvma_all();
|
||||
return;
|
||||
}
|
||||
|
||||
if (size == SBI_TLB_FLUSH_ALL) {
|
||||
__sbi_hfence_gvma_vmid(vmid);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i += PAGE_SIZE) {
|
||||
__sbi_hfence_gvma_vmid_gpa(vmid, start+i);
|
||||
}
|
||||
}
|
||||
|
||||
static void sbi_tlb_sfence_vma_asid(struct sbi_tlb_info *tinfo)
|
||||
{
|
||||
unsigned long start = tinfo->start;
|
||||
unsigned long size = tinfo->size;
|
||||
@@ -179,48 +156,284 @@ static void sbi_tlb_fifo_sfence_vma_asid(struct sbi_tlb_info *tinfo)
|
||||
}
|
||||
}
|
||||
|
||||
void sbi_tlb_fifo_process(struct sbi_scratch *scratch, u32 event)
|
||||
static void sbi_tlb_local_flush(struct sbi_tlb_info *tinfo)
|
||||
{
|
||||
switch (tinfo->type) {
|
||||
case SBI_TLB_FLUSH_VMA:
|
||||
sbi_tlb_sfence_vma(tinfo);
|
||||
break;
|
||||
case SBI_TLB_FLUSH_VMA_ASID:
|
||||
sbi_tlb_sfence_vma_asid(tinfo);
|
||||
break;
|
||||
case SBI_TLB_FLUSH_GVMA:
|
||||
sbi_tlb_hfence_gvma(tinfo);
|
||||
break;
|
||||
case SBI_TLB_FLUSH_GVMA_VMID:
|
||||
sbi_tlb_hfence_gvma_vmid(tinfo);
|
||||
break;
|
||||
case SBI_TLB_FLUSH_VVMA:
|
||||
sbi_tlb_hfence_vvma(tinfo);
|
||||
break;
|
||||
case SBI_TLB_FLUSH_VVMA_ASID:
|
||||
sbi_tlb_hfence_vvma_asid(tinfo);
|
||||
break;
|
||||
case SBI_ITLB_FLUSH:
|
||||
__asm__ __volatile("fence.i");
|
||||
break;
|
||||
default:
|
||||
sbi_printf("Invalid tlb flush request type [%lu]\n",
|
||||
tinfo->type);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void sbi_tlb_entry_process(struct sbi_scratch *scratch,
|
||||
struct sbi_tlb_info *tinfo)
|
||||
{
|
||||
u32 i;
|
||||
u64 m;
|
||||
struct sbi_scratch *rscratch = NULL;
|
||||
unsigned long *rtlb_sync = NULL;
|
||||
|
||||
sbi_tlb_local_flush(tinfo);
|
||||
for (i = 0, m = tinfo->shart_mask; m; i++, m >>= 1) {
|
||||
if (!(m & 1UL))
|
||||
continue;
|
||||
|
||||
rscratch = sbi_hart_id_to_scratch(scratch, i);
|
||||
rtlb_sync = sbi_scratch_offset_ptr(rscratch, tlb_sync_off);
|
||||
while (atomic_raw_xchg_ulong(rtlb_sync, 1)) ;
|
||||
}
|
||||
}
|
||||
|
||||
static void sbi_tlb_process_count(struct sbi_scratch *scratch, int count)
|
||||
{
|
||||
struct sbi_tlb_info tinfo;
|
||||
struct sbi_fifo *ipi_tlb_fifo =
|
||||
sbi_scratch_offset_ptr(scratch, ipi_tlb_fifo_off);
|
||||
u32 deq_count = 0;
|
||||
struct sbi_fifo *tlb_fifo =
|
||||
sbi_scratch_offset_ptr(scratch, tlb_fifo_off);
|
||||
|
||||
while (!sbi_fifo_dequeue(tlb_fifo, &tinfo)) {
|
||||
sbi_tlb_entry_process(scratch, &tinfo);
|
||||
deq_count++;
|
||||
if (deq_count > count)
|
||||
break;
|
||||
|
||||
while (!sbi_fifo_dequeue(ipi_tlb_fifo, &tinfo)) {
|
||||
if (tinfo.type == SBI_TLB_FLUSH_VMA)
|
||||
sbi_tlb_fifo_sfence_vma(&tinfo);
|
||||
else if (tinfo.type == SBI_TLB_FLUSH_VMA_ASID)
|
||||
sbi_tlb_fifo_sfence_vma_asid(&tinfo);
|
||||
sbi_memset(&tinfo, 0, SBI_TLB_INFO_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
int sbi_tlb_fifo_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||
static void sbi_tlb_process(struct sbi_scratch *scratch)
|
||||
{
|
||||
void *ipi_tlb_mem;
|
||||
struct sbi_fifo *ipi_tlb_q;
|
||||
struct sbi_tlb_info tinfo;
|
||||
struct sbi_fifo *tlb_fifo =
|
||||
sbi_scratch_offset_ptr(scratch, tlb_fifo_off);
|
||||
|
||||
while (!sbi_fifo_dequeue(tlb_fifo, &tinfo))
|
||||
sbi_tlb_entry_process(scratch, &tinfo);
|
||||
}
|
||||
|
||||
static void sbi_tlb_sync(struct sbi_scratch *scratch)
|
||||
{
|
||||
unsigned long *tlb_sync =
|
||||
sbi_scratch_offset_ptr(scratch, tlb_sync_off);
|
||||
|
||||
while (!atomic_raw_xchg_ulong(tlb_sync, 0)) {
|
||||
/*
|
||||
* While we are waiting for remote hart to set the sync,
|
||||
* consume fifo requests to avoid deadlock.
|
||||
*/
|
||||
sbi_tlb_process_count(scratch, 1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static inline int __sbi_tlb_range_check(struct sbi_tlb_info *curr,
|
||||
struct sbi_tlb_info *next)
|
||||
{
|
||||
unsigned long curr_end;
|
||||
unsigned long next_end;
|
||||
int ret = SBI_FIFO_UNCHANGED;
|
||||
|
||||
if (!curr || !next)
|
||||
return ret;
|
||||
|
||||
next_end = next->start + next->size;
|
||||
curr_end = curr->start + curr->size;
|
||||
if (next->start <= curr->start && next_end > curr_end) {
|
||||
curr->start = next->start;
|
||||
curr->size = next->size;
|
||||
curr->shart_mask = curr->shart_mask | next->shart_mask;
|
||||
ret = SBI_FIFO_UPDATED;
|
||||
} else if (next->start >= curr->start && next_end <= curr_end) {
|
||||
curr->shart_mask = curr->shart_mask | next->shart_mask;
|
||||
ret = SBI_FIFO_SKIP;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call back to decide if an inplace fifo update is required or next entry can
|
||||
* can be skipped. Here are the different cases that are being handled.
|
||||
*
|
||||
* Case1:
|
||||
* if next flush request range lies within one of the existing entry, skip
|
||||
* the next entry.
|
||||
* Case2:
|
||||
* if flush request range in current fifo entry lies within next flush
|
||||
* request, update the current entry.
|
||||
*
|
||||
* Note:
|
||||
* We can not issue a fifo reset anymore if a complete vma flush is requested.
|
||||
* This is because we are queueing FENCE.I requests as well now.
|
||||
* To ease up the pressure in enqueue/fifo sync path, try to dequeue 1 element
|
||||
* before continuing the while loop. This method is preferred over wfi/ipi because
|
||||
* of MMIO cost involved in later method.
|
||||
*/
|
||||
static int sbi_tlb_update_cb(void *in, void *data)
|
||||
{
|
||||
struct sbi_tlb_info *curr;
|
||||
struct sbi_tlb_info *next;
|
||||
int ret = SBI_FIFO_UNCHANGED;
|
||||
|
||||
if (!in || !data)
|
||||
return ret;
|
||||
|
||||
curr = (struct sbi_tlb_info *)data;
|
||||
next = (struct sbi_tlb_info *)in;
|
||||
|
||||
if (next->type == SBI_TLB_FLUSH_VMA_ASID &&
|
||||
curr->type == SBI_TLB_FLUSH_VMA_ASID) {
|
||||
if (next->asid == curr->asid)
|
||||
ret = __sbi_tlb_range_check(curr, next);
|
||||
} else if (next->type == SBI_TLB_FLUSH_VMA &&
|
||||
curr->type == SBI_TLB_FLUSH_VMA) {
|
||||
ret = __sbi_tlb_range_check(curr, next);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sbi_tlb_update(struct sbi_scratch *scratch,
|
||||
struct sbi_scratch *remote_scratch,
|
||||
u32 remote_hartid, void *data)
|
||||
{
|
||||
int ret;
|
||||
struct sbi_fifo *tlb_fifo_r;
|
||||
struct sbi_tlb_info *tinfo = data;
|
||||
u32 curr_hartid = sbi_current_hartid();
|
||||
|
||||
/*
|
||||
* If address range to flush is too big then simply
|
||||
* upgrade it to flush all because we can only flush
|
||||
* 4KB at a time.
|
||||
*/
|
||||
if (tinfo->size > tlb_range_flush_limit) {
|
||||
tinfo->start = 0;
|
||||
tinfo->size = SBI_TLB_FLUSH_ALL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the request is to queue a tlb flush entry for itself
|
||||
* then just do a local flush and return;
|
||||
*/
|
||||
if (remote_hartid == curr_hartid) {
|
||||
sbi_tlb_local_flush(tinfo);
|
||||
return -1;
|
||||
}
|
||||
|
||||
tlb_fifo_r = sbi_scratch_offset_ptr(remote_scratch, tlb_fifo_off);
|
||||
|
||||
ret = sbi_fifo_inplace_update(tlb_fifo_r, data, sbi_tlb_update_cb);
|
||||
if (ret != SBI_FIFO_UNCHANGED) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (sbi_fifo_enqueue(tlb_fifo_r, data) < 0) {
|
||||
/**
|
||||
* For now, Busy loop until there is space in the fifo.
|
||||
* There may be case where target hart is also
|
||||
* enqueue in source hart's fifo. Both hart may busy
|
||||
* loop leading to a deadlock.
|
||||
* TODO: Introduce a wait/wakeup event mechanism to handle
|
||||
* this properly.
|
||||
*/
|
||||
sbi_tlb_process_count(scratch, 1);
|
||||
sbi_dprintf(remote_scratch, "hart%d: hart%d tlb fifo full\n",
|
||||
curr_hartid, remote_hartid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct sbi_ipi_event_ops tlb_ops = {
|
||||
.name = "IPI_TLB",
|
||||
.update = sbi_tlb_update,
|
||||
.sync = sbi_tlb_sync,
|
||||
.process = sbi_tlb_process,
|
||||
};
|
||||
|
||||
static u32 tlb_event = SBI_IPI_EVENT_MAX;
|
||||
|
||||
int sbi_tlb_request(struct sbi_scratch *scratch, ulong hmask,
|
||||
ulong hbase, struct sbi_tlb_info *tinfo)
|
||||
{
|
||||
return sbi_ipi_send_many(scratch, hmask, hbase, tlb_event, tinfo);
|
||||
}
|
||||
|
||||
int sbi_tlb_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||
{
|
||||
int ret;
|
||||
void *tlb_mem;
|
||||
unsigned long *tlb_sync;
|
||||
struct sbi_fifo *tlb_q;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
if (cold_boot) {
|
||||
ipi_tlb_fifo_off = sbi_scratch_alloc_offset(sizeof(*ipi_tlb_q),
|
||||
"IPI_TLB_FIFO");
|
||||
if (!ipi_tlb_fifo_off)
|
||||
tlb_sync_off = sbi_scratch_alloc_offset(sizeof(*tlb_sync),
|
||||
"IPI_TLB_SYNC");
|
||||
if (!tlb_sync_off)
|
||||
return SBI_ENOMEM;
|
||||
ipi_tlb_fifo_mem_off = sbi_scratch_alloc_offset(
|
||||
tlb_fifo_off = sbi_scratch_alloc_offset(sizeof(*tlb_q),
|
||||
"IPI_TLB_FIFO");
|
||||
if (!tlb_fifo_off) {
|
||||
sbi_scratch_free_offset(tlb_sync_off);
|
||||
return SBI_ENOMEM;
|
||||
}
|
||||
tlb_fifo_mem_off = sbi_scratch_alloc_offset(
|
||||
SBI_TLB_FIFO_NUM_ENTRIES * SBI_TLB_INFO_SIZE,
|
||||
"IPI_TLB_FIFO_MEM");
|
||||
if (!ipi_tlb_fifo_mem_off) {
|
||||
sbi_scratch_free_offset(ipi_tlb_fifo_off);
|
||||
if (!tlb_fifo_mem_off) {
|
||||
sbi_scratch_free_offset(tlb_fifo_off);
|
||||
sbi_scratch_free_offset(tlb_sync_off);
|
||||
return SBI_ENOMEM;
|
||||
}
|
||||
ret = sbi_ipi_event_create(&tlb_ops);
|
||||
if (ret < 0) {
|
||||
sbi_scratch_free_offset(tlb_fifo_mem_off);
|
||||
sbi_scratch_free_offset(tlb_fifo_off);
|
||||
sbi_scratch_free_offset(tlb_sync_off);
|
||||
return ret;
|
||||
}
|
||||
tlb_event = ret;
|
||||
tlb_range_flush_limit = sbi_platform_tlbr_flush_limit(plat);
|
||||
} else {
|
||||
if (!ipi_tlb_fifo_off ||
|
||||
!ipi_tlb_fifo_mem_off)
|
||||
if (!tlb_sync_off ||
|
||||
!tlb_fifo_off ||
|
||||
!tlb_fifo_mem_off)
|
||||
return SBI_ENOMEM;
|
||||
if (SBI_IPI_EVENT_MAX <= tlb_event)
|
||||
return SBI_ENOSPC;
|
||||
}
|
||||
|
||||
ipi_tlb_q = sbi_scratch_offset_ptr(scratch, ipi_tlb_fifo_off);
|
||||
ipi_tlb_mem = sbi_scratch_offset_ptr(scratch, ipi_tlb_fifo_mem_off);
|
||||
tlb_sync = sbi_scratch_offset_ptr(scratch, tlb_sync_off);
|
||||
tlb_q = sbi_scratch_offset_ptr(scratch, tlb_fifo_off);
|
||||
tlb_mem = sbi_scratch_offset_ptr(scratch, tlb_fifo_mem_off);
|
||||
|
||||
sbi_fifo_init(ipi_tlb_q, ipi_tlb_mem,
|
||||
*tlb_sync = 0;
|
||||
|
||||
sbi_fifo_init(tlb_q, tlb_mem,
|
||||
SBI_TLB_FIFO_NUM_ENTRIES, SBI_TLB_INFO_SIZE);
|
||||
|
||||
return 0;
|
||||
|
@@ -9,7 +9,6 @@
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include <sbi/riscv_unpriv.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
@@ -21,12 +20,17 @@
|
||||
#include <sbi/sbi_trap.h>
|
||||
|
||||
static void __noreturn sbi_trap_error(const char *msg, int rc, u32 hartid,
|
||||
ulong mcause, ulong mtval,
|
||||
struct sbi_trap_regs *regs)
|
||||
ulong mcause, ulong mtval, ulong mtval2,
|
||||
ulong mtinst, struct sbi_trap_regs *regs)
|
||||
{
|
||||
sbi_printf("%s: hart%d: %s (error %d)\n", __func__, hartid, msg, rc);
|
||||
sbi_printf("%s: hart%d: mcause=0x%" PRILX " mtval=0x%" PRILX "\n",
|
||||
__func__, hartid, mcause, mtval);
|
||||
if (misa_extension('H')) {
|
||||
sbi_printf("%s: hart%d: mtval2=0x%" PRILX
|
||||
" mtinst=0x%" PRILX "\n",
|
||||
__func__, hartid, mtval2, mtinst);
|
||||
}
|
||||
sbi_printf("%s: hart%d: mepc=0x%" PRILX " mstatus=0x%" PRILX "\n",
|
||||
__func__, hartid, regs->mepc, regs->mstatus);
|
||||
sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
|
||||
@@ -69,51 +73,124 @@ static void __noreturn sbi_trap_error(const char *msg, int rc, u32 hartid,
|
||||
* Redirect trap to lower privledge mode (S-mode or U-mode)
|
||||
*
|
||||
* @param regs pointer to register state
|
||||
* @param trap pointer to trap details
|
||||
* @param scratch pointer to sbi_scratch of current HART
|
||||
* @param epc error PC for lower privledge mode
|
||||
* @param cause exception cause for lower privledge mode
|
||||
* @param tval trap value for lower privledge mode
|
||||
*
|
||||
* @return 0 on success and negative error code on failure
|
||||
*/
|
||||
int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch,
|
||||
ulong epc, ulong cause, ulong tval)
|
||||
int sbi_trap_redirect(struct sbi_trap_regs *regs,
|
||||
struct sbi_trap_info *trap,
|
||||
struct sbi_scratch *scratch)
|
||||
{
|
||||
ulong new_mstatus, prev_mode;
|
||||
ulong hstatus, vsstatus, prev_mode;
|
||||
#if __riscv_xlen == 32
|
||||
bool prev_virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
|
||||
#else
|
||||
bool prev_virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
|
||||
#endif
|
||||
/* By default, we redirect to HS-mode */
|
||||
bool next_virt = FALSE;
|
||||
|
||||
/* Sanity check on previous mode */
|
||||
prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
|
||||
if (prev_mode != PRV_S && prev_mode != PRV_U)
|
||||
return SBI_ENOTSUPP;
|
||||
|
||||
/* For certain exceptions from VS/VU-mode we redirect to VS-mode */
|
||||
if (misa_extension('H') && prev_virt) {
|
||||
switch (trap->cause) {
|
||||
case CAUSE_FETCH_PAGE_FAULT:
|
||||
case CAUSE_LOAD_PAGE_FAULT:
|
||||
case CAUSE_STORE_PAGE_FAULT:
|
||||
next_virt = TRUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
/* Update MSTATUS MPV bits */
|
||||
#if __riscv_xlen == 32
|
||||
regs->mstatusH &= ~MSTATUSH_MPV;
|
||||
regs->mstatusH |= (next_virt) ? MSTATUSH_MPV : 0UL;
|
||||
#else
|
||||
regs->mstatus &= ~MSTATUS_MPV;
|
||||
regs->mstatus |= (next_virt) ? MSTATUS_MPV : 0UL;
|
||||
#endif
|
||||
|
||||
/* Update HSTATUS for VS/VU-mode to HS-mode transition */
|
||||
if (misa_extension('H') && prev_virt && !next_virt) {
|
||||
/* Update HSTATUS SP2P, SP2V, and SPV bits */
|
||||
hstatus = csr_read(CSR_HSTATUS);
|
||||
hstatus &= ~HSTATUS_SP2P;
|
||||
hstatus |= (regs->mstatus & MSTATUS_SPP) ? HSTATUS_SP2P : 0;
|
||||
hstatus &= ~HSTATUS_SP2V;
|
||||
hstatus |= (hstatus & HSTATUS_SPV) ? HSTATUS_SP2V : 0;
|
||||
hstatus &= ~HSTATUS_SPV;
|
||||
hstatus |= (prev_virt) ? HSTATUS_SPV : 0;
|
||||
csr_write(CSR_HSTATUS, hstatus);
|
||||
csr_write(CSR_HTVAL, trap->tval2);
|
||||
csr_write(CSR_HTINST, trap->tinst);
|
||||
}
|
||||
|
||||
/* Update exception related CSRs */
|
||||
if (next_virt) {
|
||||
/* Update VS-mode exception info */
|
||||
csr_write(CSR_VSTVAL, trap->tval);
|
||||
csr_write(CSR_VSEPC, trap->epc);
|
||||
csr_write(CSR_VSCAUSE, trap->cause);
|
||||
|
||||
/* Set MEPC to VS-mode exception vector base */
|
||||
regs->mepc = csr_read(CSR_VSTVEC);
|
||||
|
||||
/* Set MPP to VS-mode */
|
||||
regs->mstatus &= ~MSTATUS_MPP;
|
||||
regs->mstatus |= (PRV_S << MSTATUS_MPP_SHIFT);
|
||||
|
||||
/* Get VS-mode SSTATUS CSR */
|
||||
vsstatus = csr_read(CSR_VSSTATUS);
|
||||
|
||||
/* Set SPP for VS-mode */
|
||||
vsstatus &= ~SSTATUS_SPP;
|
||||
if (prev_mode == PRV_S)
|
||||
vsstatus |= (1UL << SSTATUS_SPP_SHIFT);
|
||||
|
||||
/* Set SPIE for VS-mode */
|
||||
vsstatus &= ~SSTATUS_SPIE;
|
||||
if (vsstatus & SSTATUS_SIE)
|
||||
vsstatus |= (1UL << SSTATUS_SPIE_SHIFT);
|
||||
|
||||
/* Clear SIE for VS-mode */
|
||||
vsstatus &= ~SSTATUS_SIE;
|
||||
|
||||
/* Update VS-mode SSTATUS CSR */
|
||||
csr_write(CSR_VSSTATUS, vsstatus);
|
||||
} else {
|
||||
/* Update S-mode exception info */
|
||||
csr_write(CSR_STVAL, tval);
|
||||
csr_write(CSR_SEPC, epc);
|
||||
csr_write(CSR_SCAUSE, cause);
|
||||
csr_write(CSR_STVAL, trap->tval);
|
||||
csr_write(CSR_SEPC, trap->epc);
|
||||
csr_write(CSR_SCAUSE, trap->cause);
|
||||
|
||||
/* Set MEPC to S-mode exception vector base */
|
||||
regs->mepc = csr_read(CSR_STVEC);
|
||||
|
||||
/* Initial value of new MSTATUS */
|
||||
new_mstatus = regs->mstatus;
|
||||
/* Set MPP to S-mode */
|
||||
regs->mstatus &= ~MSTATUS_MPP;
|
||||
regs->mstatus |= (PRV_S << MSTATUS_MPP_SHIFT);
|
||||
|
||||
/* Clear MPP, SPP, SPIE, and SIE */
|
||||
new_mstatus &=
|
||||
~(MSTATUS_MPP | MSTATUS_SPP | MSTATUS_SPIE | MSTATUS_SIE);
|
||||
|
||||
/* Set SPP */
|
||||
/* Set SPP for S-mode*/
|
||||
regs->mstatus &= ~MSTATUS_SPP;
|
||||
if (prev_mode == PRV_S)
|
||||
new_mstatus |= (1UL << MSTATUS_SPP_SHIFT);
|
||||
regs->mstatus |= (1UL << MSTATUS_SPP_SHIFT);
|
||||
|
||||
/* Set SPIE */
|
||||
/* Set SPIE for S-mode */
|
||||
regs->mstatus &= ~MSTATUS_SPIE;
|
||||
if (regs->mstatus & MSTATUS_SIE)
|
||||
new_mstatus |= (1UL << MSTATUS_SPIE_SHIFT);
|
||||
regs->mstatus |= (1UL << MSTATUS_SPIE_SHIFT);
|
||||
|
||||
/* Set MPP */
|
||||
new_mstatus |= (PRV_S << MSTATUS_MPP_SHIFT);
|
||||
|
||||
/* Set new value in MSTATUS */
|
||||
regs->mstatus = new_mstatus;
|
||||
/* Clear SIE for S-mode */
|
||||
regs->mstatus &= ~MSTATUS_SIE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -127,20 +204,28 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch,
|
||||
* 1. The 'mscratch' CSR is pointing to sbi_scratch of current HART
|
||||
* 2. The 'mcause' CSR is having exception/interrupt cause
|
||||
* 3. The 'mtval' CSR is having additional trap information
|
||||
* 4. Stack pointer (SP) is setup for current HART
|
||||
* 5. Interrupts are disabled in MSTATUS CSR
|
||||
* 4. The 'mtval2' CSR is having additional trap information
|
||||
* 5. The 'mtinst' CSR is having decoded trap instruction
|
||||
* 6. Stack pointer (SP) is setup for current HART
|
||||
* 7. Interrupts are disabled in MSTATUS CSR
|
||||
*
|
||||
* @param regs pointer to register state
|
||||
* @param scratch pointer to sbi_scratch of current HART
|
||||
*/
|
||||
void sbi_trap_handler(struct sbi_trap_regs *regs, struct sbi_scratch *scratch)
|
||||
void sbi_trap_handler(struct sbi_trap_regs *regs,
|
||||
struct sbi_scratch *scratch)
|
||||
{
|
||||
int rc = SBI_ENOTSUPP;
|
||||
const char *msg = "trap handler failed";
|
||||
u32 hartid = sbi_current_hartid();
|
||||
ulong mcause = csr_read(CSR_MCAUSE);
|
||||
ulong mtval = csr_read(CSR_MTVAL);
|
||||
struct unpriv_trap *uptrap;
|
||||
ulong mtval = csr_read(CSR_MTVAL), mtval2 = 0, mtinst = 0;
|
||||
struct sbi_trap_info trap, *uptrap;
|
||||
|
||||
if (misa_extension('H')) {
|
||||
mtval2 = csr_read(CSR_MTVAL2);
|
||||
mtinst = csr_read(CSR_MTINST);
|
||||
}
|
||||
|
||||
if (mcause & (1UL << (__riscv_xlen - 1))) {
|
||||
mcause &= ~(1UL << (__riscv_xlen - 1));
|
||||
@@ -160,15 +245,19 @@ void sbi_trap_handler(struct sbi_trap_regs *regs, struct sbi_scratch *scratch)
|
||||
|
||||
switch (mcause) {
|
||||
case CAUSE_ILLEGAL_INSTRUCTION:
|
||||
rc = sbi_illegal_insn_handler(hartid, mcause, regs, scratch);
|
||||
rc = sbi_illegal_insn_handler(hartid, mcause, mtval,
|
||||
regs, scratch);
|
||||
msg = "illegal instruction handler failed";
|
||||
break;
|
||||
case CAUSE_MISALIGNED_LOAD:
|
||||
rc = sbi_misaligned_load_handler(hartid, mcause, regs, scratch);
|
||||
rc = sbi_misaligned_load_handler(hartid, mcause, mtval,
|
||||
mtval2, mtinst, regs,
|
||||
scratch);
|
||||
msg = "misaligned load handler failed";
|
||||
break;
|
||||
case CAUSE_MISALIGNED_STORE:
|
||||
rc = sbi_misaligned_store_handler(hartid, mcause, regs,
|
||||
rc = sbi_misaligned_store_handler(hartid, mcause, mtval,
|
||||
mtval2, mtinst, regs,
|
||||
scratch);
|
||||
msg = "misaligned store handler failed";
|
||||
break;
|
||||
@@ -184,24 +273,36 @@ void sbi_trap_handler(struct sbi_trap_regs *regs, struct sbi_scratch *scratch)
|
||||
uptrap = sbi_hart_get_trap_info(scratch);
|
||||
if ((regs->mstatus & MSTATUS_MPRV) && uptrap) {
|
||||
rc = 0;
|
||||
regs->mepc += uptrap->ilen;
|
||||
uptrap->epc = regs->mepc;
|
||||
regs->mepc += 4;
|
||||
uptrap->cause = mcause;
|
||||
uptrap->tval = mtval;
|
||||
uptrap->tval2 = mtval2;
|
||||
uptrap->tinst = mtinst;
|
||||
} else {
|
||||
rc = sbi_trap_redirect(regs, scratch, regs->mepc,
|
||||
mcause, mtval);
|
||||
trap.epc = regs->mepc;
|
||||
trap.cause = mcause;
|
||||
trap.tval = mtval;
|
||||
trap.tval2 = mtval2;
|
||||
trap.tinst = mtinst;
|
||||
rc = sbi_trap_redirect(regs, &trap, scratch);
|
||||
}
|
||||
msg = "page/access fault handler failed";
|
||||
break;
|
||||
default:
|
||||
/* If the trap came from S or U mode, redirect it there */
|
||||
rc = sbi_trap_redirect(regs, scratch, regs->mepc, mcause, mtval);
|
||||
trap.epc = regs->mepc;
|
||||
trap.cause = mcause;
|
||||
trap.tval = mtval;
|
||||
trap.tval2 = mtval2;
|
||||
trap.tinst = mtinst;
|
||||
rc = sbi_trap_redirect(regs, &trap, scratch);
|
||||
break;
|
||||
};
|
||||
|
||||
trap_error:
|
||||
if (rc) {
|
||||
sbi_trap_error(msg, rc, hartid, mcause, csr_read(CSR_MTVAL),
|
||||
regs);
|
||||
sbi_trap_error(msg, rc, hartid, mcause, mtval,
|
||||
mtval2, mtinst, regs);
|
||||
}
|
||||
}
|
||||
|
181
lib/sbi/sbi_unpriv.c
Normal file
181
lib/sbi/sbi_unpriv.c
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include <sbi/sbi_bits.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
#include <sbi/sbi_unpriv.h>
|
||||
|
||||
#define DEFINE_UNPRIVILEGED_LOAD_FUNCTION(type, insn) \
|
||||
type sbi_load_##type(const type *addr, \
|
||||
struct sbi_scratch *scratch, \
|
||||
struct sbi_trap_info *trap) \
|
||||
{ \
|
||||
register ulong __mstatus asm("a2"); \
|
||||
type val = 0; \
|
||||
trap->epc = 0; \
|
||||
trap->cause = 0; \
|
||||
trap->tval = 0; \
|
||||
trap->tval2 = 0; \
|
||||
trap->tinst = 0; \
|
||||
sbi_hart_set_trap_info(scratch, trap); \
|
||||
asm volatile( \
|
||||
"csrrs %0, " STR(CSR_MSTATUS) ", %3\n" \
|
||||
".option push\n" \
|
||||
".option norvc\n" \
|
||||
#insn " %1, %2\n" \
|
||||
".option pop\n" \
|
||||
"csrw " STR(CSR_MSTATUS) ", %0" \
|
||||
: "+&r"(__mstatus), "=&r"(val) \
|
||||
: "m"(*addr), "r"(MSTATUS_MPRV)); \
|
||||
sbi_hart_set_trap_info(scratch, NULL); \
|
||||
return val; \
|
||||
}
|
||||
|
||||
#define DEFINE_UNPRIVILEGED_STORE_FUNCTION(type, insn) \
|
||||
void sbi_store_##type(type *addr, type val, \
|
||||
struct sbi_scratch *scratch, \
|
||||
struct sbi_trap_info *trap) \
|
||||
{ \
|
||||
register ulong __mstatus asm("a3"); \
|
||||
trap->epc = 0; \
|
||||
trap->cause = 0; \
|
||||
trap->tval = 0; \
|
||||
trap->tval2 = 0; \
|
||||
trap->tinst = 0; \
|
||||
sbi_hart_set_trap_info(scratch, trap); \
|
||||
asm volatile( \
|
||||
"csrrs %0, " STR(CSR_MSTATUS) ", %3\n" \
|
||||
".option push\n" \
|
||||
".option norvc\n" \
|
||||
#insn " %1, %2\n" \
|
||||
".option pop\n" \
|
||||
"csrw " STR(CSR_MSTATUS) ", %0" \
|
||||
: "+&r"(__mstatus) \
|
||||
: "r"(val), "m"(*addr), "r"(MSTATUS_MPRV)); \
|
||||
sbi_hart_set_trap_info(scratch, NULL); \
|
||||
}
|
||||
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u16, lhu)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s8, lb)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s16, lh)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s32, lw)
|
||||
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u8, sb)
|
||||
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u16, sh)
|
||||
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u32, sw)
|
||||
#if __riscv_xlen == 64
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld)
|
||||
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u64, sd)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld)
|
||||
#else
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw)
|
||||
|
||||
u64 sbi_load_u64(const u64 *addr,
|
||||
struct sbi_scratch *scratch,
|
||||
struct sbi_trap_info *trap)
|
||||
{
|
||||
u64 ret = sbi_load_u32((u32 *)addr, scratch, trap);
|
||||
|
||||
if (trap->cause)
|
||||
return 0;
|
||||
ret |= ((u64)sbi_load_u32((u32 *)addr + 1, scratch, trap) << 32);
|
||||
if (trap->cause)
|
||||
return 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void sbi_store_u64(u64 *addr, u64 val,
|
||||
struct sbi_scratch *scratch,
|
||||
struct sbi_trap_info *trap)
|
||||
{
|
||||
sbi_store_u32((u32 *)addr, val, scratch, trap);
|
||||
if (trap->cause)
|
||||
return;
|
||||
|
||||
sbi_store_u32((u32 *)addr + 1, val >> 32, scratch, trap);
|
||||
if (trap->cause)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
ulong sbi_get_insn(ulong mepc, struct sbi_scratch *scratch,
|
||||
struct sbi_trap_info *trap)
|
||||
{
|
||||
ulong __mstatus = 0, val = 0;
|
||||
#ifdef __riscv_compressed
|
||||
ulong rvc_mask = 3, tmp;
|
||||
#endif
|
||||
|
||||
trap->epc = 0;
|
||||
trap->cause = 0;
|
||||
trap->tval = 0;
|
||||
trap->tval2 = 0;
|
||||
trap->tinst = 0;
|
||||
sbi_hart_set_trap_info(scratch, trap);
|
||||
|
||||
#ifndef __riscv_compressed
|
||||
asm("csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n"
|
||||
".option push\n"
|
||||
".option norvc\n"
|
||||
#if __riscv_xlen == 64
|
||||
STR(LWU) " %[insn], (%[addr])\n"
|
||||
#else
|
||||
STR(LW) " %[insn], (%[addr])\n"
|
||||
#endif
|
||||
".option pop\n"
|
||||
"csrw " STR(CSR_MSTATUS) ", %[mstatus]"
|
||||
: [mstatus] "+&r"(__mstatus), [insn] "=&r"(val)
|
||||
: [mprv] "r"(MSTATUS_MPRV | MSTATUS_MXR), [addr] "r"(mepc));
|
||||
#else
|
||||
asm("csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n"
|
||||
".option push\n"
|
||||
".option norvc\n"
|
||||
"lhu %[insn], (%[addr])\n"
|
||||
".option pop\n"
|
||||
"and %[tmp], %[insn], %[rvc_mask]\n"
|
||||
"bne %[tmp], %[rvc_mask], 2f\n"
|
||||
".option push\n"
|
||||
".option norvc\n"
|
||||
"lhu %[tmp], 2(%[addr])\n"
|
||||
".option pop\n"
|
||||
"sll %[tmp], %[tmp], 16\n"
|
||||
"add %[insn], %[insn], %[tmp]\n"
|
||||
"2: csrw " STR(CSR_MSTATUS) ", %[mstatus]"
|
||||
: [mstatus] "+&r"(__mstatus), [insn] "=&r"(val), [tmp] "=&r"(tmp)
|
||||
: [mprv] "r"(MSTATUS_MPRV | MSTATUS_MXR), [addr] "r"(mepc),
|
||||
[rvc_mask] "r"(rvc_mask));
|
||||
#endif
|
||||
|
||||
sbi_hart_set_trap_info(scratch, NULL);
|
||||
|
||||
switch (trap->cause) {
|
||||
case CAUSE_LOAD_ACCESS:
|
||||
trap->cause = CAUSE_FETCH_ACCESS;
|
||||
trap->tval = mepc;
|
||||
break;
|
||||
case CAUSE_LOAD_PAGE_FAULT:
|
||||
trap->cause = CAUSE_FETCH_PAGE_FAULT;
|
||||
trap->tval = mepc;
|
||||
break;
|
||||
case CAUSE_LOAD_GUEST_PAGE_FAULT:
|
||||
trap->cause = CAUSE_FETCH_GUEST_PAGE_FAULT;
|
||||
trap->tval = mepc;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
return val;
|
||||
}
|
@@ -51,7 +51,7 @@ void plic_fdt_fixup(void *fdt, const char *compat)
|
||||
{
|
||||
u32 *cells;
|
||||
int i, cells_count;
|
||||
u32 plic_off;
|
||||
int plic_off;
|
||||
|
||||
plic_off = fdt_node_offset_by_compatible(fdt, 0, compat);
|
||||
if (plic_off < 0)
|
||||
@@ -68,7 +68,7 @@ void plic_fdt_fixup(void *fdt, const char *compat)
|
||||
|
||||
for (i = 0; i < (cells_count / 2); i++) {
|
||||
if (fdt32_to_cpu(cells[2 * i + 1]) == IRQ_M_EXT)
|
||||
cells[2 * i + 1] = fdt32_to_cpu(0xffffffff);
|
||||
cells[2 * i + 1] = cpu_to_fdt32(0xffffffff);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,13 +91,13 @@ int plic_warm_irqchip_init(u32 target_hart, int m_cntx_id, int s_cntx_id)
|
||||
plic_set_ie(s_cntx_id, i, 0);
|
||||
}
|
||||
|
||||
/* By default, enable M-mode threshold */
|
||||
/* By default, disable M-mode threshold */
|
||||
if (m_cntx_id > -1)
|
||||
plic_set_thresh(m_cntx_id, 1);
|
||||
plic_set_thresh(m_cntx_id, 0xffffffff);
|
||||
|
||||
/* By default, disable S-mode threshold */
|
||||
if (s_cntx_id > -1)
|
||||
plic_set_thresh(s_cntx_id, 0);
|
||||
plic_set_thresh(s_cntx_id, 0xffffffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -112,7 +112,7 @@ int plic_cold_irqchip_init(unsigned long base, u32 num_sources, u32 hart_count)
|
||||
|
||||
/* Configure default priorities of all IRQs */
|
||||
for (i = 1; i <= plic_num_sources; i++)
|
||||
plic_set_priority(i, 1);
|
||||
plic_set_priority(i, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -25,29 +25,6 @@ void clint_ipi_send(u32 target_hart)
|
||||
writel(1, &clint_ipi[target_hart]);
|
||||
}
|
||||
|
||||
void clint_ipi_sync(u32 target_hart)
|
||||
{
|
||||
u32 target_ipi, incoming_ipi;
|
||||
u32 source_hart = sbi_current_hartid();
|
||||
|
||||
if (clint_ipi_hart_count <= target_hart)
|
||||
return;
|
||||
|
||||
/* Wait until target HART has handled IPI */
|
||||
incoming_ipi = 0;
|
||||
while (1) {
|
||||
target_ipi = readl(&clint_ipi[target_hart]);
|
||||
if (!target_ipi)
|
||||
break;
|
||||
|
||||
incoming_ipi |=
|
||||
atomic_raw_xchg_uint(&clint_ipi[source_hart], 0);
|
||||
}
|
||||
|
||||
if (incoming_ipi)
|
||||
writel(incoming_ipi, &clint_ipi[source_hart]);
|
||||
}
|
||||
|
||||
void clint_ipi_clear(u32 target_hart)
|
||||
{
|
||||
if (clint_ipi_hart_count <= target_hart)
|
||||
@@ -85,17 +62,45 @@ static volatile void *clint_time_base;
|
||||
static volatile u64 *clint_time_val;
|
||||
static volatile u64 *clint_time_cmp;
|
||||
|
||||
#if __riscv_xlen != 32
|
||||
static u64 clint_time_rd64(volatile u64 *addr)
|
||||
{
|
||||
return readq_relaxed(addr);
|
||||
}
|
||||
|
||||
static void clint_time_wr64(u64 value, volatile u64 *addr)
|
||||
{
|
||||
writeq_relaxed(value, addr);
|
||||
}
|
||||
#endif
|
||||
|
||||
static u64 clint_time_rd32(volatile u64 *addr)
|
||||
{
|
||||
u32 lo, hi;
|
||||
|
||||
do {
|
||||
hi = readl_relaxed((u32 *)addr + 1);
|
||||
lo = readl_relaxed((u32 *)addr);
|
||||
} while (hi != readl_relaxed((u32 *)addr + 1));
|
||||
|
||||
return ((u64)hi << 32) | (u64)lo;
|
||||
}
|
||||
|
||||
static void clint_time_wr32(u64 value, volatile u64 *addr)
|
||||
{
|
||||
u32 mask = -1U;
|
||||
|
||||
writel_relaxed(value & mask, (void *)(addr));
|
||||
writel_relaxed(value >> 32, (void *)(addr) + 0x04);
|
||||
}
|
||||
|
||||
static u64 (*clint_time_rd)(volatile u64 *addr) = clint_time_rd32;
|
||||
static void (*clint_time_wr)(u64 value, volatile u64 *addr) = clint_time_wr32;
|
||||
|
||||
u64 clint_timer_value(void)
|
||||
{
|
||||
#if __riscv_xlen == 64
|
||||
return readq_relaxed(clint_time_val);
|
||||
#else
|
||||
u64 tmp;
|
||||
tmp = readl_relaxed((void *)clint_time_val + 0x04);
|
||||
tmp <<= 32;
|
||||
tmp |= readl_relaxed(clint_time_val);
|
||||
return tmp;
|
||||
#endif
|
||||
/* Read CLINT Time Value */
|
||||
return clint_time_rd(clint_time_val);
|
||||
}
|
||||
|
||||
void clint_timer_event_stop(void)
|
||||
@@ -106,12 +111,7 @@ void clint_timer_event_stop(void)
|
||||
return;
|
||||
|
||||
/* Clear CLINT Time Compare */
|
||||
#if __riscv_xlen == 64
|
||||
writeq_relaxed(-1ULL, &clint_time_cmp[target_hart]);
|
||||
#else
|
||||
writel_relaxed(-1UL, &clint_time_cmp[target_hart]);
|
||||
writel_relaxed(-1UL, (void *)(&clint_time_cmp[target_hart]) + 0x04);
|
||||
#endif
|
||||
clint_time_wr(-1ULL, &clint_time_cmp[target_hart]);
|
||||
}
|
||||
|
||||
void clint_timer_event_start(u64 next_event)
|
||||
@@ -122,14 +122,7 @@ void clint_timer_event_start(u64 next_event)
|
||||
return;
|
||||
|
||||
/* Program CLINT Time Compare */
|
||||
#if __riscv_xlen == 64
|
||||
writeq_relaxed(next_event, &clint_time_cmp[target_hart]);
|
||||
#else
|
||||
u32 mask = -1UL;
|
||||
writel_relaxed(next_event & mask, &clint_time_cmp[target_hart]);
|
||||
writel_relaxed(next_event >> 32,
|
||||
(void *)(&clint_time_cmp[target_hart]) + 0x04);
|
||||
#endif
|
||||
clint_time_wr(next_event, &clint_time_cmp[target_hart]);
|
||||
}
|
||||
|
||||
int clint_warm_timer_init(void)
|
||||
@@ -140,17 +133,13 @@ int clint_warm_timer_init(void)
|
||||
return -1;
|
||||
|
||||
/* Clear CLINT Time Compare */
|
||||
#if __riscv_xlen == 64
|
||||
writeq_relaxed(-1ULL, &clint_time_cmp[target_hart]);
|
||||
#else
|
||||
writel_relaxed(-1UL, &clint_time_cmp[target_hart]);
|
||||
writel_relaxed(-1UL, (void *)(&clint_time_cmp[target_hart]) + 0x04);
|
||||
#endif
|
||||
clint_time_wr(-1ULL, &clint_time_cmp[target_hart]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clint_cold_timer_init(unsigned long base, u32 hart_count)
|
||||
int clint_cold_timer_init(unsigned long base, u32 hart_count,
|
||||
bool has_64bit_mmio)
|
||||
{
|
||||
/* Figure-out CLINT Time register address */
|
||||
clint_time_hart_count = hart_count;
|
||||
@@ -158,5 +147,13 @@ int clint_cold_timer_init(unsigned long base, u32 hart_count)
|
||||
clint_time_val = (u64 *)(clint_time_base + 0xbff8);
|
||||
clint_time_cmp = (u64 *)(clint_time_base + 0x4000);
|
||||
|
||||
/* Override read/write accessors for 64bit MMIO */
|
||||
#if __riscv_xlen != 32
|
||||
if (has_64bit_mmio) {
|
||||
clint_time_rd = clint_time_rd64;
|
||||
clint_time_wr = clint_time_wr64;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
149
lib/utils/sys/htif.c
Normal file
149
lib/utils/sys/htif.c
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (c) 2010-2020, The Regents of the University of California
|
||||
* (Regents). All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_locks.h>
|
||||
#include <sbi_utils/sys/htif.h>
|
||||
|
||||
#define HTIF_DATA_BITS 48
|
||||
#define HTIF_DATA_MASK ((1ULL << HTIF_DATA_BITS) - 1)
|
||||
#define HTIF_DATA_SHIFT 0
|
||||
#define HTIF_CMD_BITS 8
|
||||
#define HTIF_CMD_MASK ((1ULL << HTIF_CMD_BITS) - 1)
|
||||
#define HTIF_CMD_SHIFT 48
|
||||
#define HTIF_DEV_BITS 8
|
||||
#define HTIF_DEV_MASK ((1ULL << HTIF_DEV_BITS) - 1)
|
||||
#define HTIF_DEV_SHIFT 56
|
||||
|
||||
#define HTIF_DEV_SYSTEM 0
|
||||
#define HTIF_DEV_CONSOLE 1
|
||||
|
||||
#define HTIF_CONSOLE_CMD_GETC 0
|
||||
#define HTIF_CONSOLE_CMD_PUTC 1
|
||||
|
||||
#if __riscv_xlen == 64
|
||||
# define TOHOST_CMD(dev, cmd, payload) \
|
||||
(((uint64_t)(dev) << HTIF_DEV_SHIFT) | \
|
||||
((uint64_t)(cmd) << HTIF_CMD_SHIFT) | \
|
||||
(uint64_t)(payload))
|
||||
#else
|
||||
# define TOHOST_CMD(dev, cmd, payload) ({ \
|
||||
if ((dev) || (cmd)) __builtin_trap(); \
|
||||
(payload); })
|
||||
#endif
|
||||
#define FROMHOST_DEV(fromhost_value) \
|
||||
((uint64_t)((fromhost_value) >> HTIF_DEV_SHIFT) & HTIF_DEV_MASK)
|
||||
#define FROMHOST_CMD(fromhost_value) \
|
||||
((uint64_t)((fromhost_value) >> HTIF_CMD_SHIFT) & HTIF_CMD_MASK)
|
||||
#define FROMHOST_DATA(fromhost_value) \
|
||||
((uint64_t)((fromhost_value) >> HTIF_DATA_SHIFT) & HTIF_DATA_MASK)
|
||||
|
||||
#define PK_SYS_write 64
|
||||
|
||||
volatile uint64_t tohost __attribute__((section(".htif")));
|
||||
volatile uint64_t fromhost __attribute__((section(".htif")));
|
||||
static int htif_console_buf;
|
||||
static spinlock_t htif_lock = SPIN_LOCK_INITIALIZER;
|
||||
|
||||
static void __check_fromhost()
|
||||
{
|
||||
uint64_t fh = fromhost;
|
||||
if (!fh)
|
||||
return;
|
||||
fromhost = 0;
|
||||
|
||||
/* this should be from the console */
|
||||
if (FROMHOST_DEV(fh) != HTIF_DEV_CONSOLE)
|
||||
__builtin_trap();
|
||||
switch (FROMHOST_CMD(fh)) {
|
||||
case HTIF_CONSOLE_CMD_GETC:
|
||||
htif_console_buf = 1 + (uint8_t)FROMHOST_DATA(fh);
|
||||
break;
|
||||
case HTIF_CONSOLE_CMD_PUTC:
|
||||
break;
|
||||
default:
|
||||
__builtin_trap();
|
||||
}
|
||||
}
|
||||
|
||||
static void __set_tohost(uint64_t dev, uint64_t cmd, uint64_t data)
|
||||
{
|
||||
while (tohost)
|
||||
__check_fromhost();
|
||||
tohost = TOHOST_CMD(dev, cmd, data);
|
||||
}
|
||||
|
||||
#if __riscv_xlen == 32
|
||||
static void do_tohost_fromhost(uint64_t dev, uint64_t cmd, uint64_t data)
|
||||
{
|
||||
spin_lock(&htif_lock);
|
||||
|
||||
__set_tohost(HTIF_DEV_SYSTEM, cmd, data);
|
||||
|
||||
while (1) {
|
||||
uint64_t fh = fromhost;
|
||||
if (fh) {
|
||||
if (FROMHOST_DEV(fh) == HTIF_DEV_SYSTEM &&
|
||||
FROMHOST_CMD(fh) == cmd) {
|
||||
fromhost = 0;
|
||||
break;
|
||||
}
|
||||
__check_fromhost();
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&htif_lock);
|
||||
}
|
||||
|
||||
void htif_putc(char ch)
|
||||
{
|
||||
/* HTIF devices are not supported on RV32, so do a proxy write call */
|
||||
volatile uint64_t magic_mem[8];
|
||||
magic_mem[0] = PK_SYS_write;
|
||||
magic_mem[1] = HTIF_DEV_CONSOLE;
|
||||
magic_mem[2] = (uint64_t)(uintptr_t)&ch;
|
||||
magic_mem[3] = HTIF_CONSOLE_CMD_PUTC;
|
||||
do_tohost_fromhost(HTIF_DEV_SYSTEM, 0, (uint64_t)(uintptr_t)magic_mem);
|
||||
}
|
||||
#else
|
||||
void htif_putc(char ch)
|
||||
{
|
||||
spin_lock(&htif_lock);
|
||||
__set_tohost(HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_PUTC, ch);
|
||||
spin_unlock(&htif_lock);
|
||||
}
|
||||
#endif
|
||||
|
||||
int htif_getc(void)
|
||||
{
|
||||
int ch;
|
||||
|
||||
#if __riscv_xlen == 32
|
||||
/* HTIF devices are not supported on RV32 */
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
spin_lock(&htif_lock);
|
||||
|
||||
__check_fromhost();
|
||||
ch = htif_console_buf;
|
||||
if (ch >= 0) {
|
||||
htif_console_buf = -1;
|
||||
__set_tohost(HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_GETC, 0);
|
||||
}
|
||||
|
||||
spin_unlock(&htif_lock);
|
||||
|
||||
return ch - 1;
|
||||
}
|
||||
|
||||
int htif_system_down(u32 type)
|
||||
{
|
||||
while (1) {
|
||||
fromhost = 0;
|
||||
tohost = 1;
|
||||
}
|
||||
}
|
@@ -8,3 +8,4 @@
|
||||
#
|
||||
|
||||
libsbiutils-objs-y += sys/clint.o
|
||||
libsbiutils-objs-y += sys/htif.o
|
||||
|
36
platform/andes/ae350/config.mk
Normal file
36
platform/andes/ae350/config.mk
Normal file
@@ -0,0 +1,36 @@
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2019 Andes Technology Corporation
|
||||
#
|
||||
# Authors:
|
||||
# Zong Li <zong@andestech.com>
|
||||
# Nylon Chen <nylon7@andestech.com>
|
||||
|
||||
# Compiler flags
|
||||
platform-cppflags-y =
|
||||
platform-cflags-y =
|
||||
platform-asflags-y =
|
||||
platform-ldflags-y =
|
||||
|
||||
# Blobs to build
|
||||
FW_TEXT_START=0x00000000
|
||||
|
||||
FW_DYNAMIC=y
|
||||
|
||||
FW_JUMP=y
|
||||
ifeq ($(PLATFORM_RISCV_XLEN), 32)
|
||||
FW_JUMP_ADDR=0x400000
|
||||
else
|
||||
FW_JUMP_ADDR=0x200000
|
||||
endif
|
||||
FW_JUMP_FDT_ADDR=0x2000000
|
||||
|
||||
FW_PAYLOAD=y
|
||||
ifeq ($(PLATFORM_RISCV_XLEN), 32)
|
||||
FW_PAYLOAD_OFFSET=0x400000
|
||||
else
|
||||
FW_PAYLOAD_OFFSET=0x200000
|
||||
endif
|
||||
|
||||
FW_PAYLOAD_FDT_ADDR=0x2000000
|
11
platform/andes/ae350/objects.mk
Normal file
11
platform/andes/ae350/objects.mk
Normal file
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2019 Andes Technology Corporation
|
||||
#
|
||||
# Authors:
|
||||
# Zong Li <zong@andestech.com>
|
||||
# Nylon Chen <nylon7@andestech.com>
|
||||
#
|
||||
|
||||
platform-objs-y += plicsw.o plmt.o platform.o
|
194
platform/andes/ae350/platform.c
Normal file
194
platform/andes/ae350/platform.c
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Andes Technology Corporation
|
||||
*
|
||||
* Authors:
|
||||
* Zong Li <zong@andestech.com>
|
||||
* Nylon Chen <nylon7@andestech.com>
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include <sbi/sbi_const.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi_utils/serial/uart8250.h>
|
||||
#include <sbi_utils/irqchip/plic.h>
|
||||
#include "platform.h"
|
||||
#include "plmt.h"
|
||||
#include "plicsw.h"
|
||||
|
||||
/* Platform final initialization. */
|
||||
static int ae350_final_init(bool cold_boot)
|
||||
{
|
||||
void *fdt;
|
||||
|
||||
/* enable L1 cache */
|
||||
uintptr_t mcache_ctl_val = csr_read(CSR_MCACHECTL);
|
||||
|
||||
if (!(mcache_ctl_val & V5_MCACHE_CTL_IC_EN))
|
||||
mcache_ctl_val |= V5_MCACHE_CTL_IC_EN;
|
||||
if (!(mcache_ctl_val & V5_MCACHE_CTL_DC_EN))
|
||||
mcache_ctl_val |= V5_MCACHE_CTL_DC_EN;
|
||||
if (!(mcache_ctl_val & V5_MCACHE_CTL_CCTL_SUEN))
|
||||
mcache_ctl_val |= V5_MCACHE_CTL_CCTL_SUEN;
|
||||
csr_write(CSR_MCACHECTL, mcache_ctl_val);
|
||||
|
||||
/* enable L2 cache */
|
||||
uint32_t *l2c_ctl_base = (void *)AE350_L2C_ADDR + V5_L2C_CTL_OFFSET;
|
||||
uint32_t l2c_ctl_val = *l2c_ctl_base;
|
||||
|
||||
if (!(l2c_ctl_val & V5_L2C_CTL_ENABLE_MASK))
|
||||
l2c_ctl_val |= V5_L2C_CTL_ENABLE_MASK;
|
||||
*l2c_ctl_base = l2c_ctl_val;
|
||||
|
||||
if (!cold_boot)
|
||||
return 0;
|
||||
|
||||
fdt = sbi_scratch_thishart_arg1_ptr();
|
||||
plic_fdt_fixup(fdt, "riscv,plic0");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get number of PMP regions for given HART. */
|
||||
static u32 ae350_pmp_region_count(u32 hartid)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get PMP regions details (namely: protection, base address, and size) for
|
||||
* a given HART.
|
||||
*/
|
||||
static int ae350_pmp_region_info(u32 hartid, u32 index, ulong *prot,
|
||||
ulong *addr, ulong *log2size)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (index) {
|
||||
case 0:
|
||||
*prot = PMP_R | PMP_W | PMP_X;
|
||||
*addr = 0;
|
||||
*log2size = __riscv_xlen;
|
||||
break;
|
||||
default:
|
||||
ret = -1;
|
||||
break;
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Initialize the platform console. */
|
||||
static int ae350_console_init(void)
|
||||
{
|
||||
return uart8250_init(AE350_UART_ADDR,
|
||||
AE350_UART_FREQUENCY,
|
||||
AE350_UART_BAUDRATE,
|
||||
AE350_UART_REG_SHIFT,
|
||||
AE350_UART_REG_WIDTH);
|
||||
}
|
||||
|
||||
/* Initialize the platform interrupt controller for current HART. */
|
||||
static int ae350_irqchip_init(bool cold_boot)
|
||||
{
|
||||
u32 hartid = sbi_current_hartid();
|
||||
int ret;
|
||||
|
||||
if (cold_boot) {
|
||||
ret = plic_cold_irqchip_init(AE350_PLIC_ADDR,
|
||||
AE350_PLIC_NUM_SOURCES,
|
||||
AE350_HART_COUNT);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return plic_warm_irqchip_init(hartid, 2 * hartid, 2 * hartid + 1);
|
||||
}
|
||||
|
||||
/* Initialize IPI for current HART. */
|
||||
static int ae350_ipi_init(bool cold_boot)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (cold_boot) {
|
||||
ret = plicsw_cold_ipi_init(AE350_PLICSW_ADDR,
|
||||
AE350_HART_COUNT);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return plicsw_warm_ipi_init();
|
||||
}
|
||||
|
||||
/* Initialize platform timer for current HART. */
|
||||
static int ae350_timer_init(bool cold_boot)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (cold_boot) {
|
||||
ret = plmt_cold_timer_init(AE350_PLMT_ADDR,
|
||||
AE350_HART_COUNT);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return plmt_warm_timer_init();
|
||||
}
|
||||
|
||||
/* Reboot the platform. */
|
||||
static int ae350_system_reboot(u32 type)
|
||||
{
|
||||
/* For now nothing to do. */
|
||||
sbi_printf("System reboot\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Shutdown or poweroff the platform. */
|
||||
static int ae350_system_shutdown(u32 type)
|
||||
{
|
||||
/* For now nothing to do. */
|
||||
sbi_printf("System shutdown\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Platform descriptor. */
|
||||
const struct sbi_platform_operations platform_ops = {
|
||||
|
||||
.final_init = ae350_final_init,
|
||||
|
||||
.pmp_region_count = ae350_pmp_region_count,
|
||||
.pmp_region_info = ae350_pmp_region_info,
|
||||
|
||||
.console_init = ae350_console_init,
|
||||
.console_putc = uart8250_putc,
|
||||
.console_getc = uart8250_getc,
|
||||
|
||||
.irqchip_init = ae350_irqchip_init,
|
||||
|
||||
.ipi_init = ae350_ipi_init,
|
||||
.ipi_send = plicsw_ipi_send,
|
||||
.ipi_clear = plicsw_ipi_clear,
|
||||
|
||||
.timer_init = ae350_timer_init,
|
||||
.timer_value = plmt_timer_value,
|
||||
.timer_event_start = plmt_timer_event_start,
|
||||
.timer_event_stop = plmt_timer_event_stop,
|
||||
|
||||
.system_reboot = ae350_system_reboot,
|
||||
.system_shutdown = ae350_system_shutdown
|
||||
};
|
||||
|
||||
const struct sbi_platform platform = {
|
||||
|
||||
.opensbi_version = OPENSBI_VERSION,
|
||||
.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
|
||||
.name = "Andes AE350",
|
||||
.features = SBI_PLATFORM_DEFAULT_FEATURES,
|
||||
.hart_count = AE350_HART_COUNT,
|
||||
.hart_stack_size = AE350_HART_STACK_SIZE,
|
||||
.disabled_hart_mask = 0,
|
||||
.platform_ops_addr = (unsigned long)&platform_ops
|
||||
};
|
67
platform/andes/ae350/platform.h
Normal file
67
platform/andes/ae350/platform.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Andes Technology Corporation
|
||||
*
|
||||
* Authors:
|
||||
* Zong Li <zong@andestech.com>
|
||||
* Nylon Chen <nylon7@andestech.com>
|
||||
*/
|
||||
|
||||
#ifndef _AE350_PLATFORM_H_
|
||||
#define _AE350_PLATFORM_H_
|
||||
|
||||
#define AE350_HART_COUNT 4
|
||||
#define AE350_HART_STACK_SIZE 8192
|
||||
|
||||
#define AE350_PLIC_ADDR 0xe4000000
|
||||
#define AE350_PLIC_NUM_SOURCES 71
|
||||
|
||||
#define AE350_PLICSW_ADDR 0xe6400000
|
||||
|
||||
#define AE350_PLMT_ADDR 0xe6000000
|
||||
|
||||
#define AE350_L2C_ADDR 0xe0500000
|
||||
|
||||
#define AE350_UART_ADDR_OFFSET 0x20
|
||||
#define AE350_UART_ADDR (0xf0300000 + AE350_UART_ADDR_OFFSET)
|
||||
#define AE350_UART_FREQUENCY 19660800
|
||||
#define AE350_UART_BAUDRATE 38400
|
||||
#define AE350_UART_REG_SHIFT 2
|
||||
#define AE350_UART_REG_WIDTH 0
|
||||
|
||||
/* nds mcache_ctl register*/
|
||||
#define CSR_MCACHECTL 0x7ca
|
||||
|
||||
#define V5_MCACHE_CTL_IC_EN_OFFSET 0
|
||||
#define V5_MCACHE_CTL_DC_EN_OFFSET 1
|
||||
#define V5_MCACHE_CTL_IC_ECCEN_OFFSET 2
|
||||
#define V5_MCACHE_CTL_DC_ECCEN_OFFSET 4
|
||||
#define V5_MCACHE_CTL_IC_RWECC_OFFSET 6
|
||||
#define V5_MCACHE_CTL_DC_RWECC_OFFSET 7
|
||||
#define V5_MCACHE_CTL_CCTL_SUEN_OFFSET 8
|
||||
|
||||
#define V5_MCACHE_CTL_IC_EN (1UL << V5_MCACHE_CTL_IC_EN_OFFSET)
|
||||
#define V5_MCACHE_CTL_DC_EN (1UL << V5_MCACHE_CTL_DC_EN_OFFSET)
|
||||
#define V5_MCACHE_CTL_IC_RWECC (1UL << V5_MCACHE_CTL_IC_RWECC_OFFSET)
|
||||
#define V5_MCACHE_CTL_DC_RWECC (1UL << V5_MCACHE_CTL_DC_RWECC_OFFSET)
|
||||
#define V5_MCACHE_CTL_CCTL_SUEN (1UL << V5_MCACHE_CTL_CCTL_SUEN_OFFSET)
|
||||
|
||||
#define V5_L2C_CTL_OFFSET 0x8
|
||||
#define V5_L2C_CTL_ENABLE_OFFSET 0
|
||||
#define V5_L2C_CTL_IPFDPT_OFFSET 3
|
||||
#define V5_L2C_CTL_DPFDPT_OFFSET 5
|
||||
#define V5_L2C_CTL_TRAMOCTL_OFFSET 8
|
||||
#define V5_L2C_CTL_TRAMICTL_OFFSET 10
|
||||
#define V5_L2C_CTL_DRAMOCTL_OFFSET 11
|
||||
#define V5_L2C_CTL_DRAMICTL_OFFSET 13
|
||||
|
||||
#define V5_L2C_CTL_ENABLE_MASK (1UL << V5_L2C_CTL_ENABLE_OFFSET)
|
||||
#define V5_L2C_CTL_IPFDPT_MASK (3UL << V5_L2C_CTL_IPFDPT_OFFSET)
|
||||
#define V5_L2C_CTL_DPFDPT_MASK (3UL << V5_L2C_CTL_DPFDPT_OFFSET)
|
||||
#define V5_L2C_CTL_TRAMOCTL_MASK (3UL << V5_L2C_CTL_TRAMOCTL_OFFSET)
|
||||
#define V5_L2C_CTL_TRAMICTL_MASK (1UL << V5_L2C_CTL_TRAMICTL_OFFSET)
|
||||
#define V5_L2C_CTL_DRAMOCTL_MASK (3UL << V5_L2C_CTL_DRAMOCTL_OFFSET)
|
||||
#define V5_L2C_CTL_DRAMICTL_MASK (1UL << V5_L2C_CTL_DRAMICTL_OFFSET)
|
||||
|
||||
#endif /* _AE350_PLATFORM_H_ */
|
145
platform/andes/ae350/plicsw.c
Normal file
145
platform/andes/ae350/plicsw.c
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Andes Technology Corporation
|
||||
*
|
||||
* Authors:
|
||||
* Zong Li <zong@andestech.com>
|
||||
* Nylon Chen <nylon7@andestech.com>
|
||||
*/
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/riscv_io.h>
|
||||
#include "plicsw.h"
|
||||
#include "platform.h"
|
||||
|
||||
static u32 plicsw_ipi_hart_count;
|
||||
static struct plicsw plicsw_dev[AE350_HART_COUNT];
|
||||
|
||||
static inline void plicsw_claim(void)
|
||||
{
|
||||
u32 source_hart = sbi_current_hartid();
|
||||
|
||||
plicsw_dev[source_hart].source_id =
|
||||
readl(plicsw_dev[source_hart].plicsw_claim);
|
||||
}
|
||||
|
||||
static inline void plicsw_complete(void)
|
||||
{
|
||||
u32 source_hart = sbi_current_hartid();
|
||||
u32 source = plicsw_dev[source_hart].source_id;
|
||||
|
||||
writel(source, plicsw_dev[source_hart].plicsw_claim);
|
||||
}
|
||||
|
||||
static inline u32 plicsw_get_pending(u32 source_hart, u32 target_hart)
|
||||
{
|
||||
return readl(plicsw_dev[source_hart].plicsw_pending)
|
||||
& (PLICSW_HART_MASK >> target_hart);
|
||||
}
|
||||
|
||||
static inline void plic_sw_pending(u32 target_hart)
|
||||
{
|
||||
/*
|
||||
* The pending array registers are w1s type.
|
||||
* IPI pending array mapping as following:
|
||||
*
|
||||
* Pending array start address: base + 0x1000
|
||||
* -------------------------------------
|
||||
* | hart 3 | hart 2 | hart 1 | hart 0 |
|
||||
* -------------------------------------
|
||||
* Each hart X can send IPI to another hart by setting the
|
||||
* corresponding bit in hart X own region(see the below).
|
||||
*
|
||||
* In each hart region:
|
||||
* -----------------------------------------------
|
||||
* | bit 7 | bit 6 | bit 5 | bit 4 | ... | bit 0 |
|
||||
* -----------------------------------------------
|
||||
* The bit 7 is used to send IPI to hart 0
|
||||
* The bit 6 is used to send IPI to hart 1
|
||||
* The bit 5 is used to send IPI to hart 2
|
||||
* The bit 4 is used to send IPI to hart 3
|
||||
*/
|
||||
u32 source_hart = sbi_current_hartid();
|
||||
u32 target_offset = (PLICSW_PENDING_PER_HART - 1) - target_hart;
|
||||
u32 per_hart_offset = PLICSW_PENDING_PER_HART * source_hart;
|
||||
u32 val = 1 << target_offset << per_hart_offset;
|
||||
|
||||
writel(val, plicsw_dev[source_hart].plicsw_pending);
|
||||
}
|
||||
|
||||
void plicsw_ipi_send(u32 target_hart)
|
||||
{
|
||||
if (plicsw_ipi_hart_count <= target_hart)
|
||||
return;
|
||||
|
||||
/* Set PLICSW IPI */
|
||||
plic_sw_pending(target_hart);
|
||||
}
|
||||
|
||||
void plicsw_ipi_clear(u32 target_hart)
|
||||
{
|
||||
if (plicsw_ipi_hart_count <= target_hart)
|
||||
return;
|
||||
|
||||
/* Clear CLINT IPI */
|
||||
plicsw_claim();
|
||||
plicsw_complete();
|
||||
}
|
||||
|
||||
int plicsw_warm_ipi_init(void)
|
||||
{
|
||||
u32 hartid = sbi_current_hartid();
|
||||
|
||||
if (!plicsw_dev[hartid].plicsw_pending
|
||||
&& !plicsw_dev[hartid].plicsw_enable
|
||||
&& !plicsw_dev[hartid].plicsw_claim)
|
||||
return -1;
|
||||
|
||||
/* Clear PLICSW IPI */
|
||||
plicsw_ipi_clear(hartid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plicsw_cold_ipi_init(unsigned long base, u32 hart_count)
|
||||
{
|
||||
/* Setup source priority */
|
||||
uint32_t *priority = (void *)base + PLICSW_PRIORITY_BASE;
|
||||
|
||||
for (int i = 0; i < AE350_HART_COUNT*PLICSW_PENDING_PER_HART; i++)
|
||||
writel(1, &priority[i]);
|
||||
|
||||
/* Setup target enable.*/
|
||||
uint32_t enable_mask = PLICSW_HART_MASK;
|
||||
|
||||
for (int i = 0; i < AE350_HART_COUNT; i++) {
|
||||
uint32_t *enable = (void *)base + PLICSW_ENABLE_BASE
|
||||
+ PLICSW_ENABLE_PER_HART * i;
|
||||
writel(enable_mask, &enable[0]);
|
||||
enable_mask >>= 1;
|
||||
}
|
||||
|
||||
/* Figure-out PLICSW IPI register address */
|
||||
plicsw_ipi_hart_count = hart_count;
|
||||
|
||||
for (u32 hartid = 0; hartid < AE350_HART_COUNT; hartid++) {
|
||||
plicsw_dev[hartid].source_id = 0;
|
||||
plicsw_dev[hartid].plicsw_pending =
|
||||
(void *)base
|
||||
+ PLICSW_PENDING_BASE
|
||||
+ ((hartid / 4) * 4);
|
||||
plicsw_dev[hartid].plicsw_enable =
|
||||
(void *)base
|
||||
+ PLICSW_ENABLE_BASE
|
||||
+ PLICSW_ENABLE_PER_HART * hartid;
|
||||
plicsw_dev[hartid].plicsw_claim =
|
||||
(void *)base
|
||||
+ PLICSW_CONTEXT_BASE
|
||||
+ PLICSW_CONTEXT_CLAIM
|
||||
+ PLICSW_CONTEXT_PER_HART * hartid;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
46
platform/andes/ae350/plicsw.h
Normal file
46
platform/andes/ae350/plicsw.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Andes Technology Corporation
|
||||
*
|
||||
* Authors:
|
||||
* Zong Li <zong@andestech.com>
|
||||
* Nylon Chen <nylon7@andestech.com>
|
||||
*/
|
||||
|
||||
#ifndef _AE350_PLICSW_H_
|
||||
#define _AE350_PLICSW_H_
|
||||
|
||||
#define PLICSW_PRIORITY_BASE 0x4
|
||||
|
||||
#define PLICSW_PENDING_BASE 0x1000
|
||||
#define PLICSW_PENDING_PER_HART 0x8
|
||||
|
||||
#define PLICSW_ENABLE_BASE 0x2000
|
||||
#define PLICSW_ENABLE_PER_HART 0x80
|
||||
|
||||
#define PLICSW_CONTEXT_BASE 0x200000
|
||||
#define PLICSW_CONTEXT_PER_HART 0x1000
|
||||
#define PLICSW_CONTEXT_CLAIM 0x4
|
||||
|
||||
#define PLICSW_HART_MASK 0x80808080
|
||||
|
||||
struct plicsw {
|
||||
u32 source_id;
|
||||
|
||||
volatile uint32_t *plicsw_pending;
|
||||
volatile uint32_t *plicsw_enable;
|
||||
volatile uint32_t *plicsw_claim;
|
||||
};
|
||||
|
||||
void plicsw_ipi_send(u32 target_hart);
|
||||
|
||||
void plicsw_ipi_sync(u32 target_hart);
|
||||
|
||||
void plicsw_ipi_clear(u32 target_hart);
|
||||
|
||||
int plicsw_warm_ipi_init(void);
|
||||
|
||||
int plicsw_cold_ipi_init(unsigned long base, u32 hart_count);
|
||||
|
||||
#endif /* _AE350_PLICSW_H_ */
|
97
platform/andes/ae350/plmt.c
Normal file
97
platform/andes/ae350/plmt.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Andes Technology Corporation
|
||||
*
|
||||
* Authors:
|
||||
* Zong Li <zong@andestech.com>
|
||||
* Nylon Chen <nylon7@andestech.com>
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_io.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
|
||||
static u32 plmt_time_hart_count;
|
||||
static volatile void *plmt_time_base;
|
||||
static volatile u64 *plmt_time_val;
|
||||
static volatile u64 *plmt_time_cmp;
|
||||
|
||||
u64 plmt_timer_value(void)
|
||||
{
|
||||
#if __riscv_xlen == 64
|
||||
return readq_relaxed(plmt_time_val);
|
||||
#else
|
||||
u32 lo, hi;
|
||||
|
||||
do {
|
||||
hi = readl_relaxed((void *)plmt_time_val + 0x04);
|
||||
lo = readl_relaxed(plmt_time_val);
|
||||
} while (hi != readl_relaxed((void *)plmt_time_val + 0x04));
|
||||
|
||||
return ((u64)hi << 32) | (u64)lo;
|
||||
#endif
|
||||
}
|
||||
|
||||
void plmt_timer_event_stop(void)
|
||||
{
|
||||
u32 target_hart = sbi_current_hartid();
|
||||
|
||||
if (plmt_time_hart_count <= target_hart)
|
||||
return;
|
||||
|
||||
/* Clear PLMT Time Compare */
|
||||
#if __riscv_xlen == 64
|
||||
writeq_relaxed(-1ULL, &plmt_time_cmp[target_hart]);
|
||||
#else
|
||||
writel_relaxed(-1UL, &plmt_time_cmp[target_hart]);
|
||||
writel_relaxed(-1UL, (void *)(&plmt_time_cmp[target_hart]) + 0x04);
|
||||
#endif
|
||||
}
|
||||
|
||||
void plmt_timer_event_start(u64 next_event)
|
||||
{
|
||||
u32 target_hart = sbi_current_hartid();
|
||||
|
||||
if (plmt_time_hart_count <= target_hart)
|
||||
return;
|
||||
|
||||
/* Program PLMT Time Compare */
|
||||
#if __riscv_xlen == 64
|
||||
writeq_relaxed(next_event, &plmt_time_cmp[target_hart]);
|
||||
#else
|
||||
u32 mask = -1UL;
|
||||
|
||||
writel_relaxed(next_event & mask, &plmt_time_cmp[target_hart]);
|
||||
writel_relaxed(next_event >> 32,
|
||||
(void *)(&plmt_time_cmp[target_hart]) + 0x04);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int plmt_warm_timer_init(void)
|
||||
{
|
||||
u32 target_hart = sbi_current_hartid();
|
||||
|
||||
if (plmt_time_hart_count <= target_hart || !plmt_time_base)
|
||||
return -1;
|
||||
|
||||
/* Clear PLMT Time Compare */
|
||||
#if __riscv_xlen == 64
|
||||
writeq_relaxed(-1ULL, &plmt_time_cmp[target_hart]);
|
||||
#else
|
||||
writel_relaxed(-1UL, &plmt_time_cmp[target_hart]);
|
||||
writel_relaxed(-1UL, (void *)(&plmt_time_cmp[target_hart]) + 0x04);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plmt_cold_timer_init(unsigned long base, u32 hart_count)
|
||||
{
|
||||
plmt_time_hart_count = hart_count;
|
||||
plmt_time_base = (void *)base;
|
||||
plmt_time_val = (u64 *)(plmt_time_base);
|
||||
plmt_time_cmp = (u64 *)(plmt_time_base + 0x8);
|
||||
|
||||
return 0;
|
||||
}
|
23
platform/andes/ae350/plmt.h
Normal file
23
platform/andes/ae350/plmt.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Andes Technology Corporation
|
||||
*
|
||||
* Authors:
|
||||
* Zong Li <zong@andestech.com>
|
||||
*/
|
||||
|
||||
#ifndef _AE350_PLMT_H_
|
||||
#define _AE350_PLMT_H_
|
||||
|
||||
u64 plmt_timer_value(void);
|
||||
|
||||
void plmt_timer_event_stop(void);
|
||||
|
||||
void plmt_timer_event_start(u64 next_event);
|
||||
|
||||
int plmt_warm_timer_init(void);
|
||||
|
||||
int plmt_cold_timer_init(unsigned long base, u32 hart_count);
|
||||
|
||||
#endif /* _AE350_PLMT_H_ */
|
@@ -9,11 +9,6 @@
|
||||
|
||||
PLATFORM_RISCV_XLEN = 64
|
||||
|
||||
# Common drivers to enable
|
||||
PLATFORM_SERIAL_UART8250=y
|
||||
PLATFORM_IRQCHIP_PLIC=y
|
||||
PLATFORM_SYS_CLINT=y
|
||||
|
||||
# Blobs to build
|
||||
FW_TEXT_START=0x80000000
|
||||
FW_JUMP=n
|
||||
|
@@ -145,7 +145,7 @@ static int ariane_timer_init(bool cold_boot)
|
||||
|
||||
if (cold_boot) {
|
||||
ret = clint_cold_timer_init(ARIANE_CLINT_ADDR,
|
||||
ARIANE_HART_COUNT);
|
||||
ARIANE_HART_COUNT, TRUE);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@@ -185,7 +185,6 @@ const struct sbi_platform_operations platform_ops = {
|
||||
.irqchip_init = ariane_irqchip_init,
|
||||
.ipi_init = ariane_ipi_init,
|
||||
.ipi_send = clint_ipi_send,
|
||||
.ipi_sync = clint_ipi_sync,
|
||||
.ipi_clear = clint_ipi_clear,
|
||||
.timer_init = ariane_timer_init,
|
||||
.timer_value = clint_timer_value,
|
||||
|
@@ -7,5 +7,5 @@
|
||||
# Damien Le Moal <damien.lemoal@wdc.com>
|
||||
#
|
||||
|
||||
platform-objs-y += uarths.o sysctl.o platform.o
|
||||
platform-objs-y += platform.o
|
||||
platform-dtb-y += k210.dtb
|
||||
|
@@ -14,26 +14,42 @@
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi_utils/irqchip/plic.h>
|
||||
#include <sbi_utils/sys/clint.h>
|
||||
#include <sbi_utils/serial/sifive-uart.h>
|
||||
#include "platform.h"
|
||||
#include "uarths.h"
|
||||
|
||||
#define K210_UART_BAUDRATE 115200
|
||||
static u32 k210_get_clk_freq(void)
|
||||
{
|
||||
u32 clksel0, pll0;
|
||||
u64 pll0_freq, clkr0, clkf0, clkod0, div;
|
||||
|
||||
/*
|
||||
* If the clock selector is not set, use the base frequency.
|
||||
* Otherwise, use PLL0 frequency with a frequency divisor.
|
||||
*/
|
||||
clksel0 = k210_read_sysreg(K210_CLKSEL0);
|
||||
if (!(clksel0 & 0x1))
|
||||
return K210_CLK0_FREQ;
|
||||
|
||||
/*
|
||||
* Get PLL0 frequency:
|
||||
* freq = base frequency * clkf0 / (clkr0 * clkod0)
|
||||
*/
|
||||
pll0 = k210_read_sysreg(K210_PLL0);
|
||||
clkr0 = 1 + (pll0 & 0x0000000f);
|
||||
clkf0 = 1 + ((pll0 & 0x000003f0) >> 4);
|
||||
clkod0 = 1 + ((pll0 & 0x00003c00) >> 10);
|
||||
pll0_freq = clkf0 * K210_CLK0_FREQ / (clkr0 * clkod0);
|
||||
|
||||
/* Get the frequency divisor from the clock selector */
|
||||
div = 2ULL << ((clksel0 & 0x00000006) >> 1);
|
||||
|
||||
return pll0_freq / div;
|
||||
}
|
||||
|
||||
static int k210_console_init(void)
|
||||
{
|
||||
uarths_init(K210_UART_BAUDRATE, UARTHS_STOP_1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void k210_console_putc(char c)
|
||||
{
|
||||
uarths_putc(c);
|
||||
}
|
||||
|
||||
static int k210_console_getc(void)
|
||||
{
|
||||
return uarths_getc();
|
||||
return sifive_uart_init(K210_UART_BASE_ADDR, k210_get_clk_freq(),
|
||||
K210_UART_BAUDRATE);
|
||||
}
|
||||
|
||||
static int k210_irqchip_init(bool cold_boot)
|
||||
@@ -42,13 +58,14 @@ static int k210_irqchip_init(bool cold_boot)
|
||||
u32 hartid = sbi_current_hartid();
|
||||
|
||||
if (cold_boot) {
|
||||
rc = plic_cold_irqchip_init(PLIC_BASE_ADDR, PLIC_NUM_SOURCES,
|
||||
rc = plic_cold_irqchip_init(K210_PLIC_BASE_ADDR,
|
||||
K210_PLIC_NUM_SOURCES,
|
||||
K210_HART_COUNT);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return plic_warm_irqchip_init(hartid, (2 * hartid), (2 * hartid + 1));
|
||||
return plic_warm_irqchip_init(hartid, hartid * 2, hartid * 2 + 1);
|
||||
}
|
||||
|
||||
static int k210_ipi_init(bool cold_boot)
|
||||
@@ -56,7 +73,8 @@ static int k210_ipi_init(bool cold_boot)
|
||||
int rc;
|
||||
|
||||
if (cold_boot) {
|
||||
rc = clint_cold_ipi_init(CLINT_BASE_ADDR, K210_HART_COUNT);
|
||||
rc = clint_cold_ipi_init(K210_CLINT_BASE_ADDR,
|
||||
K210_HART_COUNT);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
@@ -69,7 +87,8 @@ static int k210_timer_init(bool cold_boot)
|
||||
int rc;
|
||||
|
||||
if (cold_boot) {
|
||||
rc = clint_cold_timer_init(CLINT_BASE_ADDR, K210_HART_COUNT);
|
||||
rc = clint_cold_timer_init(K210_CLINT_BASE_ADDR,
|
||||
K210_HART_COUNT, TRUE);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
@@ -95,14 +114,13 @@ static int k210_system_shutdown(u32 type)
|
||||
|
||||
const struct sbi_platform_operations platform_ops = {
|
||||
.console_init = k210_console_init,
|
||||
.console_putc = k210_console_putc,
|
||||
.console_getc = k210_console_getc,
|
||||
.console_putc = sifive_uart_putc,
|
||||
.console_getc = sifive_uart_getc,
|
||||
|
||||
.irqchip_init = k210_irqchip_init,
|
||||
|
||||
.ipi_init = k210_ipi_init,
|
||||
.ipi_send = clint_ipi_send,
|
||||
.ipi_sync = clint_ipi_sync,
|
||||
.ipi_clear = clint_ipi_clear,
|
||||
|
||||
.timer_init = k210_timer_init,
|
||||
|
@@ -1,178 +1,37 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright 2018 Canaan Inc.
|
||||
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* Authors:
|
||||
* Damien Le Moal <damien.lemoal@wdc.com>
|
||||
*/
|
||||
#ifndef _K210_PLATFORM_H_
|
||||
#define _K210_PLATFORM_H_
|
||||
|
||||
#ifndef _PLATFORM_H_
|
||||
#define _PLATFORM_H_
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
|
||||
/* clang-format off */
|
||||
#include <sbi/riscv_io.h>
|
||||
|
||||
#define K210_HART_COUNT 2
|
||||
#define K210_HART_STACK_SIZE 4096
|
||||
|
||||
/* Register base address */
|
||||
#define K210_UART_BAUDRATE 115200
|
||||
|
||||
/* Under Coreplex */
|
||||
#define CLINT_BASE_ADDR (0x02000000U)
|
||||
#define PLIC_BASE_ADDR (0x0C000000U)
|
||||
#define PLIC_NUM_CORES (K210_HART_COUNT)
|
||||
#define K210_CLK0_FREQ 26000000UL
|
||||
#define K210_PLIC_NUM_SOURCES 65
|
||||
|
||||
/* Under TileLink */
|
||||
#define GPIOHS_BASE_ADDR (0x38001000U)
|
||||
/* Registers base address */
|
||||
#define K210_SYSCTL_BASE_ADDR 0x50440000ULL
|
||||
#define K210_UART_BASE_ADDR 0x38000000ULL
|
||||
#define K210_CLINT_BASE_ADDR 0x02000000ULL
|
||||
#define K210_PLIC_BASE_ADDR 0x0C000000ULL
|
||||
|
||||
/* Under AXI 64 bit */
|
||||
#define RAM_BASE_ADDR (0x80000000U)
|
||||
#define RAM_SIZE (6 * 1024 * 1024U)
|
||||
/* Registers */
|
||||
#define K210_PLL0 0x08
|
||||
#define K210_CLKSEL0 0x20
|
||||
|
||||
#define IO_BASE_ADDR (0x40000000U)
|
||||
#define IO_SIZE (6 * 1024 * 1024U)
|
||||
static inline u32 k210_read_sysreg(u32 reg)
|
||||
{
|
||||
return readl((volatile void *)(K210_SYSCTL_BASE_ADDR + reg));
|
||||
}
|
||||
|
||||
#define AI_RAM_BASE_ADDR (0x80600000U)
|
||||
#define AI_RAM_SIZE (2 * 1024 * 1024U)
|
||||
|
||||
#define AI_IO_BASE_ADDR (0x40600000U)
|
||||
#define AI_IO_SIZE (2 * 1024 * 1024U)
|
||||
|
||||
#define AI_BASE_ADDR (0x40800000U)
|
||||
#define AI_SIZE (12 * 1024 * 1024U)
|
||||
|
||||
#define FFT_BASE_ADDR (0x42000000U)
|
||||
#define FFT_SIZE (4 * 1024 * 1024U)
|
||||
|
||||
#define ROM_BASE_ADDR (0x88000000U)
|
||||
#define ROM_SIZE (128 * 1024U)
|
||||
|
||||
/* Under AHB 32 bit */
|
||||
#define DMAC_BASE_ADDR (0x50000000U)
|
||||
|
||||
/* Under APB1 32 bit */
|
||||
#define GPIO_BASE_ADDR (0x50200000U)
|
||||
#define UART1_BASE_ADDR (0x50210000U)
|
||||
#define UART2_BASE_ADDR (0x50220000U)
|
||||
#define UART3_BASE_ADDR (0x50230000U)
|
||||
#define SPI_SLAVE_BASE_ADDR (0x50240000U)
|
||||
#define I2S0_BASE_ADDR (0x50250000U)
|
||||
#define I2S1_BASE_ADDR (0x50260000U)
|
||||
#define I2S2_BASE_ADDR (0x50270000U)
|
||||
#define I2C0_BASE_ADDR (0x50280000U)
|
||||
#define I2C1_BASE_ADDR (0x50290000U)
|
||||
#define I2C2_BASE_ADDR (0x502A0000U)
|
||||
#define FPIOA_BASE_ADDR (0x502B0000U)
|
||||
#define SHA256_BASE_ADDR (0x502C0000U)
|
||||
#define TIMER0_BASE_ADDR (0x502D0000U)
|
||||
#define TIMER1_BASE_ADDR (0x502E0000U)
|
||||
#define TIMER2_BASE_ADDR (0x502F0000U)
|
||||
|
||||
/* Under APB2 32 bit */
|
||||
#define WDT0_BASE_ADDR (0x50400000U)
|
||||
#define WDT1_BASE_ADDR (0x50410000U)
|
||||
#define OTP_BASE_ADDR (0x50420000U)
|
||||
#define DVP_BASE_ADDR (0x50430000U)
|
||||
#define SYSCTL_BASE_ADDR (0x50440000U)
|
||||
#define AES_BASE_ADDR (0x50450000U)
|
||||
#define RTC_BASE_ADDR (0x50460000U)
|
||||
|
||||
/* Under APB3 32 bit */
|
||||
#define SPI0_BASE_ADDR (0x52000000U)
|
||||
#define SPI1_BASE_ADDR (0x53000000U)
|
||||
#define SPI3_BASE_ADDR (0x54000000U)
|
||||
|
||||
#define read_cycle() csr_read(CSR_MCYCLE)
|
||||
|
||||
/*
|
||||
* PLIC External Interrupt Numbers
|
||||
*/
|
||||
enum plic_irq {
|
||||
IRQN_NO_INTERRUPT = 0, /*!< The non-existent interrupt */
|
||||
IRQN_SPI0_INTERRUPT = 1, /*!< SPI0 interrupt */
|
||||
IRQN_SPI1_INTERRUPT = 2, /*!< SPI1 interrupt */
|
||||
IRQN_SPI_SLAVE_INTERRUPT = 3, /*!< SPI_SLAVE interrupt */
|
||||
IRQN_SPI3_INTERRUPT = 4, /*!< SPI3 interrupt */
|
||||
IRQN_I2S0_INTERRUPT = 5, /*!< I2S0 interrupt */
|
||||
IRQN_I2S1_INTERRUPT = 6, /*!< I2S1 interrupt */
|
||||
IRQN_I2S2_INTERRUPT = 7, /*!< I2S2 interrupt */
|
||||
IRQN_I2C0_INTERRUPT = 8, /*!< I2C0 interrupt */
|
||||
IRQN_I2C1_INTERRUPT = 9, /*!< I2C1 interrupt */
|
||||
IRQN_I2C2_INTERRUPT = 10, /*!< I2C2 interrupt */
|
||||
IRQN_UART1_INTERRUPT = 11, /*!< UART1 interrupt */
|
||||
IRQN_UART2_INTERRUPT = 12, /*!< UART2 interrupt */
|
||||
IRQN_UART3_INTERRUPT = 13, /*!< UART3 interrupt */
|
||||
IRQN_TIMER0A_INTERRUPT = 14, /*!< TIMER0 channel 0 or 1 interrupt */
|
||||
IRQN_TIMER0B_INTERRUPT = 15, /*!< TIMER0 channel 2 or 3 interrupt */
|
||||
IRQN_TIMER1A_INTERRUPT = 16, /*!< TIMER1 channel 0 or 1 interrupt */
|
||||
IRQN_TIMER1B_INTERRUPT = 17, /*!< TIMER1 channel 2 or 3 interrupt */
|
||||
IRQN_TIMER2A_INTERRUPT = 18, /*!< TIMER2 channel 0 or 1 interrupt */
|
||||
IRQN_TIMER2B_INTERRUPT = 19, /*!< TIMER2 channel 2 or 3 interrupt */
|
||||
IRQN_RTC_INTERRUPT = 20, /*!< RTC tick and alarm interrupt */
|
||||
IRQN_WDT0_INTERRUPT = 21, /*!< Watching dog timer0 interrupt */
|
||||
IRQN_WDT1_INTERRUPT = 22, /*!< Watching dog timer1 interrupt */
|
||||
IRQN_APB_GPIO_INTERRUPT = 23, /*!< APB GPIO interrupt */
|
||||
IRQN_DVP_INTERRUPT = 24, /*!< Digital video port interrupt */
|
||||
IRQN_AI_INTERRUPT = 25, /*!< AI accelerator interrupt */
|
||||
IRQN_FFT_INTERRUPT = 26, /*!< FFT accelerator interrupt */
|
||||
IRQN_DMA0_INTERRUPT = 27, /*!< DMA channel0 interrupt */
|
||||
IRQN_DMA1_INTERRUPT = 28, /*!< DMA channel1 interrupt */
|
||||
IRQN_DMA2_INTERRUPT = 29, /*!< DMA channel2 interrupt */
|
||||
IRQN_DMA3_INTERRUPT = 30, /*!< DMA channel3 interrupt */
|
||||
IRQN_DMA4_INTERRUPT = 31, /*!< DMA channel4 interrupt */
|
||||
IRQN_DMA5_INTERRUPT = 32, /*!< DMA channel5 interrupt */
|
||||
IRQN_UARTHS_INTERRUPT = 33, /*!< Hi-speed UART0 interrupt */
|
||||
IRQN_GPIOHS0_INTERRUPT = 34, /*!< Hi-speed GPIO0 interrupt */
|
||||
IRQN_GPIOHS1_INTERRUPT = 35, /*!< Hi-speed GPIO1 interrupt */
|
||||
IRQN_GPIOHS2_INTERRUPT = 36, /*!< Hi-speed GPIO2 interrupt */
|
||||
IRQN_GPIOHS3_INTERRUPT = 37, /*!< Hi-speed GPIO3 interrupt */
|
||||
IRQN_GPIOHS4_INTERRUPT = 38, /*!< Hi-speed GPIO4 interrupt */
|
||||
IRQN_GPIOHS5_INTERRUPT = 39, /*!< Hi-speed GPIO5 interrupt */
|
||||
IRQN_GPIOHS6_INTERRUPT = 40, /*!< Hi-speed GPIO6 interrupt */
|
||||
IRQN_GPIOHS7_INTERRUPT = 41, /*!< Hi-speed GPIO7 interrupt */
|
||||
IRQN_GPIOHS8_INTERRUPT = 42, /*!< Hi-speed GPIO8 interrupt */
|
||||
IRQN_GPIOHS9_INTERRUPT = 43, /*!< Hi-speed GPIO9 interrupt */
|
||||
IRQN_GPIOHS10_INTERRUPT = 44, /*!< Hi-speed GPIO10 interrupt */
|
||||
IRQN_GPIOHS11_INTERRUPT = 45, /*!< Hi-speed GPIO11 interrupt */
|
||||
IRQN_GPIOHS12_INTERRUPT = 46, /*!< Hi-speed GPIO12 interrupt */
|
||||
IRQN_GPIOHS13_INTERRUPT = 47, /*!< Hi-speed GPIO13 interrupt */
|
||||
IRQN_GPIOHS14_INTERRUPT = 48, /*!< Hi-speed GPIO14 interrupt */
|
||||
IRQN_GPIOHS15_INTERRUPT = 49, /*!< Hi-speed GPIO15 interrupt */
|
||||
IRQN_GPIOHS16_INTERRUPT = 50, /*!< Hi-speed GPIO16 interrupt */
|
||||
IRQN_GPIOHS17_INTERRUPT = 51, /*!< Hi-speed GPIO17 interrupt */
|
||||
IRQN_GPIOHS18_INTERRUPT = 52, /*!< Hi-speed GPIO18 interrupt */
|
||||
IRQN_GPIOHS19_INTERRUPT = 53, /*!< Hi-speed GPIO19 interrupt */
|
||||
IRQN_GPIOHS20_INTERRUPT = 54, /*!< Hi-speed GPIO20 interrupt */
|
||||
IRQN_GPIOHS21_INTERRUPT = 55, /*!< Hi-speed GPIO21 interrupt */
|
||||
IRQN_GPIOHS22_INTERRUPT = 56, /*!< Hi-speed GPIO22 interrupt */
|
||||
IRQN_GPIOHS23_INTERRUPT = 57, /*!< Hi-speed GPIO23 interrupt */
|
||||
IRQN_GPIOHS24_INTERRUPT = 58, /*!< Hi-speed GPIO24 interrupt */
|
||||
IRQN_GPIOHS25_INTERRUPT = 59, /*!< Hi-speed GPIO25 interrupt */
|
||||
IRQN_GPIOHS26_INTERRUPT = 60, /*!< Hi-speed GPIO26 interrupt */
|
||||
IRQN_GPIOHS27_INTERRUPT = 61, /*!< Hi-speed GPIO27 interrupt */
|
||||
IRQN_GPIOHS28_INTERRUPT = 62, /*!< Hi-speed GPIO28 interrupt */
|
||||
IRQN_GPIOHS29_INTERRUPT = 63, /*!< Hi-speed GPIO29 interrupt */
|
||||
IRQN_GPIOHS30_INTERRUPT = 64, /*!< Hi-speed GPIO30 interrupt */
|
||||
IRQN_GPIOHS31_INTERRUPT = 65, /*!< Hi-speed GPIO31 interrupt */
|
||||
IRQN_MAX
|
||||
};
|
||||
|
||||
/* IRQ number settings */
|
||||
#define PLIC_NUM_SOURCES (IRQN_MAX - 1)
|
||||
#define PLIC_NUM_PRIORITIES (7)
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
#endif /* _PLATFORM_H_ */
|
||||
#endif /* _K210_PLATFORM_H_ */
|
||||
|
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Copyright 2018 Canaan Inc.
|
||||
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include "sysctl.h"
|
||||
|
||||
volatile sysctl_t *const sysctl = (volatile sysctl_t *)SYSCTL_BASE_ADDR;
|
||||
|
||||
#define SYSCTRL_CLOCK_FREQ_IN0 (26000000UL)
|
||||
|
||||
static u32 sysctl_pll0_get_freq(void)
|
||||
{
|
||||
u32 freq_in, nr, nf, od;
|
||||
|
||||
freq_in = SYSCTRL_CLOCK_FREQ_IN0;
|
||||
nr = sysctl->pll0.clkr0 + 1;
|
||||
nf = sysctl->pll0.clkf0 + 1;
|
||||
od = sysctl->pll0.clkod0 + 1;
|
||||
|
||||
/*
|
||||
* Get final PLL output freq
|
||||
* FOUT = FIN / NR * NF / OD
|
||||
* = (FIN * NF) / (NR * OD)
|
||||
*/
|
||||
return ((u64)freq_in * (u64)nf) / ((u64)nr * (u64)od);
|
||||
}
|
||||
|
||||
u32 sysctl_get_cpu_freq(void)
|
||||
{
|
||||
int clock_source;
|
||||
|
||||
clock_source = (int)sysctl->clk_sel0.aclk_sel;
|
||||
switch (clock_source) {
|
||||
case 0:
|
||||
return SYSCTRL_CLOCK_FREQ_IN0;
|
||||
case 1:
|
||||
return sysctl_pll0_get_freq() /
|
||||
(2ULL << (int)sysctl->clk_sel0.aclk_divider_sel);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
@@ -1,794 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Copyright 2018 Canaan Inc.
|
||||
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef _K210_SYSCTL_H_
|
||||
#define _K210_SYSCTL_H_
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
#include "platform.h"
|
||||
|
||||
/**
|
||||
* System controller registers
|
||||
*
|
||||
* | Offset | Name | Description |
|
||||
* |-----------|----------------|-------------------------------------|
|
||||
* | 0x00 | git_id | Git short commit id |
|
||||
* | 0x04 | clk_freq | System clock base frequency |
|
||||
* | 0x08 | pll0 | PLL0 controller |
|
||||
* | 0x0c | pll1 | PLL1 controller |
|
||||
* | 0x10 | pll2 | PLL2 controller |
|
||||
* | 0x14 | resv5 | Reserved |
|
||||
* | 0x18 | pll_lock | PLL lock tester |
|
||||
* | 0x1c | rom_error | AXI ROM detector |
|
||||
* | 0x20 | clk_sel0 | Clock select controller0 |
|
||||
* | 0x24 | clk_sel1 | Clock select controller1 |
|
||||
* | 0x28 | clk_en_cent | Central clock enable |
|
||||
* | 0x2c | clk_en_peri | Peripheral clock enable |
|
||||
* | 0x30 | soft_reset | Soft reset ctrl |
|
||||
* | 0x34 | peri_reset | Peripheral reset controller |
|
||||
* | 0x38 | clk_th0 | Clock threshold controller 0 |
|
||||
* | 0x3c | clk_th1 | Clock threshold controller 1 |
|
||||
* | 0x40 | clk_th2 | Clock threshold controller 2 |
|
||||
* | 0x44 | clk_th3 | Clock threshold controller 3 |
|
||||
* | 0x48 | clk_th4 | Clock threshold controller 4 |
|
||||
* | 0x4c | clk_th5 | Clock threshold controller 5 |
|
||||
* | 0x50 | clk_th6 | Clock threshold controller 6 |
|
||||
* | 0x54 | misc | Miscellaneous controller |
|
||||
* | 0x58 | peri | Peripheral controller |
|
||||
* | 0x5c | spi_sleep | SPI sleep controller |
|
||||
* | 0x60 | reset_status | Reset source status |
|
||||
* | 0x64 | dma_sel0 | DMA handshake selector |
|
||||
* | 0x68 | dma_sel1 | DMA handshake selector |
|
||||
* | 0x6c | power_sel | IO Power Mode Select controller |
|
||||
* | 0x70 | resv28 | Reserved |
|
||||
* | 0x74 | resv29 | Reserved |
|
||||
* | 0x78 | resv30 | Reserved |
|
||||
* | 0x7c | resv31 | Reserved |
|
||||
*/
|
||||
|
||||
typedef enum _sysctl_pll_t {
|
||||
SYSCTL_PLL0,
|
||||
SYSCTL_PLL1,
|
||||
SYSCTL_PLL2,
|
||||
SYSCTL_PLL_MAX
|
||||
} sysctl_pll_t;
|
||||
|
||||
typedef enum _sysctl_clock_source_t {
|
||||
SYSCTL_SOURCE_IN0,
|
||||
SYSCTL_SOURCE_PLL0,
|
||||
SYSCTL_SOURCE_PLL1,
|
||||
SYSCTL_SOURCE_PLL2,
|
||||
SYSCTL_SOURCE_ACLK,
|
||||
SYSCTL_SOURCE_MAX
|
||||
} sysctl_clock_source_t;
|
||||
|
||||
typedef enum _sysctl_dma_channel_t {
|
||||
SYSCTL_DMA_CHANNEL_0,
|
||||
SYSCTL_DMA_CHANNEL_1,
|
||||
SYSCTL_DMA_CHANNEL_2,
|
||||
SYSCTL_DMA_CHANNEL_3,
|
||||
SYSCTL_DMA_CHANNEL_4,
|
||||
SYSCTL_DMA_CHANNEL_5,
|
||||
SYSCTL_DMA_CHANNEL_MAX
|
||||
} sysctl_dma_channel_t;
|
||||
|
||||
typedef enum _sysctl_dma_select_t {
|
||||
SYSCTL_DMA_SELECT_SSI0_RX_REQ,
|
||||
SYSCTL_DMA_SELECT_SSI0_TX_REQ,
|
||||
SYSCTL_DMA_SELECT_SSI1_RX_REQ,
|
||||
SYSCTL_DMA_SELECT_SSI1_TX_REQ,
|
||||
SYSCTL_DMA_SELECT_SSI2_RX_REQ,
|
||||
SYSCTL_DMA_SELECT_SSI2_TX_REQ,
|
||||
SYSCTL_DMA_SELECT_SSI3_RX_REQ,
|
||||
SYSCTL_DMA_SELECT_SSI3_TX_REQ,
|
||||
SYSCTL_DMA_SELECT_I2C0_RX_REQ,
|
||||
SYSCTL_DMA_SELECT_I2C0_TX_REQ,
|
||||
SYSCTL_DMA_SELECT_I2C1_RX_REQ,
|
||||
SYSCTL_DMA_SELECT_I2C1_TX_REQ,
|
||||
SYSCTL_DMA_SELECT_I2C2_RX_REQ,
|
||||
SYSCTL_DMA_SELECT_I2C2_TX_REQ,
|
||||
SYSCTL_DMA_SELECT_UART1_RX_REQ,
|
||||
SYSCTL_DMA_SELECT_UART1_TX_REQ,
|
||||
SYSCTL_DMA_SELECT_UART2_RX_REQ,
|
||||
SYSCTL_DMA_SELECT_UART2_TX_REQ,
|
||||
SYSCTL_DMA_SELECT_UART3_RX_REQ,
|
||||
SYSCTL_DMA_SELECT_UART3_TX_REQ,
|
||||
SYSCTL_DMA_SELECT_AES_REQ,
|
||||
SYSCTL_DMA_SELECT_SHA_RX_REQ,
|
||||
SYSCTL_DMA_SELECT_AI_RX_REQ,
|
||||
SYSCTL_DMA_SELECT_FFT_RX_REQ,
|
||||
SYSCTL_DMA_SELECT_FFT_TX_REQ,
|
||||
SYSCTL_DMA_SELECT_I2S0_TX_REQ,
|
||||
SYSCTL_DMA_SELECT_I2S0_RX_REQ,
|
||||
SYSCTL_DMA_SELECT_I2S1_TX_REQ,
|
||||
SYSCTL_DMA_SELECT_I2S1_RX_REQ,
|
||||
SYSCTL_DMA_SELECT_I2S2_TX_REQ,
|
||||
SYSCTL_DMA_SELECT_I2S2_RX_REQ,
|
||||
SYSCTL_DMA_SELECT_I2S0_BF_DIR_REQ,
|
||||
SYSCTL_DMA_SELECT_I2S0_BF_VOICE_REQ,
|
||||
SYSCTL_DMA_SELECT_MAX
|
||||
} sysctl_dma_select_t;
|
||||
|
||||
/**
|
||||
* System controller clock id
|
||||
*/
|
||||
typedef enum _sysctl_clock_t {
|
||||
SYSCTL_CLOCK_PLL0,
|
||||
SYSCTL_CLOCK_PLL1,
|
||||
SYSCTL_CLOCK_PLL2,
|
||||
SYSCTL_CLOCK_CPU,
|
||||
SYSCTL_CLOCK_SRAM0,
|
||||
SYSCTL_CLOCK_SRAM1,
|
||||
SYSCTL_CLOCK_APB0,
|
||||
SYSCTL_CLOCK_APB1,
|
||||
SYSCTL_CLOCK_APB2,
|
||||
SYSCTL_CLOCK_ROM,
|
||||
SYSCTL_CLOCK_DMA,
|
||||
SYSCTL_CLOCK_AI,
|
||||
SYSCTL_CLOCK_DVP,
|
||||
SYSCTL_CLOCK_FFT,
|
||||
SYSCTL_CLOCK_GPIO,
|
||||
SYSCTL_CLOCK_SPI0,
|
||||
SYSCTL_CLOCK_SPI1,
|
||||
SYSCTL_CLOCK_SPI2,
|
||||
SYSCTL_CLOCK_SPI3,
|
||||
SYSCTL_CLOCK_I2S0,
|
||||
SYSCTL_CLOCK_I2S1,
|
||||
SYSCTL_CLOCK_I2S2,
|
||||
SYSCTL_CLOCK_I2C0,
|
||||
SYSCTL_CLOCK_I2C1,
|
||||
SYSCTL_CLOCK_I2C2,
|
||||
SYSCTL_CLOCK_UART1,
|
||||
SYSCTL_CLOCK_UART2,
|
||||
SYSCTL_CLOCK_UART3,
|
||||
SYSCTL_CLOCK_AES,
|
||||
SYSCTL_CLOCK_FPIOA,
|
||||
SYSCTL_CLOCK_TIMER0,
|
||||
SYSCTL_CLOCK_TIMER1,
|
||||
SYSCTL_CLOCK_TIMER2,
|
||||
SYSCTL_CLOCK_WDT0,
|
||||
SYSCTL_CLOCK_WDT1,
|
||||
SYSCTL_CLOCK_SHA,
|
||||
SYSCTL_CLOCK_OTP,
|
||||
SYSCTL_CLOCK_RTC,
|
||||
SYSCTL_CLOCK_ACLK = 40,
|
||||
SYSCTL_CLOCK_HCLK,
|
||||
SYSCTL_CLOCK_IN0,
|
||||
SYSCTL_CLOCK_MAX
|
||||
} sysctl_clock_t;
|
||||
|
||||
/**
|
||||
* System controller clock select id
|
||||
*/
|
||||
typedef enum _sysctl_clock_select_t {
|
||||
SYSCTL_CLOCK_SELECT_PLL0_BYPASS,
|
||||
SYSCTL_CLOCK_SELECT_PLL1_BYPASS,
|
||||
SYSCTL_CLOCK_SELECT_PLL2_BYPASS,
|
||||
SYSCTL_CLOCK_SELECT_PLL2,
|
||||
SYSCTL_CLOCK_SELECT_ACLK,
|
||||
SYSCTL_CLOCK_SELECT_SPI3,
|
||||
SYSCTL_CLOCK_SELECT_TIMER0,
|
||||
SYSCTL_CLOCK_SELECT_TIMER1,
|
||||
SYSCTL_CLOCK_SELECT_TIMER2,
|
||||
SYSCTL_CLOCK_SELECT_SPI3_SAMPLE,
|
||||
SYSCTL_CLOCK_SELECT_MAX = 11
|
||||
} sysctl_clock_select_t;
|
||||
|
||||
/**
|
||||
* System controller clock threshold id
|
||||
*/
|
||||
typedef enum _sysctl_threshold_t {
|
||||
SYSCTL_THRESHOLD_ACLK,
|
||||
SYSCTL_THRESHOLD_APB0,
|
||||
SYSCTL_THRESHOLD_APB1,
|
||||
SYSCTL_THRESHOLD_APB2,
|
||||
SYSCTL_THRESHOLD_SRAM0,
|
||||
SYSCTL_THRESHOLD_SRAM1,
|
||||
SYSCTL_THRESHOLD_AI,
|
||||
SYSCTL_THRESHOLD_DVP,
|
||||
SYSCTL_THRESHOLD_ROM,
|
||||
SYSCTL_THRESHOLD_SPI0,
|
||||
SYSCTL_THRESHOLD_SPI1,
|
||||
SYSCTL_THRESHOLD_SPI2,
|
||||
SYSCTL_THRESHOLD_SPI3,
|
||||
SYSCTL_THRESHOLD_TIMER0,
|
||||
SYSCTL_THRESHOLD_TIMER1,
|
||||
SYSCTL_THRESHOLD_TIMER2,
|
||||
SYSCTL_THRESHOLD_I2S0,
|
||||
SYSCTL_THRESHOLD_I2S1,
|
||||
SYSCTL_THRESHOLD_I2S2,
|
||||
SYSCTL_THRESHOLD_I2S0_M,
|
||||
SYSCTL_THRESHOLD_I2S1_M,
|
||||
SYSCTL_THRESHOLD_I2S2_M,
|
||||
SYSCTL_THRESHOLD_I2C0,
|
||||
SYSCTL_THRESHOLD_I2C1,
|
||||
SYSCTL_THRESHOLD_I2C2,
|
||||
SYSCTL_THRESHOLD_WDT0,
|
||||
SYSCTL_THRESHOLD_WDT1,
|
||||
SYSCTL_THRESHOLD_MAX = 28
|
||||
} sysctl_threshold_t;
|
||||
|
||||
/**
|
||||
* System controller reset control id
|
||||
*/
|
||||
typedef enum _sysctl_reset_t {
|
||||
SYSCTL_RESET_SOC,
|
||||
SYSCTL_RESET_ROM,
|
||||
SYSCTL_RESET_DMA,
|
||||
SYSCTL_RESET_AI,
|
||||
SYSCTL_RESET_DVP,
|
||||
SYSCTL_RESET_FFT,
|
||||
SYSCTL_RESET_GPIO,
|
||||
SYSCTL_RESET_SPI0,
|
||||
SYSCTL_RESET_SPI1,
|
||||
SYSCTL_RESET_SPI2,
|
||||
SYSCTL_RESET_SPI3,
|
||||
SYSCTL_RESET_I2S0,
|
||||
SYSCTL_RESET_I2S1,
|
||||
SYSCTL_RESET_I2S2,
|
||||
SYSCTL_RESET_I2C0,
|
||||
SYSCTL_RESET_I2C1,
|
||||
SYSCTL_RESET_I2C2,
|
||||
SYSCTL_RESET_UART1,
|
||||
SYSCTL_RESET_UART2,
|
||||
SYSCTL_RESET_UART3,
|
||||
SYSCTL_RESET_AES,
|
||||
SYSCTL_RESET_FPIOA,
|
||||
SYSCTL_RESET_TIMER0,
|
||||
SYSCTL_RESET_TIMER1,
|
||||
SYSCTL_RESET_TIMER2,
|
||||
SYSCTL_RESET_WDT0,
|
||||
SYSCTL_RESET_WDT1,
|
||||
SYSCTL_RESET_SHA,
|
||||
SYSCTL_RESET_RTC,
|
||||
SYSCTL_RESET_MAX = 31
|
||||
} sysctl_reset_t;
|
||||
|
||||
typedef enum _sysctl_power_bank {
|
||||
SYSCTL_POWER_BANK0,
|
||||
SYSCTL_POWER_BANK1,
|
||||
SYSCTL_POWER_BANK2,
|
||||
SYSCTL_POWER_BANK3,
|
||||
SYSCTL_POWER_BANK4,
|
||||
SYSCTL_POWER_BANK5,
|
||||
SYSCTL_POWER_BANK6,
|
||||
SYSCTL_POWER_BANK7,
|
||||
SYSCTL_POWER_BANK_MAX,
|
||||
} sysctl_power_bank_t;
|
||||
|
||||
/**
|
||||
* System controller reset control id
|
||||
*/
|
||||
typedef enum _sysctl_io_power_mode {
|
||||
SYSCTL_POWER_V33,
|
||||
SYSCTL_POWER_V18
|
||||
} sysctl_io_power_mode_t;
|
||||
|
||||
/**
|
||||
* Git short commit id
|
||||
* No. 0 Register (0x00)
|
||||
*/
|
||||
typedef struct _sysctl_git_id {
|
||||
u32 git_id : 32;
|
||||
} __attribute__((packed, aligned(4))) sysctl_git_id_t;
|
||||
|
||||
/**
|
||||
* System clock base frequency
|
||||
* No. 1 Register (0x04)
|
||||
*/
|
||||
typedef struct _sysctl_clk_freq {
|
||||
u32 clk_freq : 32;
|
||||
} __attribute__((packed, aligned(4))) sysctl_clk_freq_t;
|
||||
|
||||
/**
|
||||
* PLL0 controller
|
||||
* No. 2 Register (0x08)
|
||||
*/
|
||||
typedef struct _sysctl_pll0 {
|
||||
u32 clkr0 : 4;
|
||||
u32 clkf0 : 6;
|
||||
u32 clkod0 : 4;
|
||||
u32 bwadj0 : 6;
|
||||
u32 pll_reset0 : 1;
|
||||
u32 pll_pwrd0 : 1;
|
||||
u32 pll_intfb0 : 1;
|
||||
u32 pll_bypass0 : 1;
|
||||
u32 pll_test0 : 1;
|
||||
u32 pll_out_en0 : 1;
|
||||
u32 pll_test_en : 1;
|
||||
u32 reserved : 5;
|
||||
} __attribute__((packed, aligned(4))) sysctl_pll0_t;
|
||||
|
||||
/**
|
||||
* PLL1 controller
|
||||
* No. 3 Register (0x0c)
|
||||
*/
|
||||
typedef struct _sysctl_pll1 {
|
||||
u32 clkr1 : 4;
|
||||
u32 clkf1 : 6;
|
||||
u32 clkod1 : 4;
|
||||
u32 bwadj1 : 6;
|
||||
u32 pll_reset1 : 1;
|
||||
u32 pll_pwrd1 : 1;
|
||||
u32 pll_intfb1 : 1;
|
||||
u32 pll_bypass1 : 1;
|
||||
u32 pll_test1 : 1;
|
||||
u32 pll_out_en1 : 1;
|
||||
u32 reserved : 6;
|
||||
} __attribute__((packed, aligned(4))) sysctl_pll1_t;
|
||||
|
||||
/**
|
||||
* PLL2 controller
|
||||
* No. 4 Register (0x10)
|
||||
*/
|
||||
typedef struct _sysctl_pll2 {
|
||||
u32 clkr2 : 4;
|
||||
u32 clkf2 : 6;
|
||||
u32 clkod2 : 4;
|
||||
u32 bwadj2 : 6;
|
||||
u32 pll_reset2 : 1;
|
||||
u32 pll_pwrd2 : 1;
|
||||
u32 pll_intfb2 : 1;
|
||||
u32 pll_bypass2 : 1;
|
||||
u32 pll_test2 : 1;
|
||||
u32 pll_out_en2 : 1;
|
||||
u32 pll_ckin_sel2 : 2;
|
||||
u32 reserved : 4;
|
||||
} __attribute__((packed, aligned(4))) sysctl_pll2_t;
|
||||
|
||||
/**
|
||||
* PLL lock tester
|
||||
* No. 6 Register (0x18)
|
||||
*/
|
||||
typedef struct _sysctl_pll_lock {
|
||||
u32 pll_lock0 : 2;
|
||||
u32 pll_slip_clear0 : 1;
|
||||
u32 test_clk_out0 : 1;
|
||||
u32 reserved0 : 4;
|
||||
u32 pll_lock1 : 2;
|
||||
u32 pll_slip_clear1 : 1;
|
||||
u32 test_clk_out1 : 1;
|
||||
u32 reserved1 : 4;
|
||||
u32 pll_lock2 : 2;
|
||||
u32 pll_slip_clear2 : 1;
|
||||
u32 test_clk_out2 : 1;
|
||||
u32 reserved2 : 12;
|
||||
} __attribute__((packed, aligned(4))) sysctl_pll_lock_t;
|
||||
|
||||
/**
|
||||
* AXI ROM detector
|
||||
* No. 7 Register (0x1c)
|
||||
*/
|
||||
typedef struct _sysctl_rom_error {
|
||||
u32 rom_mul_error : 1;
|
||||
u32 rom_one_error : 1;
|
||||
u32 reserved : 30;
|
||||
} __attribute__((packed, aligned(4))) sysctl_rom_error_t;
|
||||
|
||||
/**
|
||||
* Clock select controller0
|
||||
* No. 8 Register (0x20)
|
||||
*/
|
||||
typedef struct _sysctl_clk_sel0 {
|
||||
u32 aclk_sel : 1;
|
||||
u32 aclk_divider_sel : 2;
|
||||
u32 apb0_clk_sel : 3;
|
||||
u32 apb1_clk_sel : 3;
|
||||
u32 apb2_clk_sel : 3;
|
||||
u32 spi3_clk_sel : 1;
|
||||
u32 timer0_clk_sel : 1;
|
||||
u32 timer1_clk_sel : 1;
|
||||
u32 timer2_clk_sel : 1;
|
||||
u32 reserved : 16;
|
||||
} __attribute__((packed, aligned(4))) sysctl_clk_sel0_t;
|
||||
|
||||
/**
|
||||
* Clock select controller1
|
||||
* No. 9 Register (0x24)
|
||||
*/
|
||||
typedef struct _sysctl_clk_sel1 {
|
||||
u32 spi3_sample_clk_sel : 1;
|
||||
u32 reserved0 : 30;
|
||||
u32 reserved1 : 1;
|
||||
} __attribute__((packed, aligned(4))) sysctl_clk_sel1_t;
|
||||
|
||||
/**
|
||||
* Central clock enable
|
||||
* No. 10 Register (0x28)
|
||||
*/
|
||||
typedef struct _sysctl_clk_en_cent {
|
||||
u32 cpu_clk_en : 1;
|
||||
u32 sram0_clk_en : 1;
|
||||
u32 sram1_clk_en : 1;
|
||||
u32 apb0_clk_en : 1;
|
||||
u32 apb1_clk_en : 1;
|
||||
u32 apb2_clk_en : 1;
|
||||
u32 reserved : 26;
|
||||
} __attribute__((packed, aligned(4))) sysctl_clk_en_cent_t;
|
||||
|
||||
/**
|
||||
* Peripheral clock enable
|
||||
* No. 11 Register (0x2c)
|
||||
*/
|
||||
typedef struct _sysctl_clk_en_peri {
|
||||
u32 rom_clk_en : 1;
|
||||
u32 dma_clk_en : 1;
|
||||
u32 ai_clk_en : 1;
|
||||
u32 dvp_clk_en : 1;
|
||||
u32 fft_clk_en : 1;
|
||||
u32 gpio_clk_en : 1;
|
||||
u32 spi0_clk_en : 1;
|
||||
u32 spi1_clk_en : 1;
|
||||
u32 spi2_clk_en : 1;
|
||||
u32 spi3_clk_en : 1;
|
||||
u32 i2s0_clk_en : 1;
|
||||
u32 i2s1_clk_en : 1;
|
||||
u32 i2s2_clk_en : 1;
|
||||
u32 i2c0_clk_en : 1;
|
||||
u32 i2c1_clk_en : 1;
|
||||
u32 i2c2_clk_en : 1;
|
||||
u32 uart1_clk_en : 1;
|
||||
u32 uart2_clk_en : 1;
|
||||
u32 uart3_clk_en : 1;
|
||||
u32 aes_clk_en : 1;
|
||||
u32 fpioa_clk_en : 1;
|
||||
u32 timer0_clk_en : 1;
|
||||
u32 timer1_clk_en : 1;
|
||||
u32 timer2_clk_en : 1;
|
||||
u32 wdt0_clk_en : 1;
|
||||
u32 wdt1_clk_en : 1;
|
||||
u32 sha_clk_en : 1;
|
||||
u32 otp_clk_en : 1;
|
||||
u32 reserved : 1;
|
||||
u32 rtc_clk_en : 1;
|
||||
u32 reserved0 : 2;
|
||||
} __attribute__((packed, aligned(4))) sysctl_clk_en_peri_t;
|
||||
|
||||
/**
|
||||
* Soft reset ctrl
|
||||
* No. 12 Register (0x30)
|
||||
*/
|
||||
typedef struct _sysctl_soft_reset {
|
||||
u32 soft_reset : 1;
|
||||
u32 reserved : 31;
|
||||
} __attribute__((packed, aligned(4))) sysctl_soft_reset_t;
|
||||
|
||||
/**
|
||||
* Peripheral reset controller
|
||||
* No. 13 Register (0x34)
|
||||
*/
|
||||
typedef struct _sysctl_peri_reset {
|
||||
u32 rom_reset : 1;
|
||||
u32 dma_reset : 1;
|
||||
u32 ai_reset : 1;
|
||||
u32 dvp_reset : 1;
|
||||
u32 fft_reset : 1;
|
||||
u32 gpio_reset : 1;
|
||||
u32 spi0_reset : 1;
|
||||
u32 spi1_reset : 1;
|
||||
u32 spi2_reset : 1;
|
||||
u32 spi3_reset : 1;
|
||||
u32 i2s0_reset : 1;
|
||||
u32 i2s1_reset : 1;
|
||||
u32 i2s2_reset : 1;
|
||||
u32 i2c0_reset : 1;
|
||||
u32 i2c1_reset : 1;
|
||||
u32 i2c2_reset : 1;
|
||||
u32 uart1_reset : 1;
|
||||
u32 uart2_reset : 1;
|
||||
u32 uart3_reset : 1;
|
||||
u32 aes_reset : 1;
|
||||
u32 fpioa_reset : 1;
|
||||
u32 timer0_reset : 1;
|
||||
u32 timer1_reset : 1;
|
||||
u32 timer2_reset : 1;
|
||||
u32 wdt0_reset : 1;
|
||||
u32 wdt1_reset : 1;
|
||||
u32 sha_reset : 1;
|
||||
u32 reserved : 2;
|
||||
u32 rtc_reset : 1;
|
||||
u32 reserved0 : 2;
|
||||
} __attribute__((packed, aligned(4))) sysctl_peri_reset_t;
|
||||
|
||||
/**
|
||||
* Clock threshold controller 0
|
||||
* No. 14 Register (0x38)
|
||||
*/
|
||||
typedef struct _sysctl_clk_th0 {
|
||||
u32 sram0_gclk_threshold : 4;
|
||||
u32 sram1_gclk_threshold : 4;
|
||||
u32 ai_gclk_threshold : 4;
|
||||
u32 dvp_gclk_threshold : 4;
|
||||
u32 rom_gclk_threshold : 4;
|
||||
u32 reserved : 12;
|
||||
} __attribute__((packed, aligned(4))) sysctl_clk_th0_t;
|
||||
|
||||
/**
|
||||
* Clock threshold controller 1
|
||||
* No. 15 Register (0x3c)
|
||||
*/
|
||||
typedef struct _sysctl_clk_th1 {
|
||||
u32 spi0_clk_threshold : 8;
|
||||
u32 spi1_clk_threshold : 8;
|
||||
u32 spi2_clk_threshold : 8;
|
||||
u32 spi3_clk_threshold : 8;
|
||||
} __attribute__((packed, aligned(4))) sysctl_clk_th1_t;
|
||||
|
||||
/**
|
||||
* Clock threshold controller 2
|
||||
* No. 16 Register (0x40)
|
||||
*/
|
||||
typedef struct _sysctl_clk_th2 {
|
||||
u32 timer0_clk_threshold : 8;
|
||||
u32 timer1_clk_threshold : 8;
|
||||
u32 timer2_clk_threshold : 8;
|
||||
u32 reserved : 8;
|
||||
} __attribute__((packed, aligned(4))) sysctl_clk_th2_t;
|
||||
|
||||
/**
|
||||
* Clock threshold controller 3
|
||||
* No. 17 Register (0x44)
|
||||
*/
|
||||
typedef struct _sysctl_clk_th3 {
|
||||
u32 i2s0_clk_threshold : 16;
|
||||
u32 i2s1_clk_threshold : 16;
|
||||
} __attribute__((packed, aligned(4))) sysctl_clk_th3_t;
|
||||
|
||||
/**
|
||||
* Clock threshold controller 4
|
||||
* No. 18 Register (0x48)
|
||||
*/
|
||||
typedef struct _sysctl_clk_th4 {
|
||||
u32 i2s2_clk_threshold : 16;
|
||||
u32 i2s0_mclk_threshold : 8;
|
||||
u32 i2s1_mclk_threshold : 8;
|
||||
} __attribute__((packed, aligned(4))) sysctl_clk_th4_t;
|
||||
|
||||
/**
|
||||
* Clock threshold controller 5
|
||||
* No. 19 Register (0x4c)
|
||||
*/
|
||||
typedef struct _sysctl_clk_th5 {
|
||||
u32 i2s2_mclk_threshold : 8;
|
||||
u32 i2c0_clk_threshold : 8;
|
||||
u32 i2c1_clk_threshold : 8;
|
||||
u32 i2c2_clk_threshold : 8;
|
||||
} __attribute__((packed, aligned(4))) sysctl_clk_th5_t;
|
||||
|
||||
/**
|
||||
* Clock threshold controller 6
|
||||
* No. 20 Register (0x50)
|
||||
*/
|
||||
typedef struct _sysctl_clk_th6 {
|
||||
u32 wdt0_clk_threshold : 8;
|
||||
u32 wdt1_clk_threshold : 8;
|
||||
u32 reserved0 : 8;
|
||||
u32 reserved1 : 8;
|
||||
} __attribute__((packed, aligned(4))) sysctl_clk_th6_t;
|
||||
|
||||
/**
|
||||
* Miscellaneous controller
|
||||
* No. 21 Register (0x54)
|
||||
*/
|
||||
typedef struct _sysctl_misc {
|
||||
u32 debug_sel : 6;
|
||||
u32 reserved0 : 4;
|
||||
u32 spi_dvp_data_enable : 1;
|
||||
u32 reserved1 : 21;
|
||||
} __attribute__((packed, aligned(4))) sysctl_misc_t;
|
||||
|
||||
/**
|
||||
* Peripheral controller
|
||||
* No. 22 Register (0x58)
|
||||
*/
|
||||
typedef struct _sysctl_peri {
|
||||
u32 timer0_pause : 1;
|
||||
u32 timer1_pause : 1;
|
||||
u32 timer2_pause : 1;
|
||||
u32 timer3_pause : 1;
|
||||
u32 timer4_pause : 1;
|
||||
u32 timer5_pause : 1;
|
||||
u32 timer6_pause : 1;
|
||||
u32 timer7_pause : 1;
|
||||
u32 timer8_pause : 1;
|
||||
u32 timer9_pause : 1;
|
||||
u32 timer10_pause : 1;
|
||||
u32 timer11_pause : 1;
|
||||
u32 spi0_xip_en : 1;
|
||||
u32 spi1_xip_en : 1;
|
||||
u32 spi2_xip_en : 1;
|
||||
u32 spi3_xip_en : 1;
|
||||
u32 spi0_clk_bypass : 1;
|
||||
u32 spi1_clk_bypass : 1;
|
||||
u32 spi2_clk_bypass : 1;
|
||||
u32 i2s0_clk_bypass : 1;
|
||||
u32 i2s1_clk_bypass : 1;
|
||||
u32 i2s2_clk_bypass : 1;
|
||||
u32 jtag_clk_bypass : 1;
|
||||
u32 dvp_clk_bypass : 1;
|
||||
u32 debug_clk_bypass : 1;
|
||||
u32 reserved0 : 1;
|
||||
u32 reserved1 : 6;
|
||||
} __attribute__((packed, aligned(4))) sysctl_peri_t;
|
||||
|
||||
/**
|
||||
* SPI sleep controller
|
||||
* No. 23 Register (0x5c)
|
||||
*/
|
||||
typedef struct _sysctl_spi_sleep {
|
||||
u32 ssi0_sleep : 1;
|
||||
u32 ssi1_sleep : 1;
|
||||
u32 ssi2_sleep : 1;
|
||||
u32 ssi3_sleep : 1;
|
||||
u32 reserved : 28;
|
||||
} __attribute__((packed, aligned(4))) sysctl_spi_sleep_t;
|
||||
|
||||
/**
|
||||
* Reset source status
|
||||
* No. 24 Register (0x60)
|
||||
*/
|
||||
typedef struct _sysctl_reset_status {
|
||||
u32 reset_sts_clr : 1;
|
||||
u32 pin_reset_sts : 1;
|
||||
u32 wdt0_reset_sts : 1;
|
||||
u32 wdt1_reset_sts : 1;
|
||||
u32 soft_reset_sts : 1;
|
||||
u32 reserved : 27;
|
||||
} __attribute__((packed, aligned(4))) sysctl_reset_status_t;
|
||||
|
||||
/**
|
||||
* DMA handshake selector
|
||||
* No. 25 Register (0x64)
|
||||
*/
|
||||
typedef struct _sysctl_dma_sel0 {
|
||||
u32 dma_sel0 : 6;
|
||||
u32 dma_sel1 : 6;
|
||||
u32 dma_sel2 : 6;
|
||||
u32 dma_sel3 : 6;
|
||||
u32 dma_sel4 : 6;
|
||||
u32 reserved : 2;
|
||||
} __attribute__((packed, aligned(4))) sysctl_dma_sel0_t;
|
||||
|
||||
/**
|
||||
* DMA handshake selector
|
||||
* No. 26 Register (0x68)
|
||||
*/
|
||||
typedef struct _sysctl_dma_sel1 {
|
||||
u32 dma_sel5 : 6;
|
||||
u32 reserved : 26;
|
||||
} __attribute__((packed, aligned(4))) sysctl_dma_sel1_t;
|
||||
|
||||
/**
|
||||
* IO Power Mode Select controller
|
||||
* No. 27 Register (0x6c)
|
||||
*/
|
||||
typedef struct _sysctl_power_sel {
|
||||
u32 power_mode_sel0 : 1;
|
||||
u32 power_mode_sel1 : 1;
|
||||
u32 power_mode_sel2 : 1;
|
||||
u32 power_mode_sel3 : 1;
|
||||
u32 power_mode_sel4 : 1;
|
||||
u32 power_mode_sel5 : 1;
|
||||
u32 power_mode_sel6 : 1;
|
||||
u32 power_mode_sel7 : 1;
|
||||
u32 reserved : 24;
|
||||
} __attribute__((packed, aligned(4))) sysctl_power_sel_t;
|
||||
|
||||
/**
|
||||
* System controller object
|
||||
*
|
||||
* The System controller is a peripheral device mapped in the
|
||||
* internal memory map, discoverable in the Configuration String.
|
||||
* It is responsible for low-level configuration of all system
|
||||
* related peripheral device. It contain PLL controller, clock
|
||||
* controller, reset controller, DMA handshake controller, SPI
|
||||
* controller, timer controller, WDT controller and sleep
|
||||
* controller.
|
||||
*/
|
||||
typedef struct _sysctl {
|
||||
/* No. 0 (0x00): Git short commit id */
|
||||
sysctl_git_id_t git_id;
|
||||
/* No. 1 (0x04): System clock base frequency */
|
||||
sysctl_clk_freq_t clk_freq;
|
||||
/* No. 2 (0x08): PLL0 controller */
|
||||
sysctl_pll0_t pll0;
|
||||
/* No. 3 (0x0c): PLL1 controller */
|
||||
sysctl_pll1_t pll1;
|
||||
/* No. 4 (0x10): PLL2 controller */
|
||||
sysctl_pll2_t pll2;
|
||||
/* No. 5 (0x14): Reserved */
|
||||
u32 resv5;
|
||||
/* No. 6 (0x18): PLL lock tester */
|
||||
sysctl_pll_lock_t pll_lock;
|
||||
/* No. 7 (0x1c): AXI ROM detector */
|
||||
sysctl_rom_error_t rom_error;
|
||||
/* No. 8 (0x20): Clock select controller0 */
|
||||
sysctl_clk_sel0_t clk_sel0;
|
||||
/* No. 9 (0x24): Clock select controller1 */
|
||||
sysctl_clk_sel1_t clk_sel1;
|
||||
/* No. 10 (0x28): Central clock enable */
|
||||
sysctl_clk_en_cent_t clk_en_cent;
|
||||
/* No. 11 (0x2c): Peripheral clock enable */
|
||||
sysctl_clk_en_peri_t clk_en_peri;
|
||||
/* No. 12 (0x30): Soft reset ctrl */
|
||||
sysctl_soft_reset_t soft_reset;
|
||||
/* No. 13 (0x34): Peripheral reset controller */
|
||||
sysctl_peri_reset_t peri_reset;
|
||||
/* No. 14 (0x38): Clock threshold controller 0 */
|
||||
sysctl_clk_th0_t clk_th0;
|
||||
/* No. 15 (0x3c): Clock threshold controller 1 */
|
||||
sysctl_clk_th1_t clk_th1;
|
||||
/* No. 16 (0x40): Clock threshold controller 2 */
|
||||
sysctl_clk_th2_t clk_th2;
|
||||
/* No. 17 (0x44): Clock threshold controller 3 */
|
||||
sysctl_clk_th3_t clk_th3;
|
||||
/* No. 18 (0x48): Clock threshold controller 4 */
|
||||
sysctl_clk_th4_t clk_th4;
|
||||
/* No. 19 (0x4c): Clock threshold controller 5 */
|
||||
sysctl_clk_th5_t clk_th5;
|
||||
/* No. 20 (0x50): Clock threshold controller 6 */
|
||||
sysctl_clk_th6_t clk_th6;
|
||||
/* No. 21 (0x54): Miscellaneous controller */
|
||||
sysctl_misc_t misc;
|
||||
/* No. 22 (0x58): Peripheral controller */
|
||||
sysctl_peri_t peri;
|
||||
/* No. 23 (0x5c): SPI sleep controller */
|
||||
sysctl_spi_sleep_t spi_sleep;
|
||||
/* No. 24 (0x60): Reset source status */
|
||||
sysctl_reset_status_t reset_status;
|
||||
/* No. 25 (0x64): DMA handshake selector */
|
||||
sysctl_dma_sel0_t dma_sel0;
|
||||
/* No. 26 (0x68): DMA handshake selector */
|
||||
sysctl_dma_sel1_t dma_sel1;
|
||||
/* No. 27 (0x6c): IO Power Mode Select controller */
|
||||
sysctl_power_sel_t power_sel;
|
||||
/* No. 28 (0x70): Reserved */
|
||||
u32 resv28;
|
||||
/* No. 29 (0x74): Reserved */
|
||||
u32 resv29;
|
||||
/* No. 30 (0x78): Reserved */
|
||||
u32 resv30;
|
||||
/* No. 31 (0x7c): Reserved */
|
||||
u32 resv31;
|
||||
} __attribute__((packed, aligned(4))) sysctl_t;
|
||||
|
||||
/**
|
||||
* Abstruct PLL struct
|
||||
*/
|
||||
typedef struct _sysctl_general_pll {
|
||||
u32 clkr : 4;
|
||||
u32 clkf : 6;
|
||||
u32 clkod : 4;
|
||||
u32 bwadj : 6;
|
||||
u32 pll_reset : 1;
|
||||
u32 pll_pwrd : 1;
|
||||
u32 pll_intfb : 1;
|
||||
u32 pll_bypass : 1;
|
||||
u32 pll_test : 1;
|
||||
u32 pll_out_en : 1;
|
||||
u32 pll_ckin_sel : 2;
|
||||
u32 reserved : 4;
|
||||
} __attribute__((packed, aligned(4))) sysctl_general_pll_t;
|
||||
|
||||
/**
|
||||
* Get frequency of CPU
|
||||
* @return The frequency of the CPU
|
||||
*/
|
||||
u32 sysctl_get_cpu_freq(void);
|
||||
|
||||
#endif /* _K210_SYSCTL_H_ */
|
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Copyright 2018 Canaan Inc.
|
||||
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "sysctl.h"
|
||||
#include "uarths.h"
|
||||
|
||||
static volatile struct uarths *const uarths =
|
||||
(volatile struct uarths *)UARTHS_BASE_ADDR;
|
||||
|
||||
void uarths_init(u32 baud_rate, enum uarths_stopbit stopbit)
|
||||
{
|
||||
u32 freq = sysctl_get_cpu_freq();
|
||||
u16 div = freq / baud_rate - 1;
|
||||
|
||||
/* Set UART registers */
|
||||
uarths->div.div = div;
|
||||
uarths->txctrl.nstop = stopbit;
|
||||
uarths->txctrl.txen = 1;
|
||||
uarths->rxctrl.rxen = 1;
|
||||
uarths->txctrl.txcnt = 0;
|
||||
uarths->rxctrl.rxcnt = 0;
|
||||
uarths->ip.txwm = 1;
|
||||
uarths->ip.rxwm = 0;
|
||||
uarths->ie.txwm = 1;
|
||||
uarths->ie.rxwm = 0;
|
||||
|
||||
/* Clear input */
|
||||
if (!uarths->rxdata.empty)
|
||||
(void)uarths_getc();
|
||||
}
|
||||
|
||||
void uarths_putc(char c)
|
||||
{
|
||||
while (uarths->txdata.full)
|
||||
;
|
||||
|
||||
uarths->txdata.data = (u8)c;
|
||||
}
|
||||
|
||||
int uarths_getc(void)
|
||||
{
|
||||
struct uarths_rxdata rx = uarths->rxdata;
|
||||
|
||||
if (rx.empty)
|
||||
return -1;
|
||||
|
||||
return rx.data;
|
||||
}
|
@@ -1,171 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Copyright 2018 Canaan Inc.
|
||||
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Universal Asynchronous Receiver/Transmitter (UART)
|
||||
* The UART peripheral supports the following features:
|
||||
*
|
||||
* - 8-N-1 and 8-N-2 formats: 8 data bits, no parity bit, 1 start
|
||||
* bit, 1 or 2 stop bits
|
||||
*
|
||||
* - 8-entry transmit and receive FIFO buffers with programmable
|
||||
* watermark interrupts
|
||||
*
|
||||
* - 16× Rx oversampling with 2/3 majority voting per bit
|
||||
*
|
||||
* The UART peripheral does not support hardware flow control or
|
||||
* other modem control signals, or synchronous serial data
|
||||
* tranfesrs.
|
||||
*
|
||||
* UART RAM Layout
|
||||
* | Address | Name | Description |
|
||||
* |-----------|----------|---------------------------------|
|
||||
* | 0x000 | txdata | Transmit data register |
|
||||
* | 0x004 | rxdata | Receive data register |
|
||||
* | 0x008 | txctrl | Transmit control register |
|
||||
* | 0x00C | rxctrl | Receive control register |
|
||||
* | 0x010 | ie | UART interrupt enable |
|
||||
* | 0x014 | ip | UART Interrupt pending |
|
||||
* | 0x018 | div | Baud rate divisor |
|
||||
*/
|
||||
|
||||
#ifndef _K210_UARTHS_H_
|
||||
#define _K210_UARTHS_H_
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
/* Base register address */
|
||||
#define UARTHS_BASE_ADDR (0x38000000U)
|
||||
|
||||
/* Register address offsets */
|
||||
#define UARTHS_REG_TXFIFO 0x00
|
||||
#define UARTHS_REG_RXFIFO 0x04
|
||||
#define UARTHS_REG_TXCTRL 0x08
|
||||
#define UARTHS_REG_RXCTRL 0x0c
|
||||
#define UARTHS_REG_IE 0x10
|
||||
#define UARTHS_REG_IP 0x14
|
||||
#define UARTHS_REG_DIV 0x18
|
||||
|
||||
/* TXCTRL register */
|
||||
#define UARTHS_TXEN 0x01
|
||||
#define UARTHS_TXWM(x) (((x) & 0xffff) << 16)
|
||||
|
||||
/* RXCTRL register */
|
||||
#define UARTHS_RXEN 0x01
|
||||
#define UARTHS_RXWM(x) (((x) & 0xffff) << 16)
|
||||
|
||||
/* IP register */
|
||||
#define UARTHS_IP_TXWM 0x01
|
||||
#define UARTHS_IP_RXWM 0x02
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
struct uarths_txdata {
|
||||
/* Bits [7:0] is data */
|
||||
u32 data : 8;
|
||||
/* Bits [30:8] is 0 */
|
||||
u32 zero : 23;
|
||||
/* Bit 31 is full status */
|
||||
u32 full : 1;
|
||||
} __attribute__((packed, aligned(4)));
|
||||
|
||||
struct uarths_rxdata {
|
||||
/* Bits [7:0] is data */
|
||||
u32 data : 8;
|
||||
/* Bits [30:8] is 0 */
|
||||
u32 zero : 23;
|
||||
/* Bit 31 is empty status */
|
||||
u32 empty : 1;
|
||||
} __attribute__((packed, aligned(4)));
|
||||
|
||||
struct uarths_txctrl {
|
||||
/* Bit 0 is txen, controls whether the Tx channel is active. */
|
||||
u32 txen : 1;
|
||||
/* Bit 1 is nstop, 0 for one stop bit and 1 for two stop bits */
|
||||
u32 nstop : 1;
|
||||
/* Bits [15:2] is reserved */
|
||||
u32 resv0 : 14;
|
||||
/* Bits [18:16] is threshold of interrupt triggers */
|
||||
u32 txcnt : 3;
|
||||
/* Bits [31:19] is reserved */
|
||||
u32 resv1 : 13;
|
||||
} __attribute__((packed, aligned(4)));
|
||||
|
||||
struct uarths_rxctrl {
|
||||
/* Bit 0 is txen, controls whether the Tx channel is active. */
|
||||
u32 rxen : 1;
|
||||
/* Bits [15:1] is reserved */
|
||||
u32 resv0 : 15;
|
||||
/* Bits [18:16] is threshold of interrupt triggers */
|
||||
u32 rxcnt : 3;
|
||||
/* Bits [31:19] is reserved */
|
||||
u32 resv1 : 13;
|
||||
} __attribute__((packed, aligned(4)));
|
||||
|
||||
struct uarths_ip {
|
||||
/* Bit 0 is txwm, raised less than txcnt */
|
||||
u32 txwm : 1;
|
||||
/* Bit 1 is txwm, raised greater than rxcnt */
|
||||
u32 rxwm : 1;
|
||||
/* Bits [31:2] is 0 */
|
||||
u32 zero : 30;
|
||||
} __attribute__((packed, aligned(4)));
|
||||
|
||||
struct uarths_ie {
|
||||
/* Bit 0 is txwm, raised less than txcnt */
|
||||
u32 txwm : 1;
|
||||
/* Bit 1 is txwm, raised greater than rxcnt */
|
||||
u32 rxwm : 1;
|
||||
/* Bits [31:2] is 0 */
|
||||
u32 zero : 30;
|
||||
} __attribute__((packed, aligned(4)));
|
||||
|
||||
struct uarths_div {
|
||||
/* Bits [31:2] is baud rate divisor register */
|
||||
u32 div : 16;
|
||||
/* Bits [31:16] is 0 */
|
||||
u32 zero : 16;
|
||||
} __attribute__((packed, aligned(4)));
|
||||
|
||||
struct uarths {
|
||||
/* Address offset 0x00 */
|
||||
struct uarths_txdata txdata;
|
||||
/* Address offset 0x04 */
|
||||
struct uarths_rxdata rxdata;
|
||||
/* Address offset 0x08 */
|
||||
struct uarths_txctrl txctrl;
|
||||
/* Address offset 0x0c */
|
||||
struct uarths_rxctrl rxctrl;
|
||||
/* Address offset 0x10 */
|
||||
struct uarths_ie ie;
|
||||
/* Address offset 0x14 */
|
||||
struct uarths_ip ip;
|
||||
/* Address offset 0x18 */
|
||||
struct uarths_div div;
|
||||
} __attribute__((packed, aligned(4)));
|
||||
|
||||
enum uarths_stopbit { UARTHS_STOP_1, UARTHS_STOP_2 };
|
||||
|
||||
void uarths_init(u32 baud_rate, enum uarths_stopbit stopbit);
|
||||
void uarths_putc(char c);
|
||||
int uarths_getc(void);
|
||||
|
||||
#endif /* _K210_UARTHS_H_ */
|
@@ -1,10 +0,0 @@
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
#
|
||||
# Authors:
|
||||
# Anup Patel <anup.patel@wdc.com>
|
||||
#
|
||||
|
||||
platform-objs-y += platform.o
|
@@ -1,159 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include <sbi/sbi_const.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi_utils/irqchip/plic.h>
|
||||
#include <sbi_utils/serial/sifive-uart.h>
|
||||
#include <sbi_utils/sys/clint.h>
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#define SIFIVE_U_HART_COUNT 4
|
||||
#define SIFIVE_U_HART_STACK_SIZE 8192
|
||||
|
||||
#define SIFIVE_U_SYS_CLK 1000000000
|
||||
#define SIFIVE_U_PERIPH_CLK (SIFIVE_U_SYS_CLK / 2)
|
||||
|
||||
#define SIFIVE_U_CLINT_ADDR 0x2000000
|
||||
|
||||
#define SIFIVE_U_PLIC_ADDR 0xc000000
|
||||
#define SIFIVE_U_PLIC_NUM_SOURCES 0x35
|
||||
#define SIFIVE_U_PLIC_NUM_PRIORITIES 7
|
||||
|
||||
#define SIFIVE_U_UART0_ADDR 0x10013000
|
||||
#define SIFIVE_U_UART1_ADDR 0x10023000
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
static int sifive_u_final_init(bool cold_boot)
|
||||
{
|
||||
void *fdt;
|
||||
|
||||
if (!cold_boot)
|
||||
return 0;
|
||||
|
||||
fdt = sbi_scratch_thishart_arg1_ptr();
|
||||
plic_fdt_fixup(fdt, "riscv,plic0");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 sifive_u_pmp_region_count(u32 hartid)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sifive_u_pmp_region_info(u32 hartid, u32 index, ulong *prot,
|
||||
ulong *addr, ulong *log2size)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (index) {
|
||||
case 0:
|
||||
*prot = PMP_R | PMP_W | PMP_X;
|
||||
*addr = 0;
|
||||
*log2size = __riscv_xlen;
|
||||
break;
|
||||
default:
|
||||
ret = -1;
|
||||
break;
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sifive_u_console_init(void)
|
||||
{
|
||||
return sifive_uart_init(SIFIVE_U_UART0_ADDR, SIFIVE_U_PERIPH_CLK,
|
||||
115200);
|
||||
}
|
||||
|
||||
static int sifive_u_irqchip_init(bool cold_boot)
|
||||
{
|
||||
int rc;
|
||||
u32 hartid = sbi_current_hartid();
|
||||
|
||||
if (cold_boot) {
|
||||
rc = plic_cold_irqchip_init(SIFIVE_U_PLIC_ADDR,
|
||||
SIFIVE_U_PLIC_NUM_SOURCES,
|
||||
SIFIVE_U_HART_COUNT);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return plic_warm_irqchip_init(hartid, (2 * hartid), (2 * hartid + 1));
|
||||
}
|
||||
|
||||
static int sifive_u_ipi_init(bool cold_boot)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (cold_boot) {
|
||||
rc = clint_cold_ipi_init(SIFIVE_U_CLINT_ADDR,
|
||||
SIFIVE_U_HART_COUNT);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return clint_warm_ipi_init();
|
||||
}
|
||||
|
||||
static int sifive_u_timer_init(bool cold_boot)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (cold_boot) {
|
||||
rc = clint_cold_timer_init(SIFIVE_U_CLINT_ADDR,
|
||||
SIFIVE_U_HART_COUNT);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return clint_warm_timer_init();
|
||||
}
|
||||
|
||||
static int sifive_u_system_down(u32 type)
|
||||
{
|
||||
/* For now nothing to do. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct sbi_platform_operations platform_ops = {
|
||||
.pmp_region_count = sifive_u_pmp_region_count,
|
||||
.pmp_region_info = sifive_u_pmp_region_info,
|
||||
.final_init = sifive_u_final_init,
|
||||
.console_putc = sifive_uart_putc,
|
||||
.console_getc = sifive_uart_getc,
|
||||
.console_init = sifive_u_console_init,
|
||||
.irqchip_init = sifive_u_irqchip_init,
|
||||
.ipi_send = clint_ipi_send,
|
||||
.ipi_sync = clint_ipi_sync,
|
||||
.ipi_clear = clint_ipi_clear,
|
||||
.ipi_init = sifive_u_ipi_init,
|
||||
.timer_value = clint_timer_value,
|
||||
.timer_event_stop = clint_timer_event_stop,
|
||||
.timer_event_start = clint_timer_event_start,
|
||||
.timer_init = sifive_u_timer_init,
|
||||
.system_reboot = sifive_u_system_down,
|
||||
.system_shutdown = sifive_u_system_down
|
||||
};
|
||||
|
||||
const struct sbi_platform platform = {
|
||||
.opensbi_version = OPENSBI_VERSION,
|
||||
.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
|
||||
.name = "QEMU SiFive Unleashed",
|
||||
.features = SBI_PLATFORM_DEFAULT_FEATURES,
|
||||
.hart_count = SIFIVE_U_HART_COUNT,
|
||||
.hart_stack_size = SIFIVE_U_HART_STACK_SIZE,
|
||||
.disabled_hart_mask = 0,
|
||||
.platform_ops_addr = (unsigned long)&platform_ops
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user