mirror of
https://github.com/riscv-software-src/opensbi.git
synced 2025-08-24 15:31:22 +01:00
Compare commits
100 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 |
15
Makefile
15
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
|
||||
@@ -159,7 +166,7 @@ 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)
|
||||
|
@@ -16,4 +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).
|
||||
|
||||
|
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.
|
||||
|
@@ -1,13 +1,14 @@
|
||||
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.
|
||||
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.
|
||||
To build platform specific library and firmwares, provide the
|
||||
*PLATFORM=andes/ae350* parameter to the top level make command.
|
||||
|
||||
Platform Options
|
||||
----------------
|
||||
@@ -17,7 +18,8 @@ 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.
|
||||
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
|
||||
|
||||
|
@@ -1,9 +1,11 @@
|
||||
Ariane FPGA SoC Platform
|
||||
==========================
|
||||
Ariane is a 6-stage, single issue, in-order CPU which implements the 64-bit RISC-V instruction set.
|
||||
The Ariane FPGA development platform is based on FPGA FPGA SoC(which currently supports only Genesys 2 board) and is capable
|
||||
of running Linux.
|
||||
The FPGA SoC currently contains the following peripherals:
|
||||
========================
|
||||
Ariane is a 6-stage, single issue, in-order CPU which implements the 64-bit
|
||||
RISC-V instruction set. The Ariane FPGA development platform is based on FPGA
|
||||
SoC (which currently supports only Genesys 2 board) and is capable of running
|
||||
Linux.
|
||||
|
||||
The FPGA SoC currently contains the following peripherals:
|
||||
- DDR3 memory controller
|
||||
- SPI controller to conncet to an SDCard
|
||||
- Ethernet controller
|
||||
@@ -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
|
||||
@@ -26,6 +21,10 @@ OpenSBI currently supports the following virtual and hardware platforms:
|
||||
|
||||
* **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*,
|
||||
@@ -33,7 +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,60 +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.
|
||||
|
||||
Note with QEMU v4.2 release, the QEMU *sifive_u* machine has been updated to
|
||||
closely match the SiFive HiFive Unleashed hardware and can therefore run the
|
||||
same firmware as what gets loaded onto the board, and OpenSBI's *qemu/sifive_u*
|
||||
platform should only be used with QEMU v4.1 release or before.
|
||||
|
||||
The special *qemu/sifive_u* platform support will be dropped in the future
|
||||
OpenSBI release.
|
||||
|
||||
Platform Options
|
||||
----------------
|
||||
|
||||
The *QEMU SiFive Unleashed Machine* platform does not have any platform specific
|
||||
options.
|
||||
|
||||
Executing on QEMU RISC-V 64-bit
|
||||
-------------------------------
|
||||
|
||||
**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
|
||||
```
|
@@ -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,5 +1,5 @@
|
||||
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.
|
||||
@@ -25,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**
|
||||
|
||||
@@ -49,24 +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. From, Linux v5.2 (or higher) device tree is hosted in
|
||||
Linux kernel and compiled as a part of Linux kernel build process.
|
||||
sifive_fu540_defconfig configuration and with U-Boot v2020.01 (or higher).
|
||||
|
||||
The detailed U-Boot booting guide is avaialble at [U-Boot](https://gitlab.denx.de/u-boot/u-boot/blob/master/doc/board/sifive/fu540.rst)
|
||||
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**
|
||||
@@ -74,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
|
||||
@@ -144,43 +124,33 @@ 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>
|
||||
```
|
||||
7. Load the pre-compiled device tree via tftpboot.
|
||||
6. Load the pre-compiled device tree via tftpboot.
|
||||
```
|
||||
tftpboot ${fdt_addr_r} <linux source>/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dtb
|
||||
tftpboot ${fdt_addr_r} <hifive-unleashed-a00.dtb path in tftpboot directory>
|
||||
```
|
||||
8. Set the boot command-line arguments.
|
||||
7. Set the boot command-line arguments.
|
||||
```
|
||||
setenv bootargs "root=<root partition> rw console=ttySIF0 earlycon=sbi"
|
||||
```
|
||||
@@ -188,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)
|
||||
|
||||
9. Now boot into Linux.
|
||||
8. Now boot into Linux.
|
||||
```
|
||||
bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}
|
||||
booti ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}
|
||||
or
|
||||
(If ramdisk is not loaded from network)
|
||||
bootm ${kernel_addr_r} - ${fdt_addr_r}
|
||||
booti ${kernel_addr_r} - ${fdt_addr_r}
|
||||
```
|
||||
|
||||
**U-Boot & Linux Kernel as a single payload**
|
||||
@@ -202,7 +171,7 @@ bootm ${kernel_addr_r} - ${fdt_addr_r}
|
||||
At U-Boot prompt execute the following boot command to boot Linux.
|
||||
|
||||
```
|
||||
bootm ${kernel_addr_r} - ${fdt_addr_r}
|
||||
booti ${kernel_addr_r} - ${fdt_addr_r}
|
||||
```
|
||||
|
||||
QEMU Specific Instructions
|
||||
@@ -213,3 +182,20 @@ 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.
|
@@ -41,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
|
||||
@@ -75,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
|
||||
@@ -91,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
|
||||
@@ -381,6 +394,8 @@ _start_warm:
|
||||
j _start_hang
|
||||
|
||||
.align 3
|
||||
_relocate_lottery:
|
||||
RISCV_PTR 0
|
||||
_boot_status:
|
||||
RISCV_PTR 0
|
||||
_load_start:
|
||||
@@ -390,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__)
|
||||
@@ -425,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 */
|
||||
@@ -588,8 +603,8 @@ _skip_mstatush_restore:
|
||||
|
||||
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:
|
||||
|
@@ -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++;
|
||||
}
|
||||
|
@@ -12,193 +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_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 0x0000000300000000
|
||||
#define MSTATUS_SXL 0x0000000C00000000
|
||||
#define MSTATUS_MTL 0x0000004000000000
|
||||
#define MSTATUS_MTL_SHIFT 38
|
||||
#define MSTATUS_MPV 0x0000008000000000
|
||||
#define MSTATUS_MPV_HIFT 39
|
||||
#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_UXL 0x00000003
|
||||
#define MSTATUSH_SXL 0x0000000C
|
||||
#define MSTATUSH_MTL 0x00000040
|
||||
#define MSTATUSH_MTL_SHIFT 6
|
||||
#define MSTATUSH_MPV 0x00000080
|
||||
#define MSTATUSH_MPV_HIFT 7
|
||||
#define MSTATUSH_SBE _UL(0x00000010)
|
||||
#define MSTATUSH_MBE _UL(0x00000020)
|
||||
#define MSTATUSH_MPV _UL(0x00000080)
|
||||
#endif
|
||||
#define MSTATUS64_SD 0x8000000000000000
|
||||
#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_SHIFT 5
|
||||
#define SSTATUS_SPIE (1UL << MSTATUS_SPIE_SHIFT)
|
||||
#define SSTATUS_SPP_SHIFT 8
|
||||
#define SSTATUS_SPP (1UL << MSTATUS_SPP_SHIFT)
|
||||
#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 HSTATUS_VTSR 0x00400000
|
||||
#define HSTATUS_VTVM 0x00100000
|
||||
#define HSTATUS_SP2V 0x00000200
|
||||
#define HSTATUS_SP2P 0x00000100
|
||||
#define HSTATUS_SPV 0x00000080
|
||||
#define HSTATUS_STL 0x00000040
|
||||
#define HSTATUS_SPRV 0x00000001
|
||||
|
||||
#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
|
||||
|
||||
@@ -276,10 +208,16 @@
|
||||
#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
|
||||
@@ -304,6 +242,8 @@
|
||||
#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
|
||||
@@ -475,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
|
||||
@@ -549,7 +492,16 @@
|
||||
#define INSN_MASK_WFI 0xffffff00
|
||||
#define INSN_MATCH_WFI 0x10500000
|
||||
|
||||
#define INSN_LEN(insn) ((((insn) & 0x3) < 0x3) ? 2 : 4)
|
||||
#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
|
||||
|
@@ -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
|
||||
|
@@ -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,28 +12,44 @@
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
enum sbi_ext_id {
|
||||
SBI_EXT_0_1_SET_TIMER = 0x0,
|
||||
SBI_EXT_0_1_CONSOLE_PUTCHAR = 0x1,
|
||||
SBI_EXT_0_1_CONSOLE_GETCHAR = 0x2,
|
||||
SBI_EXT_0_1_CLEAR_IPI = 0x3,
|
||||
SBI_EXT_0_1_SEND_IPI = 0x4,
|
||||
SBI_EXT_0_1_REMOTE_FENCE_I = 0x5,
|
||||
SBI_EXT_0_1_REMOTE_SFENCE_VMA = 0x6,
|
||||
SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID = 0x7,
|
||||
SBI_EXT_0_1_SHUTDOWN = 0x8,
|
||||
SBI_EXT_BASE = 0x10,
|
||||
};
|
||||
/* 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
|
||||
|
||||
enum sbi_ext_base_fid {
|
||||
SBI_EXT_BASE_GET_SPEC_VERSION = 0,
|
||||
SBI_EXT_BASE_GET_IMP_ID,
|
||||
SBI_EXT_BASE_GET_IMP_VERSION,
|
||||
SBI_EXT_BASE_PROBE_EXT,
|
||||
SBI_EXT_BASE_GET_MVENDORID,
|
||||
SBI_EXT_BASE_GET_MARCHID,
|
||||
SBI_EXT_BASE_GET_MIMPID,
|
||||
};
|
||||
/* 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
|
||||
|
@@ -20,6 +20,7 @@ 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);
|
||||
|
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);
|
||||
|
||||
|
@@ -30,21 +30,20 @@
|
||||
#define SBI_PLATFORM_HART_STACK_SIZE_OFFSET (0x54)
|
||||
/** Offset of disabled_hart_mask in struct sbi_platform */
|
||||
#define SBI_PLATFORM_DISABLED_HART_OFFSET (0x58)
|
||||
/** Offset of tlb_range_flush_limit in struct sbi_platform */
|
||||
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_OFFSET (0x60)
|
||||
/** Offset of platform_ops_addr in struct sbi_platform */
|
||||
#define SBI_PLATFORM_OPS_OFFSET (0x68)
|
||||
#define SBI_PLATFORM_OPS_OFFSET (0x60)
|
||||
/** Offset of firmware_context in struct sbi_platform */
|
||||
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x68 + __SIZEOF_POINTER__)
|
||||
#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_scratch.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 {
|
||||
@@ -75,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);
|
||||
/**
|
||||
@@ -93,6 +107,8 @@ 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);
|
||||
@@ -100,6 +116,11 @@ struct sbi_platform_operations {
|
||||
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);
|
||||
@@ -109,6 +130,8 @@ 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);
|
||||
@@ -119,9 +142,9 @@ struct sbi_platform_operations {
|
||||
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,
|
||||
unsigned long *out_trap_cause,
|
||||
unsigned long *out_trap_val);
|
||||
unsigned long *args,
|
||||
unsigned long *out_value,
|
||||
struct sbi_trap_info *out_trap);
|
||||
} __packed;
|
||||
|
||||
/** Representation of a platform */
|
||||
@@ -148,8 +171,6 @@ struct sbi_platform {
|
||||
u32 hart_stack_size;
|
||||
/** Mask representing the set of disabled HARTs */
|
||||
u64 disabled_hart_mask;
|
||||
/* Maximum value of tlb flush range request*/
|
||||
u64 tlb_range_flush_limit;
|
||||
/** Pointer to sbi platform operations */
|
||||
unsigned long platform_ops_addr;
|
||||
/** Pointer to system firmware specific context */
|
||||
@@ -189,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";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -225,8 +246,8 @@ static inline bool sbi_platform_hart_disabled(const struct sbi_platform *plat,
|
||||
*/
|
||||
static inline u64 sbi_platform_tlbr_flush_limit(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && plat->tlb_range_flush_limit)
|
||||
return plat->tlb_range_flush_limit;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -290,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
|
||||
*
|
||||
@@ -387,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
|
||||
*
|
||||
@@ -429,6 +513,17 @@ 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
|
||||
*
|
||||
@@ -484,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
|
||||
*
|
||||
@@ -540,25 +646,23 @@ static inline int sbi_platform_vendor_ext_check(const struct sbi_platform *plat,
|
||||
* @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 the callee
|
||||
* @param out_tcause trap cause that can be filled the callee
|
||||
* @param out_tvalue possible trap value that can be filled the callee
|
||||
* @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,
|
||||
unsigned long *out_tcause,
|
||||
unsigned long *out_tval)
|
||||
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_tcause,
|
||||
out_tval);
|
||||
funcid, args,
|
||||
out_value,
|
||||
out_trap);
|
||||
}
|
||||
|
||||
return SBI_ENOTSUPP;
|
||||
|
@@ -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 {
|
||||
|
@@ -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
|
||||
|
@@ -24,12 +24,12 @@ 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_stop(struct sbi_scratch *scratch);
|
||||
|
||||
void sbi_timer_event_start(struct sbi_scratch *scratch, u64 next_event);
|
||||
|
||||
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
|
||||
|
@@ -24,7 +24,10 @@
|
||||
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
|
||||
};
|
||||
|
||||
@@ -40,12 +43,9 @@ struct sbi_tlb_info {
|
||||
|
||||
#define SBI_TLB_INFO_SIZE sizeof(struct sbi_tlb_info)
|
||||
|
||||
int sbi_tlb_fifo_update(struct sbi_scratch *scratch, u32 hartid, 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);
|
||||
|
||||
int sbi_tlb_fifo_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||
|
||||
void sbi_tlb_fifo_sync(struct sbi_scratch *scratch);
|
||||
int sbi_tlb_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||
|
||||
#endif
|
||||
|
@@ -170,12 +170,28 @@ struct sbi_trap_regs {
|
||||
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 sbi_trap_info;
|
||||
|
||||
struct unpriv_trap {
|
||||
unsigned long ilen;
|
||||
unsigned long cause;
|
||||
unsigned long tval;
|
||||
};
|
||||
#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type) \
|
||||
type sbi_load_##type(const type *addr, \
|
||||
struct sbi_scratch *scratch, \
|
||||
struct sbi_trap_info *trap);
|
||||
|
||||
#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type) \
|
||||
type load_##type(const type *addr, \
|
||||
struct sbi_scratch *scratch, \
|
||||
struct unpriv_trap *trap);
|
||||
|
||||
#define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type) \
|
||||
void store_##type(type *addr, type val, \
|
||||
struct sbi_scratch *scratch, \
|
||||
struct unpriv_trap *trap);
|
||||
#define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type) \
|
||||
void sbi_store_##type(type *addr, type val, \
|
||||
struct sbi_scratch *scratch, \
|
||||
struct sbi_trap_info *trap);
|
||||
|
||||
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u8)
|
||||
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u16)
|
||||
@@ -43,7 +38,7 @@ DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u64)
|
||||
DECLARE_UNPRIVILEGED_STORE_FUNCTION(u64)
|
||||
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong)
|
||||
|
||||
ulong get_insn(ulong mepc, bool virt, struct sbi_scratch *scratch,
|
||||
struct unpriv_trap *trap);
|
||||
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 5
|
||||
#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)
|
||||
{
|
||||
|
@@ -79,7 +79,7 @@ long atomic_sub_return(atomic_t *atom, long value)
|
||||
#define axchg(ptr, x) \
|
||||
({ \
|
||||
__typeof__(*(ptr)) _x_ = (x); \
|
||||
(__typeof__(*(ptr))) __xchg((ptr), _x_, sizeof(*(ptr))); \
|
||||
(__typeof__(*(ptr))) __axchg((ptr), _x_, sizeof(*(ptr))); \
|
||||
})
|
||||
|
||||
|
||||
|
@@ -7,23 +7,10 @@
|
||||
* 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_platform.h>
|
||||
#include <sbi/sbi_system.h>
|
||||
#include <sbi/sbi_timer.h>
|
||||
#include <sbi/sbi_tlb.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_version.h>
|
||||
#include <sbi/riscv_asm.h>
|
||||
|
||||
#define SBI_ECALL_VERSION_MAJOR 0
|
||||
#define SBI_ECALL_VERSION_MINOR 2
|
||||
#define SBI_OPENSBI_IMPID 1
|
||||
|
||||
u16 sbi_ecall_version_major(void)
|
||||
{
|
||||
@@ -35,164 +22,64 @@ u16 sbi_ecall_version_minor(void)
|
||||
return SBI_ECALL_VERSION_MINOR;
|
||||
}
|
||||
|
||||
int sbi_check_extension(struct sbi_scratch *scratch, unsigned long extid,
|
||||
unsigned long *out_val)
|
||||
{
|
||||
/**
|
||||
* Each extension apart from base & 0.1, will be implemented as
|
||||
* platform specific feature. Thus, extension probing can be achieved
|
||||
* by checking the feature bits of the platform. We can create a map
|
||||
* between extension ID & feature and use a generic function to check
|
||||
* or just use a switch case for every new extension support added
|
||||
* TODO: Implement it.
|
||||
*/
|
||||
static SBI_LIST_HEAD(ecall_exts_list);
|
||||
|
||||
if ((extid >= SBI_EXT_0_1_SET_TIMER &&
|
||||
extid <= SBI_EXT_0_1_SHUTDOWN) || (extid == SBI_EXT_BASE)) {
|
||||
*out_val = 1;
|
||||
} else if (extid >= SBI_EXT_VENDOR_START &&
|
||||
extid <= SBI_EXT_VENDOR_END) {
|
||||
*out_val = sbi_platform_vendor_ext_check(
|
||||
sbi_platform_ptr(scratch),
|
||||
extid);
|
||||
} else
|
||||
*out_val = 0;
|
||||
struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
|
||||
{
|
||||
struct sbi_ecall_extension *t, *ret = NULL;
|
||||
|
||||
sbi_list_for_each_entry(t, &ecall_exts_list, head) {
|
||||
if (t->extid_start <= extid && extid <= t->extid_end) {
|
||||
ret = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
int sbi_ecall_vendor_ext_handler(struct sbi_scratch *scratch,
|
||||
unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
unsigned long *out_tcause,
|
||||
unsigned long *out_tval)
|
||||
void sbi_ecall_unregister_extension(struct sbi_ecall_extension *ext)
|
||||
{
|
||||
return sbi_platform_vendor_ext_provider(sbi_platform_ptr(scratch),
|
||||
extid, funcid, args, out_val,
|
||||
out_tcause, out_tval);
|
||||
}
|
||||
bool found = FALSE;
|
||||
struct sbi_ecall_extension *t;
|
||||
|
||||
int sbi_ecall_base_handler(struct sbi_scratch *scratch, unsigned long extid,
|
||||
unsigned long funcid, unsigned long *args,
|
||||
unsigned long *out_val, unsigned long *out_tcause,
|
||||
unsigned long *out_tval)
|
||||
{
|
||||
int ret = 0;
|
||||
if (!ext)
|
||||
return;
|
||||
|
||||
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_check_extension(scratch, args[0], out_val);
|
||||
default:
|
||||
ret = SBI_ENOTSUPP;
|
||||
sbi_list_for_each_entry(t, &ecall_exts_list, head) {
|
||||
if (t == ext) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sbi_ecall_0_1_handler(struct sbi_scratch *scratch, unsigned long extid,
|
||||
unsigned long *args, unsigned long *tval,
|
||||
unsigned long *tcause)
|
||||
{
|
||||
int ret = 0;
|
||||
struct sbi_tlb_info tlb_info;
|
||||
u32 source_hart = sbi_current_hartid();
|
||||
struct unpriv_trap uptrap = {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_ipi_send_many(scratch, &uptrap, (ulong *)args[0],
|
||||
SBI_IPI_EVENT_SOFT, NULL);
|
||||
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_ipi_send_many(scratch, &uptrap, (ulong *)args[0],
|
||||
SBI_IPI_EVENT_FENCE_I, &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_ipi_send_many(scratch, &uptrap, (ulong *)args[0],
|
||||
SBI_IPI_EVENT_SFENCE_VMA, &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_ipi_send_many(scratch, &uptrap, (ulong *)args[0],
|
||||
SBI_IPI_EVENT_SFENCE_VMA_ASID,
|
||||
&tlb_info);
|
||||
break;
|
||||
case SBI_EXT_0_1_SHUTDOWN:
|
||||
sbi_system_shutdown(scratch, 0);
|
||||
break;
|
||||
default:
|
||||
ret = SBI_ENOTSUPP;
|
||||
};
|
||||
|
||||
if (ret == SBI_ETRAP) {
|
||||
*tcause = uptrap.cause;
|
||||
*tval = uptrap.tval;
|
||||
}
|
||||
return ret;
|
||||
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;
|
||||
unsigned long out_val;
|
||||
unsigned long out_tval;
|
||||
unsigned long out_tcause;
|
||||
struct sbi_trap_info trap = {0};
|
||||
unsigned long out_val = 0;
|
||||
bool is_0_1_spec = 0;
|
||||
unsigned long args[6];
|
||||
|
||||
@@ -203,27 +90,20 @@ int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs,
|
||||
args[4] = regs->a4;
|
||||
args[5] = regs->a5;
|
||||
|
||||
if (extension_id >= SBI_EXT_0_1_SET_TIMER &&
|
||||
extension_id <= SBI_EXT_0_1_SHUTDOWN) {
|
||||
ret = sbi_ecall_0_1_handler(scratch, extension_id, args,
|
||||
&out_tval, &out_tcause);
|
||||
is_0_1_spec = 1;
|
||||
} else if (extension_id == SBI_EXT_BASE)
|
||||
ret = sbi_ecall_base_handler(scratch, extension_id, func_id,
|
||||
args, &out_val,
|
||||
&out_tval, &out_tcause);
|
||||
else if (extension_id >= SBI_EXT_VENDOR_START &&
|
||||
extension_id <= SBI_EXT_VENDOR_END) {
|
||||
ret = sbi_ecall_vendor_ext_handler(scratch, extension_id,
|
||||
func_id, args, &out_val,
|
||||
&out_tval, &out_tcause);
|
||||
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) {
|
||||
sbi_trap_redirect(regs, scratch, regs->mepc,
|
||||
out_tcause, out_tval);
|
||||
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
|
||||
@@ -240,3 +120,30 @@ int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs,
|
||||
|
||||
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,
|
||||
};
|
@@ -88,24 +88,36 @@ static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
|
||||
(1U << CAUSE_STORE_PAGE_FAULT);
|
||||
|
||||
/*
|
||||
* If hypervisor extension available then we only handle
|
||||
* hypervisor calls (i.e. ecalls from HS-mode) and we let
|
||||
* HS-mode handle supervisor calls (i.e. ecalls from VS-mode)
|
||||
* 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'))
|
||||
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;
|
||||
@@ -137,9 +149,9 @@ void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
|
||||
else
|
||||
size = 0;
|
||||
#if __riscv_xlen == 32
|
||||
sbi_printf("PMP%d: 0x%08lx-0x%08lx (A",
|
||||
sbi_printf("PMP%d : 0x%08lx-0x%08lx (A",
|
||||
#else
|
||||
sbi_printf("PMP%d: 0x%016lx-0x%016lx (A",
|
||||
sbi_printf("PMP%d : 0x%016lx-0x%016lx (A",
|
||||
#endif
|
||||
i, addr, addr + size - 1);
|
||||
if (prot & PMP_L)
|
||||
@@ -271,7 +283,6 @@ sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
|
||||
#if __riscv_xlen == 32
|
||||
if (misa_extension('H')) {
|
||||
valH = csr_read(CSR_MSTATUSH);
|
||||
valH = INSERT_FIELD(valH, MSTATUSH_MTL, 0);
|
||||
if (next_virt)
|
||||
valH = INSERT_FIELD(valH, MSTATUSH_MPV, 1);
|
||||
else
|
||||
@@ -280,7 +291,6 @@ sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
|
||||
}
|
||||
#else
|
||||
if (misa_extension('H')) {
|
||||
val = INSERT_FIELD(val, MSTATUS_MTL, 0);
|
||||
if (next_virt)
|
||||
val = INSERT_FIELD(val, MSTATUS_MPV, 1);
|
||||
else
|
||||
@@ -350,12 +360,16 @@ static unsigned long coldboot_wait_bitmap = 0;
|
||||
|
||||
void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
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);
|
||||
|
||||
@@ -378,6 +392,9 @@ void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
/* 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);
|
||||
}
|
||||
|
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,
|
||||
@@ -46,8 +54,8 @@ static int system_opcode_insn(ulong insn, u32 hartid, ulong mcause,
|
||||
if ((regs->mstatus & MSTATUS_MPV) &&
|
||||
#endif
|
||||
(insn & INSN_MASK_WFI) == INSN_MATCH_WFI)
|
||||
return sbi_trap_redirect(regs, scratch,
|
||||
regs->mepc, mcause, insn);
|
||||
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,
|
||||
@@ -125,24 +133,20 @@ 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(CSR_MTVAL);
|
||||
#if __riscv_xlen == 32
|
||||
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
|
||||
#else
|
||||
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
|
||||
#endif
|
||||
struct unpriv_trap uptrap;
|
||||
struct sbi_trap_info uptrap;
|
||||
|
||||
if (unlikely((insn & 3) != 3)) {
|
||||
if (insn == 0) {
|
||||
insn = get_insn(regs->mepc, virt, scratch, &uptrap);
|
||||
if (uptrap.cause)
|
||||
return sbi_trap_redirect(regs, scratch,
|
||||
regs->mepc, uptrap.cause, uptrap.tval);
|
||||
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,
|
||||
|
@@ -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,23 +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));
|
||||
#ifdef OPENSBI_VERSION_GIT
|
||||
sbi_printf("\nOpenSBI %s (%s %s)\n", OPENSBI_VERSION_GIT,
|
||||
__DATE__, __TIME__);
|
||||
sbi_printf("\nOpenSBI %s\n", OPENSBI_VERSION_GIT);
|
||||
#else
|
||||
sbi_printf("\nOpenSBI v%d.%d (%s %s)\n", OPENSBI_VERSION_MAJOR,
|
||||
OPENSBI_VERSION_MINOR, __DATE__, __TIME__);
|
||||
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);
|
||||
@@ -59,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();
|
||||
@@ -87,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();
|
||||
@@ -98,9 +124,13 @@ 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_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, FALSE);
|
||||
}
|
||||
@@ -108,12 +138,12 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
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);
|
||||
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);
|
||||
@@ -132,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();
|
||||
@@ -142,13 +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
|
||||
sbi_hart_switch_mode(hartid, scratch->next_arg1,
|
||||
scratch->next_addr,
|
||||
scratch->next_mode, FALSE);
|
||||
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, FALSE);
|
||||
}
|
||||
|
||||
static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);
|
||||
@@ -182,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();
|
||||
}
|
||||
|
@@ -11,89 +11,168 @@
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/riscv_atomic.h>
|
||||
#include <sbi/riscv_barrier.h>
|
||||
#include <sbi/riscv_unpriv.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_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 ||
|
||||
event == SBI_IPI_EVENT_FENCE_I ) {
|
||||
ret = sbi_tlb_fifo_update(remote_scratch, hartid, data);
|
||||
|
||||
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);
|
||||
smp_wmb();
|
||||
sbi_platform_ipi_send(plat, hartid);
|
||||
sbi_platform_ipi_send(plat, remote_hartid);
|
||||
|
||||
if (event == SBI_IPI_EVENT_SFENCE_VMA ||
|
||||
event == SBI_IPI_EVENT_SFENCE_VMA_ASID ||
|
||||
event == SBI_IPI_EVENT_FENCE_I ) {
|
||||
sbi_tlb_fifo_sync(scratch);
|
||||
}
|
||||
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 */
|
||||
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)
|
||||
{
|
||||
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);
|
||||
@@ -107,21 +186,9 @@ void sbi_ipi_process(struct sbi_scratch *scratch)
|
||||
if (!(ipi_type & 1UL))
|
||||
goto skip;
|
||||
|
||||
switch (ipi_event) {
|
||||
case SBI_IPI_EVENT_SOFT:
|
||||
csr_set(CSR_MIP, MIP_SSIP);
|
||||
break;
|
||||
case SBI_IPI_EVENT_FENCE_I:
|
||||
case SBI_IPI_EVENT_SFENCE_VMA:
|
||||
case SBI_IPI_EVENT_SFENCE_VMA_ASID:
|
||||
sbi_tlb_fifo_process(scratch);
|
||||
break;
|
||||
case SBI_IPI_EVENT_HALT:
|
||||
sbi_hart_hang();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
ipi_ops = ipi_ops_array[ipi_event];
|
||||
if (ipi_ops && ipi_ops->process)
|
||||
ipi_ops->process(scratch);
|
||||
|
||||
skip:
|
||||
ipi_type = ipi_type >> 1;
|
||||
@@ -139,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,23 +22,32 @@ 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 addr = csr_read(CSR_MTVAL);
|
||||
struct sbi_trap_info uptrap;
|
||||
int i, fp = 0, shift = 0, len = 0;
|
||||
#if __riscv_xlen == 32
|
||||
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
|
||||
#else
|
||||
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
|
||||
#endif
|
||||
ulong insn = get_insn(regs->mepc, virt, scratch, &uptrap);
|
||||
|
||||
if (uptrap.cause)
|
||||
return sbi_trap_redirect(regs, scratch, regs->mepc,
|
||||
uptrap.cause, uptrap.tval);
|
||||
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;
|
||||
@@ -101,17 +110,23 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
} else
|
||||
return sbi_trap_redirect(regs, scratch, regs->mepc,
|
||||
mcause, addr);
|
||||
} 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),
|
||||
scratch, &uptrap);
|
||||
if (uptrap.cause)
|
||||
return sbi_trap_redirect(regs, scratch, regs->mepc,
|
||||
uptrap.cause, uptrap.tval);
|
||||
val.data_bytes[i] = sbi_load_u8((void *)(addr + i),
|
||||
scratch, &uptrap);
|
||||
if (uptrap.cause) {
|
||||
uptrap.epc = regs->mepc;
|
||||
return sbi_trap_redirect(regs, &uptrap, scratch);
|
||||
}
|
||||
}
|
||||
|
||||
if (!fp)
|
||||
@@ -129,23 +144,32 @@ 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 addr = csr_read(CSR_MTVAL);
|
||||
struct sbi_trap_info uptrap;
|
||||
int i, len = 0;
|
||||
#if __riscv_xlen == 32
|
||||
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
|
||||
#else
|
||||
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
|
||||
#endif
|
||||
ulong insn = get_insn(regs->mepc, virt, scratch, &uptrap);
|
||||
|
||||
if (uptrap.cause)
|
||||
return sbi_trap_redirect(regs, scratch, regs->mepc,
|
||||
uptrap.cause, uptrap.tval);
|
||||
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);
|
||||
|
||||
@@ -199,16 +223,22 @@ int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
} else
|
||||
return sbi_trap_redirect(regs, scratch, regs->mepc,
|
||||
mcause, addr);
|
||||
} 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],
|
||||
scratch, &uptrap);
|
||||
if (uptrap.cause)
|
||||
return sbi_trap_redirect(regs, scratch, regs->mepc,
|
||||
uptrap.cause, uptrap.tval);
|
||||
sbi_store_u8((void *)(addr + i), val.data_bytes[i],
|
||||
scratch, &uptrap);
|
||||
if (uptrap.cause) {
|
||||
uptrap.epc = regs->mepc;
|
||||
return sbi_trap_redirect(regs, &uptrap, scratch);
|
||||
}
|
||||
}
|
||||
|
||||
regs->mepc += INSN_LEN(insn);
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -76,11 +76,6 @@ void sbi_timer_set_delta_upper(struct sbi_scratch *scratch, ulong delta_upper)
|
||||
*time_delta |= ((u64)delta_upper << 32);
|
||||
}
|
||||
|
||||
void sbi_timer_event_stop(struct sbi_scratch *scratch)
|
||||
{
|
||||
sbi_platform_timer_event_stop(sbi_platform_ptr(scratch));
|
||||
}
|
||||
|
||||
void sbi_timer_event_start(struct sbi_scratch *scratch, u64 next_event)
|
||||
{
|
||||
sbi_platform_timer_event_start(sbi_platform_ptr(scratch), next_event);
|
||||
@@ -113,3 +108,13 @@ int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||
|
||||
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));
|
||||
}
|
||||
|
@@ -14,8 +14,10 @@
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_fifo.h>
|
||||
#include <sbi/sbi_hart.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>
|
||||
@@ -30,7 +32,39 @@ 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;
|
||||
@@ -49,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;
|
||||
@@ -80,15 +158,32 @@ static void sbi_tlb_fifo_sfence_vma_asid(struct sbi_tlb_info *tinfo)
|
||||
|
||||
static void sbi_tlb_local_flush(struct sbi_tlb_info *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);
|
||||
} else if (tinfo->type == SBI_ITLB_FLUSH)
|
||||
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");
|
||||
else
|
||||
break;
|
||||
default:
|
||||
sbi_printf("Invalid tlb flush request type [%lu]\n",
|
||||
tinfo->type);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -111,7 +206,7 @@ static void sbi_tlb_entry_process(struct sbi_scratch *scratch,
|
||||
}
|
||||
}
|
||||
|
||||
static void sbi_tlb_fifo_process_count(struct sbi_scratch *scratch, int count)
|
||||
static void sbi_tlb_process_count(struct sbi_scratch *scratch, int count)
|
||||
{
|
||||
struct sbi_tlb_info tinfo;
|
||||
u32 deq_count = 0;
|
||||
@@ -127,7 +222,7 @@ static void sbi_tlb_fifo_process_count(struct sbi_scratch *scratch, int count)
|
||||
}
|
||||
}
|
||||
|
||||
void sbi_tlb_fifo_process(struct sbi_scratch *scratch)
|
||||
static void sbi_tlb_process(struct sbi_scratch *scratch)
|
||||
{
|
||||
struct sbi_tlb_info tinfo;
|
||||
struct sbi_fifo *tlb_fifo =
|
||||
@@ -137,7 +232,7 @@ void sbi_tlb_fifo_process(struct sbi_scratch *scratch)
|
||||
sbi_tlb_entry_process(scratch, &tinfo);
|
||||
}
|
||||
|
||||
void sbi_tlb_fifo_sync(struct sbi_scratch *scratch)
|
||||
static void sbi_tlb_sync(struct sbi_scratch *scratch)
|
||||
{
|
||||
unsigned long *tlb_sync =
|
||||
sbi_scratch_offset_ptr(scratch, tlb_sync_off);
|
||||
@@ -147,14 +242,14 @@ void sbi_tlb_fifo_sync(struct sbi_scratch *scratch)
|
||||
* While we are waiting for remote hart to set the sync,
|
||||
* consume fifo requests to avoid deadlock.
|
||||
*/
|
||||
sbi_tlb_fifo_process_count(scratch, 1);
|
||||
sbi_tlb_process_count(scratch, 1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static inline int __sbi_tlb_fifo_range_check(struct sbi_tlb_info *curr,
|
||||
struct sbi_tlb_info *next)
|
||||
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;
|
||||
@@ -196,7 +291,7 @@ static inline int __sbi_tlb_fifo_range_check(struct sbi_tlb_info *curr,
|
||||
* before continuing the while loop. This method is preferred over wfi/ipi because
|
||||
* of MMIO cost involved in later method.
|
||||
*/
|
||||
static int sbi_tlb_fifo_update_cb(void *in, void *data)
|
||||
static int sbi_tlb_update_cb(void *in, void *data)
|
||||
{
|
||||
struct sbi_tlb_info *curr;
|
||||
struct sbi_tlb_info *next;
|
||||
@@ -211,20 +306,21 @@ static int sbi_tlb_fifo_update_cb(void *in, void *data)
|
||||
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);
|
||||
ret = __sbi_tlb_range_check(curr, next);
|
||||
} else if (next->type == SBI_TLB_FLUSH_VMA &&
|
||||
curr->type == SBI_TLB_FLUSH_VMA) {
|
||||
ret = __sbi_tlb_fifo_range_check(curr, next);
|
||||
ret = __sbi_tlb_range_check(curr, next);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sbi_tlb_fifo_update(struct sbi_scratch *rscratch, u32 hartid, void *data)
|
||||
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_scratch *lscratch;
|
||||
struct sbi_tlb_info *tinfo = data;
|
||||
u32 curr_hartid = sbi_current_hartid();
|
||||
|
||||
@@ -242,15 +338,14 @@ int sbi_tlb_fifo_update(struct sbi_scratch *rscratch, u32 hartid, void *data)
|
||||
* If the request is to queue a tlb flush entry for itself
|
||||
* then just do a local flush and return;
|
||||
*/
|
||||
if (hartid == curr_hartid) {
|
||||
if (remote_hartid == curr_hartid) {
|
||||
sbi_tlb_local_flush(tinfo);
|
||||
return -1;
|
||||
}
|
||||
|
||||
lscratch = sbi_hart_id_to_scratch(rscratch, curr_hartid);
|
||||
tlb_fifo_r = sbi_scratch_offset_ptr(rscratch, tlb_fifo_off);
|
||||
tlb_fifo_r = sbi_scratch_offset_ptr(remote_scratch, tlb_fifo_off);
|
||||
|
||||
ret = sbi_fifo_inplace_update(tlb_fifo_r, data, sbi_tlb_fifo_update_cb);
|
||||
ret = sbi_fifo_inplace_update(tlb_fifo_r, data, sbi_tlb_update_cb);
|
||||
if (ret != SBI_FIFO_UNCHANGED) {
|
||||
return 1;
|
||||
}
|
||||
@@ -264,16 +359,32 @@ int sbi_tlb_fifo_update(struct sbi_scratch *rscratch, u32 hartid, void *data)
|
||||
* TODO: Introduce a wait/wakeup event mechanism to handle
|
||||
* this properly.
|
||||
*/
|
||||
sbi_tlb_fifo_process_count(lscratch, 1);
|
||||
sbi_dprintf(rscratch, "hart%d: hart%d tlb fifo full\n",
|
||||
curr_hartid, hartid);
|
||||
sbi_tlb_process_count(scratch, 1);
|
||||
sbi_dprintf(remote_scratch, "hart%d: hart%d tlb fifo full\n",
|
||||
curr_hartid, remote_hartid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sbi_tlb_fifo_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||
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;
|
||||
@@ -298,12 +409,22 @@ int sbi_tlb_fifo_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||
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 (!tlb_sync_off ||
|
||||
!tlb_fifo_off ||
|
||||
!tlb_fifo_mem_off)
|
||||
return SBI_ENOMEM;
|
||||
if (SBI_IPI_EVENT_MAX <= tlb_event)
|
||||
return SBI_ENOSPC;
|
||||
}
|
||||
|
||||
tlb_sync = sbi_scratch_offset_ptr(scratch, tlb_sync_off);
|
||||
|
@@ -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,23 +73,20 @@ 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 hstatus, vsstatus, prev_mode;
|
||||
#if __riscv_xlen == 32
|
||||
bool prev_virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
|
||||
bool prev_stage2 = (regs->mstatusH & MSTATUSH_MTL) ? TRUE : FALSE;
|
||||
#else
|
||||
bool prev_virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
|
||||
bool prev_stage2 = (regs->mstatus & MSTATUS_MTL) ? TRUE : FALSE;
|
||||
#endif
|
||||
/* By default, we redirect to HS-mode */
|
||||
bool next_virt = FALSE;
|
||||
@@ -96,8 +97,8 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch,
|
||||
return SBI_ENOTSUPP;
|
||||
|
||||
/* For certain exceptions from VS/VU-mode we redirect to VS-mode */
|
||||
if (misa_extension('H') && prev_virt && !prev_stage2) {
|
||||
switch (cause) {
|
||||
if (misa_extension('H') && prev_virt) {
|
||||
switch (trap->cause) {
|
||||
case CAUSE_FETCH_PAGE_FAULT:
|
||||
case CAUSE_LOAD_PAGE_FAULT:
|
||||
case CAUSE_STORE_PAGE_FAULT:
|
||||
@@ -108,20 +109,18 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch,
|
||||
};
|
||||
}
|
||||
|
||||
/* Update MSTATUS MPV and MTL bits */
|
||||
/* Update MSTATUS MPV bits */
|
||||
#if __riscv_xlen == 32
|
||||
regs->mstatusH &= ~MSTATUSH_MPV;
|
||||
regs->mstatusH |= (next_virt) ? MSTATUSH_MPV : 0UL;
|
||||
regs->mstatusH &= ~MSTATUSH_MTL;
|
||||
#else
|
||||
regs->mstatus &= ~MSTATUS_MPV;
|
||||
regs->mstatus |= (next_virt) ? MSTATUS_MPV : 0UL;
|
||||
regs->mstatus &= ~MSTATUS_MTL;
|
||||
#endif
|
||||
|
||||
/* Update HSTATUS for VS/VU-mode to HS-mode transition */
|
||||
if (misa_extension('H') && prev_virt && !next_virt) {
|
||||
/* Update HSTATUS SP2P, SP2V, SPV, and STL bits */
|
||||
/* Update HSTATUS SP2P, SP2V, and SPV bits */
|
||||
hstatus = csr_read(CSR_HSTATUS);
|
||||
hstatus &= ~HSTATUS_SP2P;
|
||||
hstatus |= (regs->mstatus & MSTATUS_SPP) ? HSTATUS_SP2P : 0;
|
||||
@@ -129,17 +128,17 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch,
|
||||
hstatus |= (hstatus & HSTATUS_SPV) ? HSTATUS_SP2V : 0;
|
||||
hstatus &= ~HSTATUS_SPV;
|
||||
hstatus |= (prev_virt) ? HSTATUS_SPV : 0;
|
||||
hstatus &= ~HSTATUS_STL;
|
||||
hstatus |= (prev_stage2) ? HSTATUS_STL : 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, tval);
|
||||
csr_write(CSR_VSEPC, epc);
|
||||
csr_write(CSR_VSCAUSE, cause);
|
||||
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);
|
||||
@@ -168,9 +167,9 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch,
|
||||
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);
|
||||
@@ -205,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));
|
||||
@@ -238,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;
|
||||
@@ -262,25 +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);
|
||||
}
|
||||
}
|
||||
|
@@ -8,25 +8,31 @@
|
||||
*/
|
||||
|
||||
#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>
|
||||
#include <sbi/sbi_trap.h>
|
||||
#include <sbi/sbi_unpriv.h>
|
||||
|
||||
#define DEFINE_UNPRIVILEGED_LOAD_FUNCTION(type, insn, insnlen) \
|
||||
type load_##type(const type *addr, \
|
||||
struct sbi_scratch *scratch, \
|
||||
struct unpriv_trap *trap) \
|
||||
#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->ilen = insnlen; \
|
||||
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)); \
|
||||
@@ -34,101 +40,116 @@
|
||||
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) \
|
||||
#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->ilen = insnlen; \
|
||||
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, 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)
|
||||
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, 4)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld, 2)
|
||||
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u64, sd, 2)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld, 2)
|
||||
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, 2)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw, 2)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw)
|
||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw)
|
||||
|
||||
u64 load_u64(const u64 *addr,
|
||||
struct sbi_scratch *scratch, struct unpriv_trap *trap)
|
||||
u64 sbi_load_u64(const u64 *addr,
|
||||
struct sbi_scratch *scratch,
|
||||
struct sbi_trap_info *trap)
|
||||
{
|
||||
u64 ret = load_u32((u32 *)addr, scratch, trap);
|
||||
u64 ret = sbi_load_u32((u32 *)addr, scratch, trap);
|
||||
|
||||
if (trap->cause)
|
||||
return 0;
|
||||
ret |= ((u64)load_u32((u32 *)addr + 1, scratch, trap) << 32);
|
||||
ret |= ((u64)sbi_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)
|
||||
void sbi_store_u64(u64 *addr, u64 val,
|
||||
struct sbi_scratch *scratch,
|
||||
struct sbi_trap_info *trap)
|
||||
{
|
||||
store_u32((u32 *)addr, val, scratch, trap);
|
||||
sbi_store_u32((u32 *)addr, val, scratch, trap);
|
||||
if (trap->cause)
|
||||
return;
|
||||
|
||||
store_u32((u32 *)addr + 1, val >> 32, scratch, trap);
|
||||
sbi_store_u32((u32 *)addr + 1, val >> 32, scratch, trap);
|
||||
if (trap->cause)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
ulong get_insn(ulong mepc, bool virt, struct sbi_scratch *scratch,
|
||||
struct unpriv_trap *trap)
|
||||
ulong sbi_get_insn(ulong mepc, struct sbi_scratch *scratch,
|
||||
struct sbi_trap_info *trap)
|
||||
{
|
||||
ulong __mstatus = 0, __vsstatus = 0, val = 0;
|
||||
ulong __mstatus = 0, val = 0;
|
||||
#ifdef __riscv_compressed
|
||||
ulong rvc_mask = 3, tmp;
|
||||
#endif
|
||||
|
||||
trap->ilen = 4;
|
||||
trap->epc = 0;
|
||||
trap->cause = 0;
|
||||
trap->tval = 0;
|
||||
trap->tval2 = 0;
|
||||
trap->tinst = 0;
|
||||
sbi_hart_set_trap_info(scratch, trap);
|
||||
|
||||
if (virt)
|
||||
__vsstatus = csr_read_set(CSR_VSSTATUS, SSTATUS_MXR);
|
||||
|
||||
#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]"
|
||||
@@ -137,10 +158,8 @@ ulong get_insn(ulong mepc, bool virt, struct sbi_scratch *scratch,
|
||||
[rvc_mask] "r"(rvc_mask));
|
||||
#endif
|
||||
|
||||
if (virt)
|
||||
csr_write(CSR_VSSTATUS, __vsstatus);
|
||||
|
||||
sbi_hart_set_trap_info(scratch, NULL);
|
||||
|
||||
switch (trap->cause) {
|
||||
case CAUSE_LOAD_ACCESS:
|
||||
trap->cause = CAUSE_FETCH_ACCESS;
|
||||
@@ -150,6 +169,10 @@ ulong get_insn(ulong mepc, bool virt, struct sbi_scratch *scratch,
|
||||
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;
|
||||
};
|
@@ -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;
|
||||
}
|
||||
|
@@ -62,25 +62,45 @@ static volatile void *clint_time_base;
|
||||
static volatile u64 *clint_time_val;
|
||||
static volatile u64 *clint_time_cmp;
|
||||
|
||||
static inline u32 clint_time_read_hi()
|
||||
#if __riscv_xlen != 32
|
||||
static u64 clint_time_rd64(volatile u64 *addr)
|
||||
{
|
||||
return readl_relaxed((u32 *)clint_time_val + 1);
|
||||
return readq_relaxed(addr);
|
||||
}
|
||||
|
||||
u64 clint_timer_value(void)
|
||||
static void clint_time_wr64(u64 value, volatile u64 *addr)
|
||||
{
|
||||
writeq_relaxed(value, addr);
|
||||
}
|
||||
#endif
|
||||
|
||||
static u64 clint_time_rd32(volatile u64 *addr)
|
||||
{
|
||||
#if __riscv_xlen == 64
|
||||
return readq_relaxed(clint_time_val);
|
||||
#else
|
||||
u32 lo, hi;
|
||||
|
||||
do {
|
||||
hi = clint_time_read_hi();
|
||||
lo = readl_relaxed(clint_time_val);
|
||||
} while (hi != clint_time_read_hi());
|
||||
hi = readl_relaxed((u32 *)addr + 1);
|
||||
lo = readl_relaxed((u32 *)addr);
|
||||
} while (hi != readl_relaxed((u32 *)addr + 1));
|
||||
|
||||
return ((u64)hi << 32) | (u64)lo;
|
||||
#endif
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
/* Read CLINT Time Value */
|
||||
return clint_time_rd(clint_time_val);
|
||||
}
|
||||
|
||||
void clint_timer_event_stop(void)
|
||||
@@ -90,13 +110,8 @@ void clint_timer_event_stop(void)
|
||||
if (clint_time_hart_count <= target_hart)
|
||||
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
|
||||
/* Clear CLINT Time Compare */
|
||||
clint_time_wr(-1ULL, &clint_time_cmp[target_hart]);
|
||||
}
|
||||
|
||||
void clint_timer_event_start(u64 next_event)
|
||||
@@ -106,15 +121,8 @@ void clint_timer_event_start(u64 next_event)
|
||||
if (clint_time_hart_count <= target_hart)
|
||||
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
|
||||
/* Program CLINT Time Compare */
|
||||
clint_time_wr(next_event, &clint_time_cmp[target_hart]);
|
||||
}
|
||||
|
||||
int clint_warm_timer_init(void)
|
||||
@@ -124,24 +132,28 @@ int clint_warm_timer_init(void)
|
||||
if (clint_time_hart_count <= target_hart || !clint_time_base)
|
||||
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);
|
||||
/* Clear CLINT Time Compare */
|
||||
clint_time_wr(-1ULL, &clint_time_cmp[target_hart]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
clint_time_base = (void *)base;
|
||||
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;
|
||||
}
|
||||
|
||||
int clint_cold_timer_init(unsigned long base, u32 hart_count)
|
||||
{
|
||||
/* Figure-out CLINT Time register address */
|
||||
clint_time_hart_count = hart_count;
|
||||
clint_time_base = (void *)base;
|
||||
clint_time_val = (u64 *)(clint_time_base + 0xbff8);
|
||||
clint_time_cmp = (u64 *)(clint_time_base + 0x4000);
|
||||
|
||||
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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -88,7 +88,7 @@ static int k210_timer_init(bool cold_boot)
|
||||
|
||||
if (cold_boot) {
|
||||
rc = clint_cold_timer_init(K210_CLINT_BASE_ADDR,
|
||||
K210_HART_COUNT);
|
||||
K210_HART_COUNT, TRUE);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
@@ -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,158 +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_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
|
||||
};
|
@@ -17,29 +17,24 @@ platform-ldflags-y =
|
||||
platform-runcmd = qemu-system-riscv$(PLATFORM_RISCV_XLEN) -M virt -m 256M \
|
||||
-nographic -kernel $(build_dir)/platform/qemu/virt/firmware/fw_payload.elf
|
||||
|
||||
# Common drivers to enable
|
||||
PLATFORM_IRQCHIP_PLIC=y
|
||||
PLATFORM_SERIAL_UART8250=y
|
||||
PLATFORM_SYS_CLINT=y
|
||||
|
||||
# Blobs to build
|
||||
FW_TEXT_START=0x80000000
|
||||
FW_DYNAMIC=y
|
||||
FW_JUMP=y
|
||||
ifeq ($(PLATFORM_RISCV_XLEN), 32)
|
||||
# This needs to be 4MB alligned for 32-bit system
|
||||
# This needs to be 4MB aligned for 32-bit system
|
||||
FW_JUMP_ADDR=0x80400000
|
||||
else
|
||||
# This needs to be 2MB alligned for 64-bit system
|
||||
# This needs to be 2MB aligned for 64-bit system
|
||||
FW_JUMP_ADDR=0x80200000
|
||||
endif
|
||||
FW_JUMP_FDT_ADDR=0x82200000
|
||||
FW_PAYLOAD=y
|
||||
ifeq ($(PLATFORM_RISCV_XLEN), 32)
|
||||
# This needs to be 4MB alligned for 32-bit system
|
||||
# This needs to be 4MB aligned for 32-bit system
|
||||
FW_PAYLOAD_OFFSET=0x400000
|
||||
else
|
||||
# This needs to be 2MB alligned for 64-bit system
|
||||
# This needs to be 2MB aligned for 64-bit system
|
||||
FW_PAYLOAD_OFFSET=0x200000
|
||||
endif
|
||||
FW_PAYLOAD_FDT_ADDR=0x82200000
|
||||
|
@@ -114,7 +114,8 @@ static int virt_timer_init(bool cold_boot)
|
||||
int rc;
|
||||
|
||||
if (cold_boot) {
|
||||
rc = clint_cold_timer_init(VIRT_CLINT_ADDR, VIRT_HART_COUNT);
|
||||
rc = clint_cold_timer_init(VIRT_CLINT_ADDR,
|
||||
VIRT_HART_COUNT, TRUE);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
@@ -13,12 +13,28 @@ platform-cflags-y =
|
||||
platform-asflags-y =
|
||||
platform-ldflags-y =
|
||||
|
||||
# Command for platform specific "make run"
|
||||
platform-runcmd = qemu-system-riscv$(PLATFORM_RISCV_XLEN) -M sifive_u -m 256M \
|
||||
-nographic -kernel $(build_dir)/platform/sifive/fu540/firmware/fw_payload.elf
|
||||
|
||||
# Blobs to build
|
||||
FW_TEXT_START=0x80000000
|
||||
FW_DYNAMIC=y
|
||||
FW_JUMP=y
|
||||
FW_JUMP_ADDR=0x80200000
|
||||
ifeq ($(PLATFORM_RISCV_XLEN), 32)
|
||||
# This needs to be 4MB aligned for 32-bit system
|
||||
FW_JUMP_ADDR=0x80400000
|
||||
else
|
||||
# This needs to be 2MB aligned for 64-bit system
|
||||
FW_JUMP_ADDR=0x80200000
|
||||
endif
|
||||
FW_JUMP_FDT_ADDR=0x88000000
|
||||
FW_PAYLOAD=y
|
||||
FW_PAYLOAD_OFFSET=0x200000
|
||||
ifeq ($(PLATFORM_RISCV_XLEN), 32)
|
||||
# This needs to be 4MB aligned for 32-bit system
|
||||
FW_PAYLOAD_OFFSET=0x400000
|
||||
else
|
||||
# This needs to be 2MB aligned for 64-bit system
|
||||
FW_PAYLOAD_OFFSET=0x200000
|
||||
endif
|
||||
FW_PAYLOAD_FDT_ADDR=0x88000000
|
||||
|
@@ -52,6 +52,9 @@
|
||||
#define FU540_PRCI_CLKMUXSTATUSREG 0x002C
|
||||
#define FU540_PRCI_CLKMUX_STATUS_TLCLKSEL (0x1 << 1)
|
||||
|
||||
/* Full tlb flush always */
|
||||
#define FU540_TLB_RANGE_FLUSH_LIMIT 0
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
static void fu540_modify_dt(void *fdt)
|
||||
@@ -171,12 +174,18 @@ static int fu540_ipi_init(bool cold_boot)
|
||||
return clint_warm_ipi_init();
|
||||
}
|
||||
|
||||
static u64 fu540_get_tlbr_flush_limit(void)
|
||||
{
|
||||
return FU540_TLB_RANGE_FLUSH_LIMIT;
|
||||
}
|
||||
|
||||
static int fu540_timer_init(bool cold_boot)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (cold_boot) {
|
||||
rc = clint_cold_timer_init(FU540_CLINT_ADDR, FU540_HART_COUNT);
|
||||
rc = clint_cold_timer_init(FU540_CLINT_ADDR,
|
||||
FU540_HART_COUNT, TRUE);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
@@ -201,6 +210,7 @@ const struct sbi_platform_operations platform_ops = {
|
||||
.ipi_send = clint_ipi_send,
|
||||
.ipi_clear = clint_ipi_clear,
|
||||
.ipi_init = fu540_ipi_init,
|
||||
.get_tlbr_flush_limit = fu540_get_tlbr_flush_limit,
|
||||
.timer_value = clint_timer_value,
|
||||
.timer_event_stop = clint_timer_event_stop,
|
||||
.timer_event_start = clint_timer_event_start,
|
||||
|
@@ -1,10 +1,7 @@
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
#
|
||||
# Authors:
|
||||
# Anup Patel <anup.patel@wdc.com>
|
||||
# Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
#
|
||||
|
||||
# Compiler flags
|
||||
@@ -14,27 +11,26 @@ platform-asflags-y =
|
||||
platform-ldflags-y =
|
||||
|
||||
# Command for platform specific "make run"
|
||||
platform-runcmd = qemu-system-riscv$(PLATFORM_RISCV_XLEN) -M sifive_u -m 256M \
|
||||
-nographic -kernel $(build_dir)/platform/qemu/sifive_u/firmware/fw_payload.elf
|
||||
platform-runcmd = spike \
|
||||
$(build_dir)/platform/spike/firmware/fw_payload.elf
|
||||
|
||||
# Blobs to build
|
||||
FW_TEXT_START=0x80000000
|
||||
FW_DYNAMIC=y
|
||||
FW_JUMP=y
|
||||
ifeq ($(PLATFORM_RISCV_XLEN), 32)
|
||||
# This needs to be 4MB alligned for 32-bit system
|
||||
# This needs to be 4MB aligned for 32-bit system
|
||||
FW_JUMP_ADDR=0x80400000
|
||||
else
|
||||
# This needs to be 2MB alligned for 64-bit system
|
||||
# This needs to be 2MB aligned for 64-bit system
|
||||
FW_JUMP_ADDR=0x80200000
|
||||
endif
|
||||
FW_JUMP_FDT_ADDR=0x82200000
|
||||
FW_PAYLOAD=y
|
||||
ifeq ($(PLATFORM_RISCV_XLEN), 32)
|
||||
# This needs to be 4MB alligned for 32-bit system
|
||||
# This needs to be 4MB aligned for 32-bit system
|
||||
FW_PAYLOAD_OFFSET=0x400000
|
||||
else
|
||||
# This needs to be 2MB alligned for 64-bit system
|
||||
# This needs to be 2MB aligned for 64-bit system
|
||||
FW_PAYLOAD_OFFSET=0x200000
|
||||
endif
|
||||
FW_PAYLOAD_FDT_ADDR=0x82200000
|
7
platform/spike/objects.mk
Normal file
7
platform/spike/objects.mk
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
#
|
||||
|
||||
platform-objs-y += platform.o
|
115
platform/spike/platform.c
Normal file
115
platform/spike/platform.c
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*/
|
||||
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi_utils/sys/htif.h>
|
||||
#include <sbi_utils/sys/clint.h>
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#define SPIKE_HART_COUNT 8
|
||||
#define SPIKE_HART_STACK_SIZE 8192
|
||||
|
||||
#define SPIKE_CLINT_ADDR 0x2000000
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
static int spike_final_init(bool cold_boot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 spike_pmp_region_count(u32 hartid)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int spike_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 spike_console_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int spike_irqchip_init(bool cold_boot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int spike_ipi_init(bool cold_boot)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (cold_boot) {
|
||||
ret = clint_cold_ipi_init(SPIKE_CLINT_ADDR,
|
||||
SPIKE_HART_COUNT);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return clint_warm_ipi_init();
|
||||
}
|
||||
|
||||
static int spike_timer_init(bool cold_boot)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (cold_boot) {
|
||||
rc = clint_cold_timer_init(SPIKE_CLINT_ADDR,
|
||||
SPIKE_HART_COUNT, TRUE);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return clint_warm_timer_init();
|
||||
}
|
||||
|
||||
const struct sbi_platform_operations platform_ops = {
|
||||
.pmp_region_count = spike_pmp_region_count,
|
||||
.pmp_region_info = spike_pmp_region_info,
|
||||
.final_init = spike_final_init,
|
||||
.console_putc = htif_putc,
|
||||
.console_getc = htif_getc,
|
||||
.console_init = spike_console_init,
|
||||
.irqchip_init = spike_irqchip_init,
|
||||
.ipi_send = clint_ipi_send,
|
||||
.ipi_clear = clint_ipi_clear,
|
||||
.ipi_init = spike_ipi_init,
|
||||
.timer_value = clint_timer_value,
|
||||
.timer_event_stop = clint_timer_event_stop,
|
||||
.timer_event_start = clint_timer_event_start,
|
||||
.timer_init = spike_timer_init,
|
||||
.system_reboot = htif_system_down,
|
||||
.system_shutdown = htif_system_down
|
||||
};
|
||||
|
||||
const struct sbi_platform platform = {
|
||||
.opensbi_version = OPENSBI_VERSION,
|
||||
.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
|
||||
.name = "Spike",
|
||||
.features = SBI_PLATFORM_DEFAULT_FEATURES,
|
||||
.hart_count = SPIKE_HART_COUNT,
|
||||
.hart_stack_size = SPIKE_HART_STACK_SIZE,
|
||||
.disabled_hart_mask = 0,
|
||||
.platform_ops_addr = (unsigned long)&platform_ops
|
||||
};
|
@@ -143,7 +143,7 @@ static int platform_timer_init(bool cold_boot)
|
||||
/* Example if the generic CLINT driver is used */
|
||||
if (cold_boot) {
|
||||
ret = clint_cold_timer_init(PLATFORM_CLINT_ADDR,
|
||||
PLATFORM_HART_COUNT);
|
||||
PLATFORM_HART_COUNT, TRUE);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@@ -213,8 +213,8 @@ const struct sbi_platform_operations platform_ops = {
|
||||
.timer_event_stop = platform_timer_event_stop,
|
||||
.timer_event_start = platform_timer_event_start,
|
||||
.timer_init = platform_timer_init,
|
||||
.system_reboot = platform_system_down,
|
||||
.system_shutdown = platform_system_down
|
||||
.system_reboot = platform_system_reboot,
|
||||
.system_shutdown = platform_system_shutdown
|
||||
};
|
||||
const struct sbi_platform platform = {
|
||||
.opensbi_version = OPENSBI_VERSION,
|
||||
@@ -224,6 +224,5 @@ const struct sbi_platform platform = {
|
||||
.hart_count = 1,
|
||||
.hart_stack_size = 4096,
|
||||
.disabled_hart_mask = 0,
|
||||
.tlb_range_flush_limit = 0,
|
||||
.platform_ops_addr = (unsigned long)&platform_ops
|
||||
};
|
||||
|
14
platform/thead/c910/config.mk
Normal file
14
platform/thead/c910/config.mk
Normal file
@@ -0,0 +1,14 @@
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
|
||||
# Compiler flags
|
||||
platform-cppflags-y =
|
||||
platform-cflags-y =
|
||||
platform-asflags-y =
|
||||
platform-ldflags-y =
|
||||
|
||||
# Blobs to build
|
||||
FW_TEXT_START?=0x0
|
||||
FW_JUMP=y
|
||||
FW_JUMP_ADDR?=0x00200000
|
5
platform/thead/c910/objects.mk
Normal file
5
platform/thead/c910/objects.mk
Normal file
@@ -0,0 +1,5 @@
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
|
||||
platform-objs-y += platform.o
|
158
platform/thead/c910/platform.c
Normal file
158
platform/thead/c910/platform.c
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include <sbi/riscv_io.h>
|
||||
#include <sbi/sbi_const.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi_utils/irqchip/plic.h>
|
||||
#include <sbi_utils/sys/clint.h>
|
||||
#include <sbi_utils/serial/uart8250.h>
|
||||
#include "platform.h"
|
||||
|
||||
static struct c910_regs_struct c910_regs;
|
||||
|
||||
static int c910_early_init(bool cold_boot)
|
||||
{
|
||||
if (cold_boot) {
|
||||
/* Load from boot core */
|
||||
c910_regs.pmpaddr0 = csr_read(CSR_PMPADDR0);
|
||||
c910_regs.pmpaddr1 = csr_read(CSR_PMPADDR1);
|
||||
c910_regs.pmpaddr2 = csr_read(CSR_PMPADDR2);
|
||||
c910_regs.pmpaddr3 = csr_read(CSR_PMPADDR3);
|
||||
c910_regs.pmpaddr4 = csr_read(CSR_PMPADDR4);
|
||||
c910_regs.pmpaddr5 = csr_read(CSR_PMPADDR5);
|
||||
c910_regs.pmpaddr6 = csr_read(CSR_PMPADDR6);
|
||||
c910_regs.pmpaddr7 = csr_read(CSR_PMPADDR7);
|
||||
c910_regs.pmpcfg0 = csr_read(CSR_PMPCFG0);
|
||||
|
||||
c910_regs.mcor = csr_read(CSR_MCOR);
|
||||
c910_regs.mhcr = csr_read(CSR_MHCR);
|
||||
c910_regs.mccr2 = csr_read(CSR_MCCR2);
|
||||
c910_regs.mhint = csr_read(CSR_MHINT);
|
||||
c910_regs.mxstatus = csr_read(CSR_MXSTATUS);
|
||||
|
||||
c910_regs.plic_base_addr = csr_read(CSR_PLIC_BASE);
|
||||
c910_regs.clint_base_addr =
|
||||
c910_regs.plic_base_addr + C910_PLIC_CLINT_OFFSET;
|
||||
} else {
|
||||
/* Store to other core */
|
||||
csr_write(CSR_PMPADDR0, c910_regs.pmpaddr0);
|
||||
csr_write(CSR_PMPADDR1, c910_regs.pmpaddr1);
|
||||
csr_write(CSR_PMPADDR2, c910_regs.pmpaddr2);
|
||||
csr_write(CSR_PMPADDR3, c910_regs.pmpaddr3);
|
||||
csr_write(CSR_PMPADDR4, c910_regs.pmpaddr4);
|
||||
csr_write(CSR_PMPADDR5, c910_regs.pmpaddr5);
|
||||
csr_write(CSR_PMPADDR6, c910_regs.pmpaddr6);
|
||||
csr_write(CSR_PMPADDR7, c910_regs.pmpaddr7);
|
||||
csr_write(CSR_PMPCFG0, c910_regs.pmpcfg0);
|
||||
|
||||
csr_write(CSR_MCOR, c910_regs.mcor);
|
||||
csr_write(CSR_MHCR, c910_regs.mhcr);
|
||||
csr_write(CSR_MHINT, c910_regs.mhint);
|
||||
csr_write(CSR_MXSTATUS, c910_regs.mxstatus);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int c910_final_init(bool cold_boot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int c910_irqchip_init(bool cold_boot)
|
||||
{
|
||||
/* Delegate plic enable into S-mode */
|
||||
writel(C910_PLIC_DELEG_ENABLE,
|
||||
(void *)c910_regs.plic_base_addr + C910_PLIC_DELEG_OFFSET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int c910_ipi_init(bool cold_boot)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (cold_boot) {
|
||||
rc = clint_cold_ipi_init(c910_regs.clint_base_addr, C910_HART_COUNT);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return clint_warm_ipi_init();
|
||||
}
|
||||
|
||||
static int c910_timer_init(bool cold_boot)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (cold_boot) {
|
||||
ret = clint_cold_timer_init(c910_regs.clint_base_addr,
|
||||
C910_HART_COUNT, FALSE);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return clint_warm_timer_init();
|
||||
}
|
||||
|
||||
static int c910_system_shutdown(u32 type)
|
||||
{
|
||||
asm volatile ("ebreak");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sbi_boot_other_core(int hartid)
|
||||
{
|
||||
csr_write(CSR_MRVBR, FW_TEXT_START);
|
||||
csr_write(CSR_MRMR, csr_read(CSR_MRMR) | (1 << hartid));
|
||||
}
|
||||
|
||||
static int c910_vendor_ext_provider(long extid, long funcid,
|
||||
unsigned long *args,
|
||||
unsigned long *out_value,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
switch (extid) {
|
||||
case SBI_EXT_VENDOR_C910_BOOT_OTHER_CORE:
|
||||
sbi_boot_other_core((int)args[0]);
|
||||
break;
|
||||
default:
|
||||
sbi_printf("Unsupported private sbi call: %ld\n", extid);
|
||||
asm volatile ("ebreak");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct sbi_platform_operations platform_ops = {
|
||||
.early_init = c910_early_init,
|
||||
.final_init = c910_final_init,
|
||||
|
||||
.irqchip_init = c910_irqchip_init,
|
||||
|
||||
.ipi_init = c910_ipi_init,
|
||||
.ipi_send = clint_ipi_send,
|
||||
.ipi_clear = clint_ipi_clear,
|
||||
|
||||
.timer_init = c910_timer_init,
|
||||
.timer_event_start = clint_timer_event_start,
|
||||
|
||||
.system_shutdown = c910_system_shutdown,
|
||||
|
||||
.vendor_ext_provider = c910_vendor_ext_provider,
|
||||
};
|
||||
|
||||
const struct sbi_platform platform = {
|
||||
.opensbi_version = OPENSBI_VERSION,
|
||||
.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
|
||||
.name = "T-HEAD Xuantie c910",
|
||||
.features = SBI_THEAD_FEATURES,
|
||||
.hart_count = C910_HART_COUNT,
|
||||
.hart_stack_size = C910_HART_STACK_SIZE,
|
||||
.disabled_hart_mask = 0,
|
||||
.platform_ops_addr = (unsigned long)&platform_ops
|
||||
};
|
50
platform/thead/c910/platform.h
Normal file
50
platform/thead/c910/platform.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#ifndef _C910_PLATFORM_H_
|
||||
#define _C910_PLATFORM_H_
|
||||
|
||||
#define C910_HART_COUNT 16
|
||||
#define C910_HART_STACK_SIZE 8192
|
||||
|
||||
#define SBI_THEAD_FEATURES \
|
||||
(SBI_PLATFORM_HAS_SCOUNTEREN | \
|
||||
SBI_PLATFORM_HAS_MCOUNTEREN | \
|
||||
SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
|
||||
|
||||
#define CSR_MCOR 0x7c2
|
||||
#define CSR_MHCR 0x7c1
|
||||
#define CSR_MCCR2 0x7c3
|
||||
#define CSR_MHINT 0x7c5
|
||||
#define CSR_MXSTATUS 0x7c0
|
||||
#define CSR_PLIC_BASE 0xfc1
|
||||
#define CSR_MRMR 0x7c6
|
||||
#define CSR_MRVBR 0x7c7
|
||||
|
||||
#define SBI_EXT_VENDOR_C910_BOOT_OTHER_CORE 0x09000003
|
||||
|
||||
#define C910_PLIC_CLINT_OFFSET 0x04000000 /* 64M */
|
||||
#define C910_PLIC_DELEG_OFFSET 0x001ffffc
|
||||
#define C910_PLIC_DELEG_ENABLE 0x1
|
||||
|
||||
struct c910_regs_struct {
|
||||
u64 pmpaddr0;
|
||||
u64 pmpaddr1;
|
||||
u64 pmpaddr2;
|
||||
u64 pmpaddr3;
|
||||
u64 pmpaddr4;
|
||||
u64 pmpaddr5;
|
||||
u64 pmpaddr6;
|
||||
u64 pmpaddr7;
|
||||
u64 pmpcfg0;
|
||||
u64 mcor;
|
||||
u64 mhcr;
|
||||
u64 mccr2;
|
||||
u64 mhint;
|
||||
u64 mxstatus;
|
||||
u64 plic_base_addr;
|
||||
u64 clint_base_addr;
|
||||
};
|
||||
|
||||
#endif /* _C910_PLATFORM_H_ */
|
@@ -85,16 +85,16 @@ case "${BUILD_RISCV_XLEN}" in
|
||||
32)
|
||||
# Setup 32-bit platform list
|
||||
BUILD_PLATFORM_SUBDIR=("qemu/virt")
|
||||
BUILD_PLATFORM_SUBDIR+=("qemu/sifive_u")
|
||||
;;
|
||||
64)
|
||||
# Setup 64-bit platform list
|
||||
BUILD_PLATFORM_SUBDIR=("qemu/virt")
|
||||
BUILD_PLATFORM_SUBDIR+=("qemu/sifive_u")
|
||||
BUILD_PLATFORM_SUBDIR+=("sifive/fu540")
|
||||
BUILD_PLATFORM_SUBDIR+=("kendryte/k210")
|
||||
BUILD_PLATFORM_SUBDIR+=("ariane-fpga")
|
||||
BUILD_PLATFORM_SUBDIR+=("andes/ae350")
|
||||
BUILD_PLATFORM_SUBDIR+=("thead/c910")
|
||||
BUILD_PLATFORM_SUBDIR+=("spike")
|
||||
;;
|
||||
*)
|
||||
echo "Invalid RISC-V XLEN"
|
||||
|
Reference in New Issue
Block a user