mirror of
https://github.com/riscv-software-src/opensbi.git
synced 2025-08-24 23:41:23 +01:00
Compare commits
91 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
234ed8e427 | ||
![]() |
da5293f742 | ||
![]() |
1bbf36183e | ||
![]() |
386eba21bf | ||
![]() |
e884416650 | ||
![]() |
db56341dfa | ||
![]() |
0d49c3bc18 | ||
![]() |
12394a269b | ||
![]() |
b7df5e4392 | ||
![]() |
80bc5065bb | ||
![]() |
7dcb1e1753 | ||
![]() |
a029bd90c6 | ||
![]() |
6fc1986f50 | ||
![]() |
7baccfca79 | ||
![]() |
2179777364 | ||
![]() |
e7da0b4204 | ||
![]() |
4fffb53269 | ||
![]() |
ba741ea0ad | ||
![]() |
c0d2baa8c0 | ||
![]() |
9b65dcaedd | ||
![]() |
555e73778a | ||
![]() |
62ea4f4e2a | ||
![]() |
c1f6d89678 | ||
![]() |
c709d40a67 | ||
![]() |
4e370224df | ||
![]() |
3d921fad0d | ||
![]() |
8d2edc4fc9 | ||
![]() |
2677324f90 | ||
![]() |
548d03e577 | ||
![]() |
5c429ae213 | ||
![]() |
da074796df | ||
![]() |
c4acc60a46 | ||
![]() |
54a7734d86 | ||
![]() |
781cafdbee | ||
![]() |
48616b3de2 | ||
![]() |
914f81fbee | ||
![]() |
a809f406b9 | ||
![]() |
bf21632860 | ||
![]() |
74c0ea1e83 | ||
![]() |
fdf5d5c322 | ||
![]() |
c347408a39 | ||
![]() |
c10c30b485 | ||
![]() |
e856462ac2 | ||
![]() |
5fd99dbdaa | ||
![]() |
5edbb7cda1 | ||
![]() |
3e200370ee | ||
![]() |
530e95bd63 | ||
![]() |
3a30d2c34d | ||
![]() |
e73b92d862 | ||
![]() |
b1678af210 | ||
![]() |
8b650050ec | ||
![]() |
f81d6f6f43 | ||
![]() |
a126886bfa | ||
![]() |
a12d46a5e7 | ||
![]() |
dbeeacb878 | ||
![]() |
a0f2d4a10c | ||
![]() |
e9a4bfb7b5 | ||
![]() |
9c07c513aa | ||
![]() |
6ca096977d | ||
![]() |
af4b50f896 | ||
![]() |
a04c46506a | ||
![]() |
79bf80b44e | ||
![]() |
7701ea13be | ||
![]() |
aaeca7eb4e | ||
![]() |
172fa1601c | ||
![]() |
9f935a4a43 | ||
![]() |
7ccf6bf54c | ||
![]() |
6734304f8c | ||
![]() |
c1c7c3ee9e | ||
![]() |
bef63d6848 | ||
![]() |
dcb10c0056 | ||
![]() |
ebc8ebc0f8 | ||
![]() |
162d453b49 | ||
![]() |
2c341f7844 | ||
![]() |
74d1db7062 | ||
![]() |
7b0b289887 | ||
![]() |
4f3bad6e43 | ||
![]() |
e435ba0524 | ||
![]() |
d7f87d99a3 | ||
![]() |
9d56961b23 | ||
![]() |
4b18a2acc2 | ||
![]() |
937caee083 | ||
![]() |
2cfd2fc904 | ||
![]() |
2845d2d2cf | ||
![]() |
8e47649eff | ||
![]() |
ec1abf6657 | ||
![]() |
a5f9104330 | ||
![]() |
7d61a68775 | ||
![]() |
ec3e5b14d5 | ||
![]() |
78afe11ba2 | ||
![]() |
35bc810252 |
45
Makefile
45
Makefile
@@ -94,6 +94,8 @@ DTC = dtc
|
||||
|
||||
# Guess the compillers xlen
|
||||
OPENSBI_CC_XLEN := $(shell TMP=`$(CC) -dumpmachine | sed 's/riscv\([0-9][0-9]\).*/\1/'`; echo $${TMP})
|
||||
OPENSBI_CC_ABI := $(shell TMP=`$(CC) -v 2>&1 | sed -n 's/.*\(with\-abi=\([a-zA-Z0-9]*\)\).*/\2/p'`; echo $${TMP})
|
||||
OPENSBI_CC_ISA := $(shell TMP=`$(CC) -v 2>&1 | sed -n 's/.*\(with\-arch=\([a-zA-Z0-9]*\)\).*/\2/p'`; echo $${TMP})
|
||||
|
||||
# Setup platform XLEN
|
||||
ifndef PLATFORM_RISCV_XLEN
|
||||
@@ -143,14 +145,22 @@ deps-y+=$(firmware-objs-path-y:.o=.dep)
|
||||
|
||||
# Setup platform ABI, ISA and Code Model
|
||||
ifndef PLATFORM_RISCV_ABI
|
||||
ifeq ($(PLATFORM_RISCV_XLEN), 32)
|
||||
PLATFORM_RISCV_ABI = ilp$(PLATFORM_RISCV_XLEN)
|
||||
ifneq ($(PLATFORM_RISCV_TOOLCHAIN_DEFAULT), 1)
|
||||
ifeq ($(PLATFORM_RISCV_XLEN), 32)
|
||||
PLATFORM_RISCV_ABI = ilp$(PLATFORM_RISCV_XLEN)
|
||||
else
|
||||
PLATFORM_RISCV_ABI = lp$(PLATFORM_RISCV_XLEN)
|
||||
endif
|
||||
else
|
||||
PLATFORM_RISCV_ABI = lp$(PLATFORM_RISCV_XLEN)
|
||||
PLATFORM_RISCV_ABI = $(OPENSBI_CC_ABI)
|
||||
endif
|
||||
endif
|
||||
ifndef PLATFORM_RISCV_ISA
|
||||
PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc
|
||||
ifneq ($(PLATFORM_RISCV_TOOLCHAIN_DEFAULT), 1)
|
||||
PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc
|
||||
else
|
||||
PLATFORM_RISCV_ISA = $(OPENSBI_CC_ISA)
|
||||
endif
|
||||
endif
|
||||
ifndef PLATFORM_RISCV_CODE_MODEL
|
||||
PLATFORM_RISCV_CODE_MODEL = medany
|
||||
@@ -291,7 +301,10 @@ compile_dts = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
||||
$(CPP) $(DTSCPPFLAGS) $(2) | $(DTC) -O dtb -i `dirname $(2)` -o $(1)
|
||||
compile_d2c = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
||||
echo " D2C $(subst $(build_dir)/,,$(1))"; \
|
||||
$(src_dir)/scripts/d2c.sh -i $(4) -a $(3) -p $(2) > $(1)
|
||||
$(if $($(2)-varalign-$(3)),$(eval D2C_ALIGN_BYTES := $($(2)-varalign-$(3))),$(eval D2C_ALIGN_BYTES := $(4))) \
|
||||
$(if $($(2)-varprefix-$(3)),$(eval D2C_NAME_PREFIX := $($(2)-varprefix-$(3))),$(eval D2C_NAME_PREFIX := $(5))) \
|
||||
$(if $($(2)-padding-$(3)),$(eval D2C_PADDING_BYTES := $($(2)-padding-$(3))),$(eval D2C_PADDING_BYTES := 0)) \
|
||||
$(src_dir)/scripts/d2c.sh -i $(6) -a $(D2C_ALIGN_BYTES) -p $(D2C_NAME_PREFIX) -t $(D2C_PADDING_BYTES) > $(1)
|
||||
compile_gen_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
||||
echo " GEN-DEP $(subst $(build_dir)/,,$(1))"; \
|
||||
echo "$(1:.dep=$(2)): $(3)" >> $(1)
|
||||
@@ -310,15 +323,6 @@ all: $(targets-y)
|
||||
# Preserve all intermediate files
|
||||
.SECONDARY:
|
||||
|
||||
$(build_dir)/%.bin: $(build_dir)/%.elf
|
||||
$(call compile_objcopy,$@,$<)
|
||||
|
||||
$(build_dir)/%.elf: $(build_dir)/%.o $(build_dir)/%.elf.ld $(platform_build_dir)/lib/libplatsbi.a
|
||||
$(call compile_elf,$@,$@.ld,$< $(platform_build_dir)/lib/libplatsbi.a)
|
||||
|
||||
$(platform_build_dir)/%.ld: $(src_dir)/%.ldS
|
||||
$(call compile_cpp,$@,$<)
|
||||
|
||||
$(build_dir)/lib/libsbi.a: $(libsbi-objs-path-y)
|
||||
$(call compile_ar,$@,$^)
|
||||
|
||||
@@ -340,6 +344,15 @@ $(build_dir)/%.dep: $(src_dir)/%.S
|
||||
$(build_dir)/%.o: $(src_dir)/%.S
|
||||
$(call compile_as,$@,$<)
|
||||
|
||||
$(platform_build_dir)/%.bin: $(platform_build_dir)/%.elf
|
||||
$(call compile_objcopy,$@,$<)
|
||||
|
||||
$(platform_build_dir)/%.elf: $(platform_build_dir)/%.o $(platform_build_dir)/%.elf.ld $(platform_build_dir)/lib/libplatsbi.a
|
||||
$(call compile_elf,$@,$@.ld,$< $(platform_build_dir)/lib/libplatsbi.a)
|
||||
|
||||
$(platform_build_dir)/%.ld: $(src_dir)/%.ldS
|
||||
$(call compile_cpp,$@,$<)
|
||||
|
||||
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.c
|
||||
$(call compile_cc_dep,$@,$<)
|
||||
|
||||
@@ -361,7 +374,7 @@ $(platform_build_dir)/%.dep: $(platform_src_dir)/%.dts
|
||||
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
|
||||
|
||||
$(platform_build_dir)/%.c: $(platform_build_dir)/%.dtb
|
||||
$(call compile_d2c,$@,$(platform-varprefix-$(subst .dtb,.o,$(subst /,-,$(subst $(platform_build_dir)/,,$<)))),16,$<)
|
||||
$(call compile_d2c,$@,platform,$(subst .dtb,.o,$(subst /,-,$(subst $(platform_build_dir)/,,$<))),16,dt,$<)
|
||||
|
||||
$(platform_build_dir)/%.dtb: $(platform_src_dir)/%.dts
|
||||
$(call compile_dts,$@,$<)
|
||||
@@ -461,6 +474,8 @@ clean:
|
||||
$(CMD_PREFIX)find $(build_dir) -type f -name "*.elf" -exec rm -rf {} +
|
||||
$(if $(V), @echo " RM $(build_dir)/*.bin")
|
||||
$(CMD_PREFIX)find $(build_dir) -type f -name "*.bin" -exec rm -rf {} +
|
||||
$(if $(V), @echo " RM $(build_dir)/*.dtb")
|
||||
$(CMD_PREFIX)find $(build_dir) -type f -name "*.dtb" -exec rm -rf {} +
|
||||
|
||||
# Rule for "make distclean"
|
||||
.PHONY: distclean
|
||||
|
11
README.md
11
README.md
@@ -45,7 +45,7 @@ between:
|
||||
executing in VS-mode.
|
||||
|
||||
The *RISC-V SBI specification* is maintained as an independent project by the
|
||||
RISC-V Foundation on [Github] (https://github.com/riscv/riscv-sbi-doc).
|
||||
RISC-V Foundation on [Github].
|
||||
|
||||
The goal of the OpenSBI project is to provide an open-source reference
|
||||
implementation of the RISC-V SBI specifications for platform-specific firmwares
|
||||
@@ -69,7 +69,7 @@ platform-dependent hardware manipulation functions. For all supported platforms,
|
||||
OpenSBI also provides several runtime firmware examples built using the platform
|
||||
*libplatsbi.a*. These example firmwares can be used to replace the legacy
|
||||
*riscv-pk* bootloader (aka BBL) and enable the use of well-known bootloaders
|
||||
such as [U-Boot] (https://git.denx.de/u-boot.git).
|
||||
such as [U-Boot].
|
||||
|
||||
Supported SBI version
|
||||
---------------------
|
||||
@@ -97,8 +97,7 @@ Required Toolchain
|
||||
|
||||
OpenSBI can be compiled natively or cross-compiled on a x86 host. For
|
||||
cross-compilation, you can build your own toolchain or just download
|
||||
a prebuilt one from the
|
||||
[Bootlin toolchain repository] (https://toolchains.bootlin.com/).
|
||||
a prebuilt one from the [Bootlin toolchain repository].
|
||||
|
||||
Please note that only a 64-bit version of the toolchain is available in
|
||||
the Bootlin toolchain repository for now.
|
||||
@@ -226,6 +225,8 @@ Detailed documentation of various aspects of OpenSBI can be found under the
|
||||
* [Platform Documentation]: Documentation of the platforms currently supported.
|
||||
* [Firmware Documentation]: Documentation for the different types of firmware
|
||||
examples build supported by OpenSBI.
|
||||
* [Domain Support]: Documentation for the OpenSBI domain support which helps
|
||||
users achieve system-level partitioning using OpenSBI.
|
||||
|
||||
OpenSBI source code is also well documented. For source level documentation,
|
||||
doxygen style is used. Please refer to the [Doxygen manual] for details on this
|
||||
@@ -269,6 +270,7 @@ make I=<install_directory> install_docs
|
||||
|
||||
[Github]: https://github.com/riscv/riscv-sbi-doc
|
||||
[U-Boot]: https://www.denx.de/wiki/U-Boot/SourceCode
|
||||
[Bootlin toolchain repository]: https://toolchains.bootlin.com/
|
||||
[COPYING.BSD]: COPYING.BSD
|
||||
[SPDX]: http://spdx.org/licenses/
|
||||
[Contribution Guideline]: docs/contributing.md
|
||||
@@ -278,6 +280,7 @@ make I=<install_directory> install_docs
|
||||
[Platform Support Guide]: docs/platform_guide.md
|
||||
[Platform Documentation]: docs/platform/platform.md
|
||||
[Firmware Documentation]: docs/firmware/fw.md
|
||||
[Domain Support]: docs/domain_support.md
|
||||
[Doxygen manual]: http://www.doxygen.nl/manual/index.html
|
||||
[Kendryte standalone SDK]: https://github.com/kendryte/kendryte-standalone-sdk
|
||||
[third party notices]: ThirdPartyNotices.md
|
||||
|
314
docs/domain_support.md
Normal file
314
docs/domain_support.md
Normal file
@@ -0,0 +1,314 @@
|
||||
OpenSBI Domain Support
|
||||
======================
|
||||
|
||||
An OpenSBI domain is a system-level partition (subset) of underlying hardware
|
||||
having it's own memory regions (RAM and MMIO devices) and HARTs. The OpenSBI
|
||||
will try to achieve secure isolation between domains using RISC-V platform
|
||||
features such as PMP, ePMP, IOPMP, SiFive Shield, etc.
|
||||
|
||||
Important entities which help implement OpenSBI domain support are:
|
||||
|
||||
* **struct sbi_domain_memregion** - Representation of a domain memory region
|
||||
* **struct sbi_hartmask** - Representation of domain HART set
|
||||
* **struct sbi_domain** - Representation of a domain instance
|
||||
|
||||
Each HART of a RISC-V platform must have an OpenSBI domain assigned to it.
|
||||
The OpenSBI platform support is responsible for populating domains and
|
||||
providing HART id to domain mapping. The OpenSBI domain support will by
|
||||
default assign **the ROOT domain** to all HARTs of a RISC-V platform so
|
||||
it is not mandatory for the OpenSBI platform support to populate domains.
|
||||
|
||||
Domain Memory Region
|
||||
--------------------
|
||||
|
||||
A domain memory region is represented by **struct sbi_domain_memregion** in
|
||||
OpenSBI and has following details:
|
||||
|
||||
* **order** - The size of a memory region is **2 ^ order** where **order**
|
||||
must be **3 <= order <= __riscv_xlen**
|
||||
* **base** - The base address of a memory region is **2 ^ order**
|
||||
aligned start address
|
||||
* **flags** - The flags of a memory region represent memory type (i.e.
|
||||
RAM or MMIO) and allowed accesses (i.e. READ, WRITE, EXECUTE, etc)
|
||||
|
||||
Domain Instance
|
||||
---------------
|
||||
|
||||
A domain instance is represented by **struct sbi_domain** in OpenSBI and
|
||||
has following details:
|
||||
|
||||
* **index** - Logical index of this domain
|
||||
* **name** - Name of this domain
|
||||
* **assigned_harts** - HARTs assigned to this domain
|
||||
* **possible_harts** - HARTs possible in this domain
|
||||
* **regions** - Array of memory regions terminated by a memory region
|
||||
with order zero
|
||||
* **boot_hartid** - HART id of the HART booting this domain. The domain
|
||||
boot HART will be started at boot-time if boot HART is possible and
|
||||
assigned for this domain.
|
||||
* **next_addr** - Address of the next booting stage for this domain
|
||||
* **next_arg1** - Arg1 (or 'a1' register) of the next booting stage for
|
||||
this domain
|
||||
* **next_mode** - Privilege mode of the next booting stage for this
|
||||
domain. This can be either S-mode or U-mode.
|
||||
* **system_reset_allowed** - Is domain allowed to reset the system?
|
||||
|
||||
The memory regions represented by **regions** in **struct sbi_domain** have
|
||||
following additional constraints to align with RISC-V PMP requirements:
|
||||
|
||||
* A memory region to protect OpenSBI firmware from S-mode and U-mode
|
||||
should always be present
|
||||
* For two overlapping memory regions, one should be sub-region of another
|
||||
* Two overlapping memory regions should not be of same size
|
||||
* Two overlapping memory regions cannot have same flags
|
||||
* Memory access checks on overlapping address should prefer smallest
|
||||
overlapping memory region flags.
|
||||
|
||||
ROOT Domain
|
||||
-----------
|
||||
|
||||
**The ROOT domain** is the default OpenSBI domain which is assigned by
|
||||
default to all HARTs of a RISC-V platform. The OpenSBI domain support
|
||||
will hand-craft **the ROOT domain** very early at boot-time in the
|
||||
following manner:
|
||||
|
||||
* **index** - Logical index of the ROOT domain is always zero
|
||||
* **name** - Name of the ROOT domain is "root"
|
||||
* **assigned_harts** - At boot-time all valid HARTs of a RISC-V platform
|
||||
are assigned the ROOT domain which changes later based on OpenSBI
|
||||
platform support
|
||||
* **possible_harts** - All valid HARTs of a RISC-V platform are possible
|
||||
HARTs of the ROOT domain
|
||||
* **regions** - Two memory regions available to the ROOT domain:
|
||||
**A)** A memory region to protect OpenSBI firmware from S-mode and U-mode
|
||||
**B)** A memory region of **order=__riscv_xlen** allowing S-mode and
|
||||
U-mode access to full memory address space
|
||||
* **boot_hartid** - Coldboot HART is the HART booting the ROOT domain
|
||||
* **next_addr** - Next booting stage address in coldboot HART scratch
|
||||
space is the next address for the ROOT domain
|
||||
* **next_arg1** - Next booting stage arg1 in coldboot HART scratch space
|
||||
is the next arg1 for the ROOT domain
|
||||
* **next_mode** - Next booting stage mode in coldboot HART scratch space
|
||||
is the next mode for the ROOT domain
|
||||
* **system_reset_allowed** - The ROOT domain is allowed to reset the system
|
||||
|
||||
Domain Effects
|
||||
--------------
|
||||
|
||||
Few noteworthy effects of a system partitioned into domains are as follows:
|
||||
|
||||
* At any point in time, a HART is running in exactly one OpenSBI domain context
|
||||
* The SBI IPI and RFENCE calls from HART A are restricted to the HARTs in
|
||||
domain assigned to HART A
|
||||
* The SBI HSM calls which try to change/read state of HART B from HART A will
|
||||
only work if both HART A and HART B are assigned same domain
|
||||
* A HART running in S-mode or U-mode can only access memory based on the
|
||||
memory regions of the domain assigned to the HART
|
||||
|
||||
Domain Device Tree Bindings
|
||||
---------------------------
|
||||
|
||||
The OpenSBI domains can be described in the **device tree (DT) blob** (or
|
||||
flattened device tree) passed to the OpenSBI firmwares by the previous
|
||||
booting stage. This allows OpenSBI platform support to parse and populate
|
||||
OpenSBI domains from the device tree blob (or flattened device tree).
|
||||
|
||||
### Domain Configuration Node
|
||||
|
||||
All OpenSBI domain description related DT nodes should be under the domain
|
||||
configuration DT node. The **/chosen** DT node is the preferred parent of
|
||||
the domain configuration DT node.
|
||||
|
||||
The DT properties of a domain configuration DT node are as follows:
|
||||
|
||||
* **compatible** (Mandatory) - The compatible string of the domain
|
||||
configuration. This DT property should have value *"opensbi,domain,config"*
|
||||
|
||||
### Domain Memory Region Node
|
||||
|
||||
The domain memory region DT node describes details of a memory region and
|
||||
can be pointed by multiple domain instance DT nodes. The access permissions
|
||||
of the memory region are specified separately in domain instance node.
|
||||
|
||||
The DT properties of a domain memory region DT node are as follows:
|
||||
|
||||
* **compatible** (Mandatory) - The compatible string of the domain memory
|
||||
region. This DT property should have value *"opensbi,domain,memregion"*
|
||||
* **base** (Mandatory) - The base address of the domain memory region. This
|
||||
DT property should have a **2 ^ order** aligned 64 bit address (i.e. two
|
||||
DT cells).
|
||||
* **order** (Mandatory) - The order of the domain memory region. This DT
|
||||
property should have a 32 bit value (i.e. one DT cell) in the range
|
||||
**3 <= order <= __riscv_xlen**.
|
||||
* **mmio** (Optional) - A boolean flag representing whether the domain
|
||||
memory region is a memory-mapped I/O (MMIO) region.
|
||||
* **devices** (Optional) - The list of device DT node phandles for devices
|
||||
which fall under this domain memory region.
|
||||
|
||||
### Domain Instance Node
|
||||
|
||||
The domain instance DT node describes set of possible HARTs, set of memory
|
||||
regions, and other details of a domain instance.
|
||||
|
||||
The DT properties of a domain instance DT node are as follows:
|
||||
|
||||
* **compatible** (Mandatory) - The compatible string of the domain instance.
|
||||
This DT property should have value *"opensbi,domain,instance"*
|
||||
* **possible-harts** (Optional) - The list of CPU DT node phandles for the
|
||||
the domain instance. This list represents the possible HARTs of the
|
||||
domain instance.
|
||||
* **regions** (Optional) - The list of domain memory region DT node phandle
|
||||
and access permissions for the domain instance. Each list entry is a pair
|
||||
of DT node phandle and access permissions. The access permissions are
|
||||
represented as a 32bit bitmask having bits: **readable** (BIT[0]),
|
||||
**writeable** (BIT[1]), **executable** (BIT[2]), and **m-mode** (BIT[3]).
|
||||
* **boot-hart** (Optional) - The DT node phandle of the HART booting the
|
||||
domain instance. If coldboot HART is assigned to the domain instance then
|
||||
this DT property is ignored and the coldboot HART is assumed to be the
|
||||
boot HART of the domain instance.
|
||||
* **next-arg1** (Optional) - The 64 bit next booting stage arg1 for the
|
||||
domain instance. If this DT property is not available and coldboot HART
|
||||
is not assigned to the domain instance then **0x0** is used as default
|
||||
value. If this DT property is not available and coldboot HART is assigned
|
||||
to the domain instance then **next booting stage arg1 of coldboot HART**
|
||||
is used as default value.
|
||||
* **next-addr** (Optional) - The 64 bit next booting stage address for the
|
||||
domain instance. If this DT property is not available and coldboot HART
|
||||
is not assigned to the domain instance then **0x0** is used as default
|
||||
value. If this DT property is not available and coldboot HART is assigned
|
||||
to the domain instance then **next booting stage address of coldboot HART**
|
||||
is used as default value.
|
||||
* **next-mode** (Optional) - The 32 bit next booting stage mode for the
|
||||
domain instance. The possible values of this DT property are: **0x1**
|
||||
(s-mode), and **0x0** (u-mode). If this DT property is not available
|
||||
and coldboot HART is not assigned to the domain instance then **0x1**
|
||||
is used as default value. If this DT property is not available and
|
||||
coldboot HART is assigned to the domain instance then **next booting
|
||||
stage mode of coldboot HART** is used as default value.
|
||||
* **system-reset-allowed** (Optional) - A boolean flag representing
|
||||
whether the domain instance is allowed to do system reset.
|
||||
|
||||
### Assigning HART To Domain Instance
|
||||
|
||||
By default, all HARTs are assigned to **the ROOT domain**. The OpenSBI
|
||||
platform support can provide the HART to domain instance assignment using
|
||||
platform specific callback.
|
||||
|
||||
The HART to domain instance assignment can be parsed from the device tree
|
||||
using optional DT property **opensbi,domain** in each CPU DT node. The
|
||||
value of DT property **opensbi,domain** is the DT phandle of the domain
|
||||
instance DT node. If **opensbi,domain** DT property is not specified then
|
||||
corresponding HART is assigned to **the ROOT domain**.
|
||||
|
||||
### Domain Configuration Only Accessible to OpenSBI
|
||||
|
||||
The software running inside a domain instance should only be aware of
|
||||
devices and hardware resources accessible to itself.
|
||||
|
||||
To hide domain configuration from domain instances, the following should
|
||||
be done:
|
||||
|
||||
* The previous booting stage should preferably provide a separate device
|
||||
tree for each domain instance and mention location of device tree in
|
||||
respective domain instance DT nodes using **next-arg1** DT property.
|
||||
* If domain assigned to a HART does not have separate device tree then
|
||||
OpenSBI platform support should remove all domain configuration details
|
||||
from the device tree passed by previous booting stage before passing it
|
||||
to the next booting stage.
|
||||
|
||||
### Example
|
||||
|
||||
```
|
||||
chosen {
|
||||
opensbi-domains {
|
||||
compatible = "opensbi,domain,config";
|
||||
|
||||
tmem: tmem {
|
||||
compatible = "opensbi,domain,memregion";
|
||||
base = <0x0 0x80100000>;
|
||||
order = <20>;
|
||||
};
|
||||
|
||||
tuart: tuart {
|
||||
compatible = "opensbi,domain,memregion";
|
||||
base = <0x0 0x10011000>;
|
||||
order = <12>;
|
||||
mmio;
|
||||
devices = <&uart1>;
|
||||
};
|
||||
|
||||
allmem: allmem {
|
||||
compatible = "opensbi,domain,memregion";
|
||||
base = <0x0 0x0>;
|
||||
order = <64>;
|
||||
};
|
||||
|
||||
tdomain: trusted-domain {
|
||||
compatible = "opensbi,domain,instance";
|
||||
possible-harts = <&cpu0>;
|
||||
regions = <&tmem 0x7>, <&tuart 0x7>;
|
||||
boot-hart = <&cpu0>;
|
||||
next-arg1 = <0x0 0x0>;
|
||||
next-addr = <0x0 0x80100000>;
|
||||
next-mode = <0x0>;
|
||||
system-reset-allowed;
|
||||
};
|
||||
|
||||
udomain: untrusted-domain {
|
||||
compatible = "opensbi,domain,instance";
|
||||
possible-harts = <&cpu1 &cpu2 &cpu3 &cpu4>;
|
||||
regions = <&tmem 0x0>, <&tuart 0x0>, <&allmem 0x7>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
timebase-frequency = <10000000>;
|
||||
|
||||
cpu0: cpu@0 {
|
||||
device_type = "cpu";
|
||||
reg = <0x00>;
|
||||
compatible = "riscv";
|
||||
opensbi-domain = <&tdomain>;
|
||||
...
|
||||
};
|
||||
|
||||
cpu1: cpu@1 {
|
||||
device_type = "cpu";
|
||||
reg = <0x01>;
|
||||
compatible = "riscv";
|
||||
opensbi-domain = <&udomain>;
|
||||
...
|
||||
};
|
||||
|
||||
cpu2: cpu@2 {
|
||||
device_type = "cpu";
|
||||
reg = <0x02>;
|
||||
compatible = "riscv";
|
||||
opensbi-domain = <&udomain>;
|
||||
...
|
||||
};
|
||||
|
||||
cpu3: cpu@3 {
|
||||
device_type = "cpu";
|
||||
reg = <0x03>;
|
||||
compatible = "riscv";
|
||||
opensbi-domain = <&udomain>;
|
||||
...
|
||||
};
|
||||
|
||||
cpu4: cpu@4 {
|
||||
device_type = "cpu";
|
||||
reg = <0x04>;
|
||||
compatible = "riscv";
|
||||
opensbi-domain = <&udomain>;
|
||||
...
|
||||
};
|
||||
};
|
||||
|
||||
uart1: serial@10011000 {
|
||||
...
|
||||
};
|
||||
```
|
@@ -795,6 +795,7 @@ INPUT = @@SRC_DIR@@/README.md \
|
||||
@@SRC_DIR@@/docs/platform_guide.md \
|
||||
@@SRC_DIR@@/docs/platform_requirements.md \
|
||||
@@SRC_DIR@@/docs/library_usage.md \
|
||||
@@SRC_DIR@@/docs/domain_support.md \
|
||||
@@SRC_DIR@@/docs/firmware \
|
||||
@@SRC_DIR@@/docs/platform \
|
||||
@@SRC_DIR@@/include \
|
||||
|
@@ -51,11 +51,17 @@ case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree in the
|
||||
Firmware Configuration and Compilation
|
||||
--------------------------------------
|
||||
|
||||
All firmware types mandate the definition of the following compile time
|
||||
configuration parameter.
|
||||
All firmware types support the following common compile time configuration
|
||||
parameters:
|
||||
|
||||
* **FW_TEXT_ADDR** - Defines the address at which the previous booting stage
|
||||
loads OpenSBI firmware.
|
||||
* **FW_TEXT_ADDR** - Defines the execution address of the OpenSBI firmware.
|
||||
This configuration parameter is mandatory.
|
||||
* **FW_FDT_PATH** - Path to an external flattened device tree binary file to
|
||||
be embedded in the *.rodata* section of the final firmware. If this option
|
||||
is not provided then the firmware will expect the FDT to be passed as an
|
||||
argument by the prior booting stage.
|
||||
* **FW_FDT_PADDING** - Optional zero bytes padding to the embedded flattened
|
||||
device tree binary file specified by **FW_FDT_PATH** option.
|
||||
|
||||
Additionally, each firmware type as a set of type specific configuration
|
||||
parameters. Detailed information for each firmware type can be found in the
|
||||
|
@@ -55,14 +55,9 @@ file. The parameters currently defined are as follows:
|
||||
automatically generated and used as a payload. This test payload executes
|
||||
an infinite `while (1)` loop after printing a message on the platform console.
|
||||
|
||||
* **FW_PAYLOAD_FDT_PATH** - Path to an external flattened device tree binary
|
||||
file to be embedded in the *.text* section of the final firmware. If this
|
||||
option is not provided then the firmware will expect the FDT to be passed
|
||||
as an argument by the prior booting stage.
|
||||
|
||||
* **FW_PAYLOAD_FDT_ADDR** - Address where the FDT passed by the prior booting
|
||||
stage or specified by the *FW_PAYLOAD_FDT_PATH* parameter and embedded in
|
||||
the *.text* section will be placed before executing the next booting stage,
|
||||
stage or specified by the *FW_FDT_PATH* parameter and embedded in the
|
||||
*.rodata* section will be placed before executing the next booting stage,
|
||||
that is, the payload firmware. If this option is not provided, then the
|
||||
firmware will pass the FDT address passed by the previous booting stage
|
||||
to the next booting stage.
|
||||
|
@@ -19,12 +19,12 @@ Building Andes AE350 Platform
|
||||
-----------------------------
|
||||
|
||||
To use Linux v5.2 should be used to build Andes AE350 OpenSBI binaries by using
|
||||
the compile time option FW_PAYLOAD_FDT_PATH.
|
||||
the compile time option FW_FDT_PATH.
|
||||
|
||||
AE350's dts is included in https://github.com/andestech/linux/tree/ast-v3_2_0-release-public
|
||||
|
||||
**Linux Kernel Payload**
|
||||
|
||||
```
|
||||
make PLATFORM=andes/ae350 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_PAYLOAD_FDT_PATH=<ae350.dtb path>
|
||||
make PLATFORM=andes/ae350 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<ae350.dtb path>
|
||||
```
|
||||
|
@@ -28,7 +28,7 @@ make PLATFORM=generic
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv64 -M virt -m 256M -nographic \
|
||||
-kernel build/platform/generic/firmware/fw_payload.bin
|
||||
-bios build/platform/generic/firmware/fw_payload.bin
|
||||
```
|
||||
|
||||
**U-Boot Payload**
|
||||
@@ -44,7 +44,7 @@ make PLATFORM=generic FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv64 -M virt -m 256M -nographic \
|
||||
-kernel build/platform/generic/firmware/fw_payload.elf
|
||||
-bios build/platform/generic/firmware/fw_payload.elf
|
||||
```
|
||||
or
|
||||
```
|
||||
@@ -66,7 +66,7 @@ make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Im
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv64 -M virt -m 256M -nographic \
|
||||
-kernel build/platform/generic/firmware/fw_payload.elf \
|
||||
-bios build/platform/generic/firmware/fw_payload.elf \
|
||||
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
|
||||
-device virtio-blk-device,drive=hd0 \
|
||||
-append "root=/dev/vda rw console=ttyS0"
|
||||
@@ -95,7 +95,7 @@ make PLATFORM=generic PLATFORM_RISCV_XLEN=32
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv32 -M virt -m 256M -nographic \
|
||||
-kernel build/platform/generic/firmware/fw_payload.bin
|
||||
-bios build/platform/generic/firmware/fw_payload.bin
|
||||
```
|
||||
|
||||
**U-Boot Payload**
|
||||
@@ -111,7 +111,7 @@ make PLATFORM=generic PLATFORM_RISCV_XLEN=32 FW_PAYLOAD_PATH=<uboot_build_direct
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv32 -M virt -m 256M -nographic \
|
||||
-kernel build/platform/generic/firmware/fw_payload.elf
|
||||
-bios build/platform/generic/firmware/fw_payload.elf
|
||||
```
|
||||
or
|
||||
```
|
||||
@@ -133,7 +133,7 @@ make PLATFORM=generic PLATFORM_RISCV_XLEN=32 FW_PAYLOAD_PATH=<linux_build_direct
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv32 -M virt -m 256M -nographic \
|
||||
-kernel build/platform/generic/firmware/fw_payload.elf \
|
||||
-bios build/platform/generic/firmware/fw_payload.elf \
|
||||
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
|
||||
-device virtio-blk-device,drive=hd0 \
|
||||
-append "root=/dev/vda rw console=ttyS0"
|
||||
|
@@ -23,11 +23,11 @@ Building Shakti C-class Platform
|
||||
**Linux Kernel Payload**
|
||||
|
||||
```
|
||||
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_PAYLOAD_FDT_PATH=<shakti.dtb path>
|
||||
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<shakti.dtb path>
|
||||
```
|
||||
|
||||
**Test Payload**
|
||||
|
||||
```
|
||||
make PLATFORM=generic FW_PAYLOAD_FDT_PATH=<shakti.dtb path>
|
||||
make PLATFORM=generic FW_FDT_PATH=<shakti.dtb path>
|
||||
```
|
||||
|
@@ -27,27 +27,28 @@ U-Boot v2020.01 (or higher) should be used.
|
||||
The HiFive Unleashed device tree(DT) is merged in Linux v5.2 release. This
|
||||
DT (device tree) is not backward compatible with the DT passed from FSBL.
|
||||
|
||||
To use Linux v5.2 (or higher, the pre-built DTB (DT binary) from Linux v5.2
|
||||
To use Linux v5.2 (or higher), the pre-built DTB (DT binary) from Linux v5.2
|
||||
(or higher) should be used to build SiFive FU540 OpenSBI binaries by using
|
||||
the compile time option *FW_PAYLOAD_FDT_PATH*.
|
||||
the compile time option *FW_FDT_PATH*.
|
||||
|
||||
```
|
||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
||||
or
|
||||
(For Linux v5.2 or higher)
|
||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_PAYLOAD_FDT_PATH=<hifive-unleashed-a00.dtb path from Linux kernel>
|
||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<hifive-unleashed-a00.dtb path from Linux kernel>
|
||||
```
|
||||
|
||||
**U-Boot Payload**
|
||||
|
||||
The command-line example here assumes that U-Boot was compiled using the
|
||||
sifive_fu540_defconfig configuration and with U-Boot v2020.01 (or higher).
|
||||
|
||||
The detailed U-Boot booting guide is avaialble at [U-Boot].
|
||||
sifive_fu540_defconfig configuration and with U-Boot v2020.01, and up to
|
||||
v2020.07-rc3.
|
||||
|
||||
```
|
||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot-dtb.bin
|
||||
```
|
||||
For U-Boot v2020.07-rc4 or later releases, SPL support was added in U-Boot.
|
||||
Please refer to the detailed U-Boot booting guide available at [U-Boot].
|
||||
|
||||
Flashing the OpenSBI firmware binary to storage media:
|
||||
------------------------------------------------------
|
||||
@@ -146,7 +147,7 @@ booti ${kernel_addr_r} - ${fdt_addr_r}
|
||||
QEMU Specific Instructions
|
||||
--------------------------
|
||||
If you want to test OpenSBI with QEMU 'sifive_u' machine, please follow the
|
||||
same instructions above, with the exception of not passing FW_PAYLOAD_FDT_PATH.
|
||||
same instructions above, with the exception of not passing FW_FDT_PATH.
|
||||
|
||||
This is because QEMU generates a device tree blob on the fly based on the
|
||||
command line parameters and it's compatible with the one used in the upstream
|
||||
@@ -155,13 +156,37 @@ 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:
|
||||
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
|
||||
```
|
||||
|
||||
U-Boot v2020.07 release added SPL support to SiFive HiFive Unleashed board,
|
||||
hence a build error will be seen after you switch to **CONFIG_OF_PRIOR_STAGE**.
|
||||
|
||||
```
|
||||
./tools/mkimage: Can't open arch/riscv/dts/hifive-unleashed-a00.dtb: No such file or directory
|
||||
./tools/mkimage: failed to build FIT
|
||||
Makefile:1402: recipe for target 'u-boot.img' failed
|
||||
make: *** [u-boot.img] Error 1
|
||||
```
|
||||
|
||||
The above errors can be safely ignored as we don't run U-Boot SPL under QEMU.
|
||||
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv64 -M sifive_u -m 256M -nographic \
|
||||
-bios build/platform/sifive/fu540/firmware/fw_payload.bin
|
||||
```
|
||||
or
|
||||
```
|
||||
qemu-system-riscv64 -M sifive_u -m 256M -nographic \
|
||||
-bios build/platform/sifive/fu540/firmware/fw_jump.bin \
|
||||
-kernel <uboot_build_dir>/u-boot.bin
|
||||
```
|
||||
|
||||
While the real hardware operates at the 64-bit mode, it's possible for QEMU to
|
||||
test the 32-bit OpenSBI firmware. This can be helpful for testing 32-bit SiFive
|
||||
specific drivers.
|
||||
|
@@ -59,7 +59,7 @@ make PLATFORM=generic
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv64 -M spike -m 256M -nographic \
|
||||
-kernel build/platform/generic/firmware/fw_payload.elf
|
||||
-bios build/platform/generic/firmware/fw_payload.elf
|
||||
```
|
||||
|
||||
**Linux Kernel Payload**
|
||||
@@ -75,7 +75,7 @@ make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Im
|
||||
Run:
|
||||
```
|
||||
qemu-system-riscv64 -M spike -m 256M -nographic \
|
||||
-kernel build/platform/generic/firmware/fw_payload.elf \
|
||||
-bios build/platform/generic/firmware/fw_payload.elf \
|
||||
-initrd <path_to_cpio_ramdisk> \
|
||||
-append "root=/dev/ram rw console=hvc0 earlycon=sbi"
|
||||
```
|
||||
|
@@ -7,5 +7,8 @@
|
||||
# Anup Patel <anup.patel@wdc.com>
|
||||
#
|
||||
|
||||
$(platform_build_dir)/firmware/fw_dynamic.o: $(FW_FDT_PATH)
|
||||
$(platform_build_dir)/firmware/fw_jump.o: $(FW_FDT_PATH)
|
||||
$(platform_build_dir)/firmware/fw_payload.o: $(FW_FDT_PATH)
|
||||
|
||||
$(platform_build_dir)/firmware/fw_payload.o: $(FW_PAYLOAD_PATH_FINAL)
|
||||
$(platform_build_dir)/firmware/fw_payload.o: $(FW_PAYLOAD_FDT_PATH)
|
||||
|
@@ -182,14 +182,10 @@ _bss_zero:
|
||||
call fw_save_info
|
||||
MOV_5R a0, s0, a1, s1, a2, s2, a3, s3, a4, s4
|
||||
|
||||
#ifdef FW_FDT_PATH
|
||||
/* Override previous arg1 */
|
||||
MOV_3R s0, a0, s1, a1, s2, a2
|
||||
call fw_prev_arg1
|
||||
add t1, a0, zero
|
||||
MOV_3R a0, s0, a1, s1, a2, s2
|
||||
beqz t1, _prev_arg1_override_done
|
||||
add a1, t1, zero
|
||||
_prev_arg1_override_done:
|
||||
la a1, fw_fdt_bin
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialize platform
|
||||
@@ -265,6 +261,9 @@ _scratch_init:
|
||||
/* Store hartid-to-scratch function address in scratch space */
|
||||
la a4, _hartid_to_scratch
|
||||
REG_S a4, SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET(tp)
|
||||
/* Store trap-exit function address in scratch space */
|
||||
la a4, _trap_exit
|
||||
REG_S a4, SBI_SCRATCH_TRAP_EXIT_OFFSET(tp)
|
||||
/* Clear tmp0 in scratch space */
|
||||
REG_S zero, SBI_SCRATCH_TMP0_OFFSET(tp)
|
||||
/* Store firmware options in scratch space */
|
||||
@@ -417,8 +416,28 @@ _start_warm:
|
||||
|
||||
/* Setup trap handler */
|
||||
la a4, _trap_handler
|
||||
#if __riscv_xlen == 32
|
||||
csrr a5, CSR_MISA
|
||||
srli a5, a5, ('H' - 'A')
|
||||
andi a5, a5, 0x1
|
||||
beq a5, zero, _skip_trap_handler_rv32_hyp
|
||||
la a4, _trap_handler_rv32_hyp
|
||||
_skip_trap_handler_rv32_hyp:
|
||||
#endif
|
||||
csrw CSR_MTVEC, a4
|
||||
|
||||
#if __riscv_xlen == 32
|
||||
/* Override trap exit for H-extension */
|
||||
csrr a5, CSR_MISA
|
||||
srli a5, a5, ('H' - 'A')
|
||||
andi a5, a5, 0x1
|
||||
beq a5, zero, _skip_trap_exit_rv32_hyp
|
||||
la a4, _trap_exit_rv32_hyp
|
||||
csrr a5, CSR_MSCRATCH
|
||||
REG_S a4, SBI_SCRATCH_TRAP_EXIT_OFFSET(a5)
|
||||
_skip_trap_exit_rv32_hyp:
|
||||
#endif
|
||||
|
||||
/* Initialize SBI runtime */
|
||||
csrr a0, CSR_MSCRATCH
|
||||
call sbi_init
|
||||
@@ -480,45 +499,37 @@ fw_platform_init:
|
||||
add a0, a1, zero
|
||||
ret
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _trap_handler
|
||||
_trap_handler:
|
||||
.macro TRAP_SAVE_AND_SETUP_SP_T0
|
||||
/* Swap TP and MSCRATCH */
|
||||
csrrw tp, CSR_MSCRATCH, tp
|
||||
|
||||
/* Save T0 in scratch space */
|
||||
REG_S t0, SBI_SCRATCH_TMP0_OFFSET(tp)
|
||||
|
||||
/* Check which mode we came from */
|
||||
/*
|
||||
* Set T0 to appropriate exception stack
|
||||
*
|
||||
* Came_From_M_Mode = ((MSTATUS.MPP < PRV_M) ? 1 : 0) - 1;
|
||||
* Exception_Stack = TP ^ (Came_From_M_Mode & (SP ^ TP))
|
||||
*
|
||||
* Came_From_M_Mode = 0 ==> Exception_Stack = TP
|
||||
* Came_From_M_Mode = -1 ==> Exception_Stack = SP
|
||||
*/
|
||||
csrr t0, CSR_MSTATUS
|
||||
srl t0, t0, MSTATUS_MPP_SHIFT
|
||||
and t0, t0, PRV_M
|
||||
xori t0, t0, PRV_M
|
||||
beq t0, zero, _trap_handler_m_mode
|
||||
slti t0, t0, PRV_M
|
||||
add t0, t0, -1
|
||||
xor sp, sp, tp
|
||||
and t0, t0, sp
|
||||
xor sp, sp, tp
|
||||
xor t0, tp, t0
|
||||
|
||||
/* We came from S-mode or U-mode */
|
||||
_trap_handler_s_mode:
|
||||
/* Set T0 to original SP */
|
||||
add t0, sp, zero
|
||||
/* Save original SP on exception stack */
|
||||
REG_S sp, (SBI_TRAP_REGS_OFFSET(sp) - SBI_TRAP_REGS_SIZE)(t0)
|
||||
|
||||
/* Setup exception stack */
|
||||
add sp, tp, -(SBI_TRAP_REGS_SIZE)
|
||||
|
||||
/* Jump to code common for all modes */
|
||||
j _trap_handler_all_mode
|
||||
|
||||
/* We came from M-mode */
|
||||
_trap_handler_m_mode:
|
||||
/* Set T0 to original SP */
|
||||
add t0, sp, zero
|
||||
|
||||
/* Re-use current SP as exception stack */
|
||||
add sp, sp, -(SBI_TRAP_REGS_SIZE)
|
||||
|
||||
_trap_handler_all_mode:
|
||||
/* Save original SP (from T0) on stack */
|
||||
REG_S t0, SBI_TRAP_REGS_OFFSET(sp)(sp)
|
||||
/* Set SP to exception stack and make room for trap registers */
|
||||
add sp, t0, -(SBI_TRAP_REGS_SIZE)
|
||||
|
||||
/* Restore T0 from scratch space */
|
||||
REG_L t0, SBI_SCRATCH_TMP0_OFFSET(tp)
|
||||
@@ -528,23 +539,23 @@ _trap_handler_all_mode:
|
||||
|
||||
/* Swap TP and MSCRATCH */
|
||||
csrrw tp, CSR_MSCRATCH, tp
|
||||
.endm
|
||||
|
||||
.macro TRAP_SAVE_MEPC_MSTATUS have_mstatush
|
||||
/* Save MEPC and MSTATUS CSRs */
|
||||
csrr t0, CSR_MEPC
|
||||
REG_S t0, SBI_TRAP_REGS_OFFSET(mepc)(sp)
|
||||
csrr t0, CSR_MSTATUS
|
||||
REG_S t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
|
||||
REG_S zero, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
|
||||
#if __riscv_xlen == 32
|
||||
csrr t0, CSR_MISA
|
||||
srli t0, t0, ('H' - 'A')
|
||||
andi t0, t0, 0x1
|
||||
beq t0, zero, _skip_mstatush_save
|
||||
.if \have_mstatush
|
||||
csrr t0, CSR_MSTATUSH
|
||||
REG_S t0, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
|
||||
_skip_mstatush_save:
|
||||
#endif
|
||||
.else
|
||||
REG_S zero, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
|
||||
.endif
|
||||
.endm
|
||||
|
||||
.macro TRAP_SAVE_GENERAL_REGS_EXCEPT_SP_T0
|
||||
/* Save all general regisers except SP and T0 */
|
||||
REG_S zero, SBI_TRAP_REGS_OFFSET(zero)(sp)
|
||||
REG_S ra, SBI_TRAP_REGS_OFFSET(ra)(sp)
|
||||
@@ -576,11 +587,15 @@ _skip_mstatush_save:
|
||||
REG_S t4, SBI_TRAP_REGS_OFFSET(t4)(sp)
|
||||
REG_S t5, SBI_TRAP_REGS_OFFSET(t5)(sp)
|
||||
REG_S t6, SBI_TRAP_REGS_OFFSET(t6)(sp)
|
||||
.endm
|
||||
|
||||
.macro TRAP_CALL_C_ROUTINE
|
||||
/* Call C routine */
|
||||
add a0, sp, zero
|
||||
call sbi_trap_handler
|
||||
.endm
|
||||
|
||||
.macro TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
|
||||
/* Restore all general regisers except SP and T0 */
|
||||
REG_L ra, SBI_TRAP_REGS_OFFSET(ra)(sp)
|
||||
REG_L gp, SBI_TRAP_REGS_OFFSET(gp)(sp)
|
||||
@@ -611,30 +626,98 @@ _skip_mstatush_save:
|
||||
REG_L t4, SBI_TRAP_REGS_OFFSET(t4)(sp)
|
||||
REG_L t5, SBI_TRAP_REGS_OFFSET(t5)(sp)
|
||||
REG_L t6, SBI_TRAP_REGS_OFFSET(t6)(sp)
|
||||
.endm
|
||||
|
||||
.macro TRAP_RESTORE_MEPC_MSTATUS have_mstatush
|
||||
/* Restore MEPC and MSTATUS CSRs */
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(mepc)(sp)
|
||||
csrw CSR_MEPC, t0
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
|
||||
csrw CSR_MSTATUS, t0
|
||||
#if __riscv_xlen == 32
|
||||
csrr t0, CSR_MISA
|
||||
srli t0, t0, ('H' - 'A')
|
||||
andi t0, t0, 0x1
|
||||
beq t0, zero, _skip_mstatush_restore
|
||||
.if \have_mstatush
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
|
||||
csrw CSR_MSTATUSH, t0
|
||||
_skip_mstatush_restore:
|
||||
#endif
|
||||
.endif
|
||||
.endm
|
||||
|
||||
.macro TRAP_RESTORE_SP_T0
|
||||
/* Restore T0 */
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(t0)(sp)
|
||||
|
||||
/* Restore SP */
|
||||
REG_L sp, SBI_TRAP_REGS_OFFSET(sp)(sp)
|
||||
.endm
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _trap_handler
|
||||
_trap_handler:
|
||||
TRAP_SAVE_AND_SETUP_SP_T0
|
||||
|
||||
TRAP_SAVE_MEPC_MSTATUS 0
|
||||
|
||||
TRAP_SAVE_GENERAL_REGS_EXCEPT_SP_T0
|
||||
|
||||
TRAP_CALL_C_ROUTINE
|
||||
|
||||
TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
|
||||
|
||||
TRAP_RESTORE_MEPC_MSTATUS 0
|
||||
|
||||
TRAP_RESTORE_SP_T0
|
||||
|
||||
mret
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _trap_exit
|
||||
_trap_exit:
|
||||
add sp, a0, zero
|
||||
|
||||
TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
|
||||
|
||||
TRAP_RESTORE_MEPC_MSTATUS 0
|
||||
|
||||
TRAP_RESTORE_SP_T0
|
||||
|
||||
mret
|
||||
|
||||
#if __riscv_xlen == 32
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _trap_handler_rv32_hyp
|
||||
_trap_handler_rv32_hyp:
|
||||
TRAP_SAVE_AND_SETUP_SP_T0
|
||||
|
||||
TRAP_SAVE_MEPC_MSTATUS 1
|
||||
|
||||
TRAP_SAVE_GENERAL_REGS_EXCEPT_SP_T0
|
||||
|
||||
TRAP_CALL_C_ROUTINE
|
||||
|
||||
TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
|
||||
|
||||
TRAP_RESTORE_MEPC_MSTATUS 1
|
||||
|
||||
TRAP_RESTORE_SP_T0
|
||||
|
||||
mret
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _trap_exit_rv32_hyp
|
||||
_trap_exit_rv32_hyp:
|
||||
add sp, a0, zero
|
||||
|
||||
TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
|
||||
|
||||
TRAP_RESTORE_MEPC_MSTATUS 1
|
||||
|
||||
TRAP_RESTORE_SP_T0
|
||||
|
||||
mret
|
||||
#endif
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _reset_regs
|
||||
@@ -673,3 +756,14 @@ _reset_regs:
|
||||
csrw CSR_MSCRATCH, 0
|
||||
|
||||
ret
|
||||
|
||||
#ifdef FW_FDT_PATH
|
||||
.section .rodata
|
||||
.align 4
|
||||
.globl fw_fdt_bin
|
||||
fw_fdt_bin:
|
||||
.incbin FW_FDT_PATH
|
||||
#ifdef FW_FDT_PADDING
|
||||
.fill FW_FDT_PADDING, 1, 0
|
||||
#endif
|
||||
#endif
|
||||
|
@@ -86,19 +86,6 @@ fw_save_info:
|
||||
2:
|
||||
ret
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_prev_arg1
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
* The a0, a1, and a2 registers will be same as passed by
|
||||
* previous booting stage.
|
||||
* The previous arg1 should be returned in 'a0'.
|
||||
*/
|
||||
fw_prev_arg1:
|
||||
add a0, zero, zero
|
||||
ret
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_arg1
|
||||
|
@@ -34,19 +34,6 @@ fw_boot_hart:
|
||||
fw_save_info:
|
||||
ret
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_prev_arg1
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
* The a0, a1, and a2 registers will be same as passed by
|
||||
* previous booting stage.
|
||||
* The previous arg1 should be returned in 'a0'.
|
||||
*/
|
||||
fw_prev_arg1:
|
||||
add a0, zero, zero
|
||||
ret
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_arg1
|
||||
|
@@ -34,23 +34,6 @@ fw_boot_hart:
|
||||
fw_save_info:
|
||||
ret
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_prev_arg1
|
||||
/*
|
||||
* We can only use a0, a1, and a2 registers here.
|
||||
* The a0, a1, and a2 registers will be same as passed by
|
||||
* previous booting stage.
|
||||
* The previous arg1 should be returned in 'a0'.
|
||||
*/
|
||||
fw_prev_arg1:
|
||||
#ifdef FW_PAYLOAD_FDT_PATH
|
||||
la a0, fdt_bin
|
||||
#else
|
||||
add a0, zero, zero
|
||||
#endif
|
||||
ret
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.global fw_next_arg1
|
||||
@@ -102,14 +85,6 @@ fw_options:
|
||||
add a0, zero, zero
|
||||
ret
|
||||
|
||||
#ifdef FW_PAYLOAD_FDT_PATH
|
||||
.section .text, "ax", %progbits
|
||||
.align 4
|
||||
.globl fdt_bin
|
||||
fdt_bin:
|
||||
.incbin FW_PAYLOAD_FDT_PATH
|
||||
#endif
|
||||
|
||||
.section .payload, "ax", %progbits
|
||||
.align 4
|
||||
.globl payload_bin
|
||||
|
@@ -17,6 +17,13 @@ ifdef FW_TEXT_START
|
||||
firmware-genflags-y += -DFW_TEXT_START=$(FW_TEXT_START)
|
||||
endif
|
||||
|
||||
ifdef FW_FDT_PATH
|
||||
firmware-genflags-y += -DFW_FDT_PATH=\"$(FW_FDT_PATH)\"
|
||||
ifdef FW_FDT_PADDING
|
||||
firmware-genflags-y += -DFW_FDT_PADDING=$(FW_FDT_PADDING)
|
||||
endif
|
||||
endif
|
||||
|
||||
firmware-bins-$(FW_DYNAMIC) += fw_dynamic.bin
|
||||
|
||||
firmware-bins-$(FW_JUMP) += fw_jump.bin
|
||||
@@ -41,9 +48,6 @@ ifdef FW_PAYLOAD_ALIGN
|
||||
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_ALIGN=$(FW_PAYLOAD_ALIGN)
|
||||
endif
|
||||
|
||||
ifdef FW_PAYLOAD_FDT_PATH
|
||||
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_FDT_PATH=\"$(FW_PAYLOAD_FDT_PATH)\"
|
||||
endif
|
||||
ifdef FW_PAYLOAD_FDT_ADDR
|
||||
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_FDT_ADDR=$(FW_PAYLOAD_FDT_ADDR)
|
||||
endif
|
||||
|
@@ -180,7 +180,7 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
|
||||
unsigned long log2len);
|
||||
|
||||
int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
|
||||
unsigned long *size);
|
||||
unsigned long *log2len);
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
|
@@ -144,7 +144,12 @@
|
||||
#define PMP_L _UL(0x80)
|
||||
|
||||
#define PMP_SHIFT 2
|
||||
#define PMP_COUNT 16
|
||||
#define PMP_COUNT 64
|
||||
#if __riscv_xlen == 64
|
||||
#define PMP_ADDR_MASK ((_ULL(0x1) << 54) - 1)
|
||||
#else
|
||||
#define PMP_ADDR_MASK _UL(0xFFFFFFFF)
|
||||
#endif
|
||||
|
||||
#if __riscv_xlen == 64
|
||||
#define MSTATUS_SD MSTATUS64_SD
|
||||
@@ -166,18 +171,27 @@
|
||||
#define HGATP_MODE_SHIFT HGATP32_MODE_SHIFT
|
||||
#endif
|
||||
|
||||
#define CSR_USTATUS 0x0
|
||||
#define CSR_FFLAGS 0x1
|
||||
#define CSR_FRM 0x2
|
||||
#define CSR_FCSR 0x3
|
||||
/* ===== User-level CSRs ===== */
|
||||
|
||||
/* User Trap Setup (N-extension) */
|
||||
#define CSR_USTATUS 0x000
|
||||
#define CSR_UIE 0x004
|
||||
#define CSR_UTVEC 0x005
|
||||
|
||||
/* User Trap Handling (N-extension) */
|
||||
#define CSR_USCRATCH 0x040
|
||||
#define CSR_UEPC 0x041
|
||||
#define CSR_UCAUSE 0x042
|
||||
#define CSR_UTVAL 0x043
|
||||
#define CSR_UIP 0x044
|
||||
|
||||
/* User Floating-point CSRs */
|
||||
#define CSR_FFLAGS 0x001
|
||||
#define CSR_FRM 0x002
|
||||
#define CSR_FCSR 0x003
|
||||
|
||||
/* User Counters/Timers */
|
||||
#define CSR_CYCLE 0xc00
|
||||
#define CSR_UIE 0x4
|
||||
#define CSR_UTVEC 0x5
|
||||
#define CSR_USCRATCH 0x40
|
||||
#define CSR_UEPC 0x41
|
||||
#define CSR_UCAUSE 0x42
|
||||
#define CSR_UTVAL 0x43
|
||||
#define CSR_UIP 0x44
|
||||
#define CSR_TIME 0xc01
|
||||
#define CSR_INSTRET 0xc02
|
||||
#define CSR_HPMCOUNTER3 0xc03
|
||||
@@ -209,148 +223,6 @@
|
||||
#define CSR_HPMCOUNTER29 0xc1d
|
||||
#define CSR_HPMCOUNTER30 0xc1e
|
||||
#define CSR_HPMCOUNTER31 0xc1f
|
||||
#define CSR_SSTATUS 0x100
|
||||
#define CSR_SIE 0x104
|
||||
#define CSR_STVEC 0x105
|
||||
#define CSR_SCOUNTEREN 0x106
|
||||
#define CSR_SSCRATCH 0x140
|
||||
#define CSR_SEPC 0x141
|
||||
#define CSR_SCAUSE 0x142
|
||||
#define CSR_STVAL 0x143
|
||||
#define CSR_SIP 0x144
|
||||
#define CSR_SATP 0x180
|
||||
|
||||
#define CSR_HSTATUS 0x600
|
||||
#define CSR_HEDELEG 0x602
|
||||
#define CSR_HIDELEG 0x603
|
||||
#define CSR_HIE 0x604
|
||||
#define CSR_HTIMEDELTA 0x605
|
||||
#define CSR_HTIMEDELTAH 0x615
|
||||
#define CSR_HCOUNTERNEN 0x606
|
||||
#define CSR_HGEIE 0x607
|
||||
#define CSR_HTVAL 0x643
|
||||
#define CSR_HIP 0x644
|
||||
#define CSR_HTINST 0x64a
|
||||
#define CSR_HGATP 0x680
|
||||
#define CSR_HGEIP 0xe07
|
||||
|
||||
#define CSR_VSSTATUS 0x200
|
||||
#define CSR_VSIE 0x204
|
||||
#define CSR_VSTVEC 0x205
|
||||
#define CSR_VSSCRATCH 0x240
|
||||
#define CSR_VSEPC 0x241
|
||||
#define CSR_VSCAUSE 0x242
|
||||
#define CSR_VSTVAL 0x243
|
||||
#define CSR_VSIP 0x244
|
||||
#define CSR_VSATP 0x280
|
||||
|
||||
#define CSR_MSTATUS 0x300
|
||||
#define CSR_MISA 0x301
|
||||
#define CSR_MEDELEG 0x302
|
||||
#define CSR_MIDELEG 0x303
|
||||
#define CSR_MIE 0x304
|
||||
#define CSR_MTVEC 0x305
|
||||
#define CSR_MCOUNTEREN 0x306
|
||||
#define CSR_MSTATUSH 0x310
|
||||
#define CSR_MSCRATCH 0x340
|
||||
#define CSR_MEPC 0x341
|
||||
#define CSR_MCAUSE 0x342
|
||||
#define CSR_MTVAL 0x343
|
||||
#define CSR_MIP 0x344
|
||||
#define CSR_MTINST 0x34a
|
||||
#define CSR_MTVAL2 0x34b
|
||||
#define CSR_PMPCFG0 0x3a0
|
||||
#define CSR_PMPCFG1 0x3a1
|
||||
#define CSR_PMPCFG2 0x3a2
|
||||
#define CSR_PMPCFG3 0x3a3
|
||||
#define CSR_PMPADDR0 0x3b0
|
||||
#define CSR_PMPADDR1 0x3b1
|
||||
#define CSR_PMPADDR2 0x3b2
|
||||
#define CSR_PMPADDR3 0x3b3
|
||||
#define CSR_PMPADDR4 0x3b4
|
||||
#define CSR_PMPADDR5 0x3b5
|
||||
#define CSR_PMPADDR6 0x3b6
|
||||
#define CSR_PMPADDR7 0x3b7
|
||||
#define CSR_PMPADDR8 0x3b8
|
||||
#define CSR_PMPADDR9 0x3b9
|
||||
#define CSR_PMPADDR10 0x3ba
|
||||
#define CSR_PMPADDR11 0x3bb
|
||||
#define CSR_PMPADDR12 0x3bc
|
||||
#define CSR_PMPADDR13 0x3bd
|
||||
#define CSR_PMPADDR14 0x3be
|
||||
#define CSR_PMPADDR15 0x3bf
|
||||
#define CSR_TSELECT 0x7a0
|
||||
#define CSR_TDATA1 0x7a1
|
||||
#define CSR_TDATA2 0x7a2
|
||||
#define CSR_TDATA3 0x7a3
|
||||
#define CSR_DCSR 0x7b0
|
||||
#define CSR_DPC 0x7b1
|
||||
#define CSR_DSCRATCH 0x7b2
|
||||
|
||||
#define CSR_MCYCLE 0xb00
|
||||
#define CSR_MINSTRET 0xb02
|
||||
#define CSR_MHPMCOUNTER3 0xb03
|
||||
#define CSR_MHPMCOUNTER4 0xb04
|
||||
#define CSR_MHPMCOUNTER5 0xb05
|
||||
#define CSR_MHPMCOUNTER6 0xb06
|
||||
#define CSR_MHPMCOUNTER7 0xb07
|
||||
#define CSR_MHPMCOUNTER8 0xb08
|
||||
#define CSR_MHPMCOUNTER9 0xb09
|
||||
#define CSR_MHPMCOUNTER10 0xb0a
|
||||
#define CSR_MHPMCOUNTER11 0xb0b
|
||||
#define CSR_MHPMCOUNTER12 0xb0c
|
||||
#define CSR_MHPMCOUNTER13 0xb0d
|
||||
#define CSR_MHPMCOUNTER14 0xb0e
|
||||
#define CSR_MHPMCOUNTER15 0xb0f
|
||||
#define CSR_MHPMCOUNTER16 0xb10
|
||||
#define CSR_MHPMCOUNTER17 0xb11
|
||||
#define CSR_MHPMCOUNTER18 0xb12
|
||||
#define CSR_MHPMCOUNTER19 0xb13
|
||||
#define CSR_MHPMCOUNTER20 0xb14
|
||||
#define CSR_MHPMCOUNTER21 0xb15
|
||||
#define CSR_MHPMCOUNTER22 0xb16
|
||||
#define CSR_MHPMCOUNTER23 0xb17
|
||||
#define CSR_MHPMCOUNTER24 0xb18
|
||||
#define CSR_MHPMCOUNTER25 0xb19
|
||||
#define CSR_MHPMCOUNTER26 0xb1a
|
||||
#define CSR_MHPMCOUNTER27 0xb1b
|
||||
#define CSR_MHPMCOUNTER28 0xb1c
|
||||
#define CSR_MHPMCOUNTER29 0xb1d
|
||||
#define CSR_MHPMCOUNTER30 0xb1e
|
||||
#define CSR_MHPMCOUNTER31 0xb1f
|
||||
#define CSR_MHPMEVENT3 0x323
|
||||
#define CSR_MHPMEVENT4 0x324
|
||||
#define CSR_MHPMEVENT5 0x325
|
||||
#define CSR_MHPMEVENT6 0x326
|
||||
#define CSR_MHPMEVENT7 0x327
|
||||
#define CSR_MHPMEVENT8 0x328
|
||||
#define CSR_MHPMEVENT9 0x329
|
||||
#define CSR_MHPMEVENT10 0x32a
|
||||
#define CSR_MHPMEVENT11 0x32b
|
||||
#define CSR_MHPMEVENT12 0x32c
|
||||
#define CSR_MHPMEVENT13 0x32d
|
||||
#define CSR_MHPMEVENT14 0x32e
|
||||
#define CSR_MHPMEVENT15 0x32f
|
||||
#define CSR_MHPMEVENT16 0x330
|
||||
#define CSR_MHPMEVENT17 0x331
|
||||
#define CSR_MHPMEVENT18 0x332
|
||||
#define CSR_MHPMEVENT19 0x333
|
||||
#define CSR_MHPMEVENT20 0x334
|
||||
#define CSR_MHPMEVENT21 0x335
|
||||
#define CSR_MHPMEVENT22 0x336
|
||||
#define CSR_MHPMEVENT23 0x337
|
||||
#define CSR_MHPMEVENT24 0x338
|
||||
#define CSR_MHPMEVENT25 0x339
|
||||
#define CSR_MHPMEVENT26 0x33a
|
||||
#define CSR_MHPMEVENT27 0x33b
|
||||
#define CSR_MHPMEVENT28 0x33c
|
||||
#define CSR_MHPMEVENT29 0x33d
|
||||
#define CSR_MHPMEVENT30 0x33e
|
||||
#define CSR_MHPMEVENT31 0x33f
|
||||
#define CSR_MVENDORID 0xf11
|
||||
#define CSR_MARCHID 0xf12
|
||||
#define CSR_MIMPID 0xf13
|
||||
#define CSR_MHARTID 0xf14
|
||||
#define CSR_CYCLEH 0xc80
|
||||
#define CSR_TIMEH 0xc81
|
||||
#define CSR_INSTRETH 0xc82
|
||||
@@ -383,6 +255,203 @@
|
||||
#define CSR_HPMCOUNTER29H 0xc9d
|
||||
#define CSR_HPMCOUNTER30H 0xc9e
|
||||
#define CSR_HPMCOUNTER31H 0xc9f
|
||||
|
||||
/* ===== Supervisor-level CSRs ===== */
|
||||
|
||||
/* Supervisor Trap Setup */
|
||||
#define CSR_SSTATUS 0x100
|
||||
#define CSR_SEDELEG 0x102
|
||||
#define CSR_SIDELEG 0x103
|
||||
#define CSR_SIE 0x104
|
||||
#define CSR_STVEC 0x105
|
||||
#define CSR_SCOUNTEREN 0x106
|
||||
|
||||
/* Supervisor Trap Handling */
|
||||
#define CSR_SSCRATCH 0x140
|
||||
#define CSR_SEPC 0x141
|
||||
#define CSR_SCAUSE 0x142
|
||||
#define CSR_STVAL 0x143
|
||||
#define CSR_SIP 0x144
|
||||
|
||||
/* Supervisor Protection and Translation */
|
||||
#define CSR_SATP 0x180
|
||||
|
||||
/* ===== Hypervisor-level CSRs ===== */
|
||||
|
||||
/* Hypervisor Trap Setup (H-extension) */
|
||||
#define CSR_HSTATUS 0x600
|
||||
#define CSR_HEDELEG 0x602
|
||||
#define CSR_HIDELEG 0x603
|
||||
#define CSR_HIE 0x604
|
||||
#define CSR_HCOUNTEREN 0x606
|
||||
#define CSR_HGEIE 0x607
|
||||
|
||||
/* Hypervisor Trap Handling (H-extension) */
|
||||
#define CSR_HTVAL 0x643
|
||||
#define CSR_HIP 0x644
|
||||
#define CSR_HVIP 0x645
|
||||
#define CSR_HTINST 0x64a
|
||||
#define CSR_HGEIP 0xe12
|
||||
|
||||
/* Hypervisor Protection and Translation (H-extension) */
|
||||
#define CSR_HGATP 0x680
|
||||
|
||||
/* Hypervisor Counter/Timer Virtualization Registers (H-extension) */
|
||||
#define CSR_HTIMEDELTA 0x605
|
||||
#define CSR_HTIMEDELTAH 0x615
|
||||
|
||||
/* Virtual Supervisor Registers (H-extension) */
|
||||
#define CSR_VSSTATUS 0x200
|
||||
#define CSR_VSIE 0x204
|
||||
#define CSR_VSTVEC 0x205
|
||||
#define CSR_VSSCRATCH 0x240
|
||||
#define CSR_VSEPC 0x241
|
||||
#define CSR_VSCAUSE 0x242
|
||||
#define CSR_VSTVAL 0x243
|
||||
#define CSR_VSIP 0x244
|
||||
#define CSR_VSATP 0x280
|
||||
|
||||
/* ===== Machine-level CSRs ===== */
|
||||
|
||||
/* Machine Information Registers */
|
||||
#define CSR_MVENDORID 0xf11
|
||||
#define CSR_MARCHID 0xf12
|
||||
#define CSR_MIMPID 0xf13
|
||||
#define CSR_MHARTID 0xf14
|
||||
|
||||
/* Machine Trap Setup */
|
||||
#define CSR_MSTATUS 0x300
|
||||
#define CSR_MISA 0x301
|
||||
#define CSR_MEDELEG 0x302
|
||||
#define CSR_MIDELEG 0x303
|
||||
#define CSR_MIE 0x304
|
||||
#define CSR_MTVEC 0x305
|
||||
#define CSR_MCOUNTEREN 0x306
|
||||
#define CSR_MSTATUSH 0x310
|
||||
|
||||
/* Machine Trap Handling */
|
||||
#define CSR_MSCRATCH 0x340
|
||||
#define CSR_MEPC 0x341
|
||||
#define CSR_MCAUSE 0x342
|
||||
#define CSR_MTVAL 0x343
|
||||
#define CSR_MIP 0x344
|
||||
#define CSR_MTINST 0x34a
|
||||
#define CSR_MTVAL2 0x34b
|
||||
|
||||
/* Machine Memory Protection */
|
||||
#define CSR_PMPCFG0 0x3a0
|
||||
#define CSR_PMPCFG1 0x3a1
|
||||
#define CSR_PMPCFG2 0x3a2
|
||||
#define CSR_PMPCFG3 0x3a3
|
||||
#define CSR_PMPCFG4 0x3a4
|
||||
#define CSR_PMPCFG5 0x3a5
|
||||
#define CSR_PMPCFG6 0x3a6
|
||||
#define CSR_PMPCFG7 0x3a7
|
||||
#define CSR_PMPCFG8 0x3a8
|
||||
#define CSR_PMPCFG9 0x3a9
|
||||
#define CSR_PMPCFG10 0x3aa
|
||||
#define CSR_PMPCFG11 0x3ab
|
||||
#define CSR_PMPCFG12 0x3ac
|
||||
#define CSR_PMPCFG13 0x3ad
|
||||
#define CSR_PMPCFG14 0x3ae
|
||||
#define CSR_PMPCFG15 0x3af
|
||||
#define CSR_PMPADDR0 0x3b0
|
||||
#define CSR_PMPADDR1 0x3b1
|
||||
#define CSR_PMPADDR2 0x3b2
|
||||
#define CSR_PMPADDR3 0x3b3
|
||||
#define CSR_PMPADDR4 0x3b4
|
||||
#define CSR_PMPADDR5 0x3b5
|
||||
#define CSR_PMPADDR6 0x3b6
|
||||
#define CSR_PMPADDR7 0x3b7
|
||||
#define CSR_PMPADDR8 0x3b8
|
||||
#define CSR_PMPADDR9 0x3b9
|
||||
#define CSR_PMPADDR10 0x3ba
|
||||
#define CSR_PMPADDR11 0x3bb
|
||||
#define CSR_PMPADDR12 0x3bc
|
||||
#define CSR_PMPADDR13 0x3bd
|
||||
#define CSR_PMPADDR14 0x3be
|
||||
#define CSR_PMPADDR15 0x3bf
|
||||
#define CSR_PMPADDR16 0x3c0
|
||||
#define CSR_PMPADDR17 0x3c1
|
||||
#define CSR_PMPADDR18 0x3c2
|
||||
#define CSR_PMPADDR19 0x3c3
|
||||
#define CSR_PMPADDR20 0x3c4
|
||||
#define CSR_PMPADDR21 0x3c5
|
||||
#define CSR_PMPADDR22 0x3c6
|
||||
#define CSR_PMPADDR23 0x3c7
|
||||
#define CSR_PMPADDR24 0x3c8
|
||||
#define CSR_PMPADDR25 0x3c9
|
||||
#define CSR_PMPADDR26 0x3ca
|
||||
#define CSR_PMPADDR27 0x3cb
|
||||
#define CSR_PMPADDR28 0x3cc
|
||||
#define CSR_PMPADDR29 0x3cd
|
||||
#define CSR_PMPADDR30 0x3ce
|
||||
#define CSR_PMPADDR31 0x3cf
|
||||
#define CSR_PMPADDR32 0x3d0
|
||||
#define CSR_PMPADDR33 0x3d1
|
||||
#define CSR_PMPADDR34 0x3d2
|
||||
#define CSR_PMPADDR35 0x3d3
|
||||
#define CSR_PMPADDR36 0x3d4
|
||||
#define CSR_PMPADDR37 0x3d5
|
||||
#define CSR_PMPADDR38 0x3d6
|
||||
#define CSR_PMPADDR39 0x3d7
|
||||
#define CSR_PMPADDR40 0x3d8
|
||||
#define CSR_PMPADDR41 0x3d9
|
||||
#define CSR_PMPADDR42 0x3da
|
||||
#define CSR_PMPADDR43 0x3db
|
||||
#define CSR_PMPADDR44 0x3dc
|
||||
#define CSR_PMPADDR45 0x3dd
|
||||
#define CSR_PMPADDR46 0x3de
|
||||
#define CSR_PMPADDR47 0x3df
|
||||
#define CSR_PMPADDR48 0x3e0
|
||||
#define CSR_PMPADDR49 0x3e1
|
||||
#define CSR_PMPADDR50 0x3e2
|
||||
#define CSR_PMPADDR51 0x3e3
|
||||
#define CSR_PMPADDR52 0x3e4
|
||||
#define CSR_PMPADDR53 0x3e5
|
||||
#define CSR_PMPADDR54 0x3e6
|
||||
#define CSR_PMPADDR55 0x3e7
|
||||
#define CSR_PMPADDR56 0x3e8
|
||||
#define CSR_PMPADDR57 0x3e9
|
||||
#define CSR_PMPADDR58 0x3ea
|
||||
#define CSR_PMPADDR59 0x3eb
|
||||
#define CSR_PMPADDR60 0x3ec
|
||||
#define CSR_PMPADDR61 0x3ed
|
||||
#define CSR_PMPADDR62 0x3ee
|
||||
#define CSR_PMPADDR63 0x3ef
|
||||
|
||||
/* Machine Counters/Timers */
|
||||
#define CSR_MCYCLE 0xb00
|
||||
#define CSR_MINSTRET 0xb02
|
||||
#define CSR_MHPMCOUNTER3 0xb03
|
||||
#define CSR_MHPMCOUNTER4 0xb04
|
||||
#define CSR_MHPMCOUNTER5 0xb05
|
||||
#define CSR_MHPMCOUNTER6 0xb06
|
||||
#define CSR_MHPMCOUNTER7 0xb07
|
||||
#define CSR_MHPMCOUNTER8 0xb08
|
||||
#define CSR_MHPMCOUNTER9 0xb09
|
||||
#define CSR_MHPMCOUNTER10 0xb0a
|
||||
#define CSR_MHPMCOUNTER11 0xb0b
|
||||
#define CSR_MHPMCOUNTER12 0xb0c
|
||||
#define CSR_MHPMCOUNTER13 0xb0d
|
||||
#define CSR_MHPMCOUNTER14 0xb0e
|
||||
#define CSR_MHPMCOUNTER15 0xb0f
|
||||
#define CSR_MHPMCOUNTER16 0xb10
|
||||
#define CSR_MHPMCOUNTER17 0xb11
|
||||
#define CSR_MHPMCOUNTER18 0xb12
|
||||
#define CSR_MHPMCOUNTER19 0xb13
|
||||
#define CSR_MHPMCOUNTER20 0xb14
|
||||
#define CSR_MHPMCOUNTER21 0xb15
|
||||
#define CSR_MHPMCOUNTER22 0xb16
|
||||
#define CSR_MHPMCOUNTER23 0xb17
|
||||
#define CSR_MHPMCOUNTER24 0xb18
|
||||
#define CSR_MHPMCOUNTER25 0xb19
|
||||
#define CSR_MHPMCOUNTER26 0xb1a
|
||||
#define CSR_MHPMCOUNTER27 0xb1b
|
||||
#define CSR_MHPMCOUNTER28 0xb1c
|
||||
#define CSR_MHPMCOUNTER29 0xb1d
|
||||
#define CSR_MHPMCOUNTER30 0xb1e
|
||||
#define CSR_MHPMCOUNTER31 0xb1f
|
||||
#define CSR_MCYCLEH 0xb80
|
||||
#define CSR_MINSTRETH 0xb82
|
||||
#define CSR_MHPMCOUNTER3H 0xb83
|
||||
@@ -415,6 +484,52 @@
|
||||
#define CSR_MHPMCOUNTER30H 0xb9e
|
||||
#define CSR_MHPMCOUNTER31H 0xb9f
|
||||
|
||||
/* Machine Counter Setup */
|
||||
#define CSR_MCOUNTINHIBIT 0x320
|
||||
#define CSR_MHPMEVENT3 0x323
|
||||
#define CSR_MHPMEVENT4 0x324
|
||||
#define CSR_MHPMEVENT5 0x325
|
||||
#define CSR_MHPMEVENT6 0x326
|
||||
#define CSR_MHPMEVENT7 0x327
|
||||
#define CSR_MHPMEVENT8 0x328
|
||||
#define CSR_MHPMEVENT9 0x329
|
||||
#define CSR_MHPMEVENT10 0x32a
|
||||
#define CSR_MHPMEVENT11 0x32b
|
||||
#define CSR_MHPMEVENT12 0x32c
|
||||
#define CSR_MHPMEVENT13 0x32d
|
||||
#define CSR_MHPMEVENT14 0x32e
|
||||
#define CSR_MHPMEVENT15 0x32f
|
||||
#define CSR_MHPMEVENT16 0x330
|
||||
#define CSR_MHPMEVENT17 0x331
|
||||
#define CSR_MHPMEVENT18 0x332
|
||||
#define CSR_MHPMEVENT19 0x333
|
||||
#define CSR_MHPMEVENT20 0x334
|
||||
#define CSR_MHPMEVENT21 0x335
|
||||
#define CSR_MHPMEVENT22 0x336
|
||||
#define CSR_MHPMEVENT23 0x337
|
||||
#define CSR_MHPMEVENT24 0x338
|
||||
#define CSR_MHPMEVENT25 0x339
|
||||
#define CSR_MHPMEVENT26 0x33a
|
||||
#define CSR_MHPMEVENT27 0x33b
|
||||
#define CSR_MHPMEVENT28 0x33c
|
||||
#define CSR_MHPMEVENT29 0x33d
|
||||
#define CSR_MHPMEVENT30 0x33e
|
||||
#define CSR_MHPMEVENT31 0x33f
|
||||
|
||||
/* Debug/Trace Registers */
|
||||
#define CSR_TSELECT 0x7a0
|
||||
#define CSR_TDATA1 0x7a1
|
||||
#define CSR_TDATA2 0x7a2
|
||||
#define CSR_TDATA3 0x7a3
|
||||
|
||||
/* Debug Mode Registers */
|
||||
#define CSR_DCSR 0x7b0
|
||||
#define CSR_DPC 0x7b1
|
||||
#define CSR_DSCRATCH0 0x7b2
|
||||
#define CSR_DSCRATCH1 0x7b3
|
||||
|
||||
/* ===== Trap/Exception Causes ===== */
|
||||
|
||||
#define CAUSE_MISALIGNED_FETCH 0x0
|
||||
#define CAUSE_FETCH_ACCESS 0x1
|
||||
#define CAUSE_ILLEGAL_INSTRUCTION 0x2
|
||||
@@ -424,8 +539,8 @@
|
||||
#define CAUSE_MISALIGNED_STORE 0x6
|
||||
#define CAUSE_STORE_ACCESS 0x7
|
||||
#define CAUSE_USER_ECALL 0x8
|
||||
#define CAUSE_HYPERVISOR_ECALL 0x9
|
||||
#define CAUSE_SUPERVISOR_ECALL 0xa
|
||||
#define CAUSE_SUPERVISOR_ECALL 0x9
|
||||
#define CAUSE_VIRTUAL_SUPERVISOR_ECALL 0xa
|
||||
#define CAUSE_MACHINE_ECALL 0xb
|
||||
#define CAUSE_FETCH_PAGE_FAULT 0xc
|
||||
#define CAUSE_LOAD_PAGE_FAULT 0xd
|
||||
@@ -435,6 +550,8 @@
|
||||
#define CAUSE_VIRTUAL_INST_FAULT 0x16
|
||||
#define CAUSE_STORE_GUEST_PAGE_FAULT 0x17
|
||||
|
||||
/* ===== Instruction Encodings ===== */
|
||||
|
||||
#define INSN_MATCH_LB 0x3
|
||||
#define INSN_MASK_LB 0x707f
|
||||
#define INSN_MATCH_LH 0x1003
|
||||
|
@@ -66,10 +66,8 @@ static inline int ffs(int x)
|
||||
x >>= 2;
|
||||
r += 2;
|
||||
}
|
||||
if (!(x & 1)) {
|
||||
x >>= 1;
|
||||
if (!(x & 1))
|
||||
r += 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -148,10 +146,8 @@ static inline int fls(int x)
|
||||
x <<= 2;
|
||||
r -= 2;
|
||||
}
|
||||
if (!(x & 0x80000000u)) {
|
||||
x <<= 1;
|
||||
if (!(x & 0x80000000u))
|
||||
r -= 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
165
include/sbi/sbi_domain.h
Normal file
165
include/sbi/sbi_domain.h
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __SBI_DOMAIN_H__
|
||||
#define __SBI_DOMAIN_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
#include <sbi/sbi_hartmask.h>
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
/** Domain access types */
|
||||
enum sbi_domain_access {
|
||||
SBI_DOMAIN_READ = (1UL << 0),
|
||||
SBI_DOMAIN_WRITE = (1UL << 1),
|
||||
SBI_DOMAIN_EXECUTE = (1UL << 2),
|
||||
SBI_DOMAIN_MMIO = (1UL << 3)
|
||||
};
|
||||
|
||||
/** Representation of OpenSBI domain memory region */
|
||||
struct sbi_domain_memregion {
|
||||
/**
|
||||
* Size of memory region as power of 2
|
||||
* It has to be minimum 3 and maximum __riscv_xlen
|
||||
*/
|
||||
unsigned long order;
|
||||
/**
|
||||
* Base address of memory region
|
||||
* It must be 2^order aligned address
|
||||
*/
|
||||
unsigned long base;
|
||||
/** Flags representing memory region attributes */
|
||||
#define SBI_DOMAIN_MEMREGION_READABLE (1UL << 0)
|
||||
#define SBI_DOMAIN_MEMREGION_WRITEABLE (1UL << 1)
|
||||
#define SBI_DOMAIN_MEMREGION_EXECUTABLE (1UL << 2)
|
||||
#define SBI_DOMAIN_MEMREGION_MMODE (1UL << 3)
|
||||
#define SBI_DOMAIN_MEMREGION_ACCESS_MASK (0xfUL)
|
||||
|
||||
#define SBI_DOMAIN_MEMREGION_MMIO (1UL << 31)
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
/** Maximum number of domains */
|
||||
#define SBI_DOMAIN_MAX_INDEX 32
|
||||
|
||||
/** Representation of OpenSBI domain */
|
||||
struct sbi_domain {
|
||||
/**
|
||||
* Logical index of this domain
|
||||
* Note: This set by sbi_domain_finalize() in the coldboot path
|
||||
*/
|
||||
u32 index;
|
||||
/**
|
||||
* HARTs assigned to this domain
|
||||
* Note: This set by sbi_domain_init() and sbi_domain_finalize()
|
||||
* in the coldboot path
|
||||
*/
|
||||
struct sbi_hartmask assigned_harts;
|
||||
/** Name of this domain */
|
||||
char name[64];
|
||||
/** Possible HARTs in this domain */
|
||||
const struct sbi_hartmask *possible_harts;
|
||||
/** Array of memory regions terminated by a region with order zero */
|
||||
struct sbi_domain_memregion *regions;
|
||||
/** HART id of the HART booting this domain */
|
||||
u32 boot_hartid;
|
||||
/** Arg1 (or 'a1' register) of next booting stage for this domain */
|
||||
unsigned long next_arg1;
|
||||
/** Address of next booting stage for this domain */
|
||||
unsigned long next_addr;
|
||||
/** Privilege mode of next booting stage for this domain */
|
||||
unsigned long next_mode;
|
||||
/** Is domain allowed to reset the system */
|
||||
bool system_reset_allowed;
|
||||
};
|
||||
|
||||
/** HART id to domain table */
|
||||
extern struct sbi_domain *hartid_to_domain_table[];
|
||||
|
||||
/** Get pointer to sbi_domain from HART id */
|
||||
#define sbi_hartid_to_domain(__hartid) \
|
||||
hartid_to_domain_table[__hartid]
|
||||
|
||||
/** Get pointer to sbi_domain for current HART */
|
||||
#define sbi_domain_thishart_ptr() \
|
||||
sbi_hartid_to_domain(current_hartid())
|
||||
|
||||
/** Index to domain table */
|
||||
extern struct sbi_domain *domidx_to_domain_table[];
|
||||
|
||||
/** Get pointer to sbi_domain from index */
|
||||
#define sbi_index_to_domain(__index) \
|
||||
domidx_to_domain_table[__index]
|
||||
|
||||
/** Iterate over each domain */
|
||||
#define sbi_domain_for_each(__i, __d) \
|
||||
for ((__i) = 0; ((__d) = sbi_index_to_domain(__i)); (__i)++)
|
||||
|
||||
/** Iterate over each memory region of a domain */
|
||||
#define sbi_domain_for_each_memregion(__d, __r) \
|
||||
for ((__r) = (__d)->regions; (__r)->order; (__r)++)
|
||||
|
||||
/**
|
||||
* Check whether given HART is assigned to specified domain
|
||||
* @param dom pointer to domain
|
||||
* @param hartid the HART ID
|
||||
* @return TRUE if HART is assigned to domain otherwise FALSE
|
||||
*/
|
||||
bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid);
|
||||
|
||||
/**
|
||||
* Get ulong assigned HART mask for given domain and HART base ID
|
||||
* @param dom pointer to domain
|
||||
* @param hbase the HART base ID
|
||||
* @return ulong possible HART mask
|
||||
* Note: the return ulong mask will be set to zero on failure.
|
||||
*/
|
||||
ulong sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom,
|
||||
ulong hbase);
|
||||
|
||||
/** Initialize a domain memory region as firmware region */
|
||||
void sbi_domain_memregion_initfw(struct sbi_domain_memregion *reg);
|
||||
|
||||
/**
|
||||
* Check whether we can access specified address for given mode and
|
||||
* memory region flags under a domain
|
||||
* @param dom pointer to domain
|
||||
* @param addr the address to be checked
|
||||
* @param mode the privilege mode of access
|
||||
* @param access_flags bitmask of domain access types (enum sbi_domain_access)
|
||||
* @return TRUE if access allowed otherwise FALSE
|
||||
*/
|
||||
bool sbi_domain_check_addr(const struct sbi_domain *dom,
|
||||
unsigned long addr, unsigned long mode,
|
||||
unsigned long access_flags);
|
||||
|
||||
/** Dump domain details on the console */
|
||||
void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix);
|
||||
|
||||
/** Dump all domain details on the console */
|
||||
void sbi_domain_dump_all(const char *suffix);
|
||||
|
||||
/**
|
||||
* Register a new domain
|
||||
* @param dom pointer to domain
|
||||
* @param assign_mask pointer to HART mask of HARTs assigned to the domain
|
||||
*
|
||||
* @return 0 on success and negative error code on failure
|
||||
*/
|
||||
int sbi_domain_register(struct sbi_domain *dom,
|
||||
const struct sbi_hartmask *assign_mask);
|
||||
|
||||
/** Finalize domain tables and startup non-root domains */
|
||||
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid);
|
||||
|
||||
/** Initialize domains */
|
||||
int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid);
|
||||
|
||||
#endif
|
@@ -26,7 +26,8 @@ struct sbi_ecall_extension {
|
||||
unsigned long extid_end;
|
||||
int (* probe)(unsigned long extid, unsigned long *out_val);
|
||||
int (* handle)(unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
const struct sbi_trap_regs *regs,
|
||||
unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap);
|
||||
};
|
||||
|
||||
@@ -37,6 +38,7 @@ extern struct sbi_ecall_extension ecall_rfence;
|
||||
extern struct sbi_ecall_extension ecall_ipi;
|
||||
extern struct sbi_ecall_extension ecall_vendor;
|
||||
extern struct sbi_ecall_extension ecall_hsm;
|
||||
extern struct sbi_ecall_extension ecall_srst;
|
||||
|
||||
u16 sbi_ecall_version_major(void);
|
||||
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#define SBI_EXT_IPI 0x735049
|
||||
#define SBI_EXT_RFENCE 0x52464E43
|
||||
#define SBI_EXT_HSM 0x48534D
|
||||
#define SBI_EXT_SRST 0x53525354
|
||||
|
||||
/* SBI function IDs for BASE extension*/
|
||||
#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
|
||||
@@ -62,6 +63,17 @@
|
||||
#define SBI_HSM_HART_STATUS_START_PENDING 0x2
|
||||
#define SBI_HSM_HART_STATUS_STOP_PENDING 0x3
|
||||
|
||||
/* SBI function IDs for SRST extension */
|
||||
#define SBI_EXT_SRST_RESET 0x0
|
||||
|
||||
#define SBI_SRST_RESET_TYPE_SHUTDOWN 0x0
|
||||
#define SBI_SRST_RESET_TYPE_COLD_REBOOT 0x1
|
||||
#define SBI_SRST_RESET_TYPE_WARM_REBOOT 0x2
|
||||
#define SBI_SRST_RESET_TYPE_LAST SBI_SRST_RESET_TYPE_WARM_REBOOT
|
||||
|
||||
#define SBI_SRST_RESET_REASON_NONE 0x0
|
||||
#define SBI_SRST_RESET_REASON_SYSFAIL 0x1
|
||||
|
||||
#define SBI_SPEC_VERSION_MAJOR_OFFSET 24
|
||||
#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f
|
||||
#define SBI_SPEC_VERSION_MINOR_MASK 0xffffff
|
||||
|
@@ -14,14 +14,12 @@
|
||||
|
||||
/** Possible feature flags of a hart */
|
||||
enum sbi_hart_features {
|
||||
/** Hart has PMP support */
|
||||
SBI_HART_HAS_PMP = (1 << 0),
|
||||
/** Hart has S-mode counter enable */
|
||||
SBI_HART_HAS_SCOUNTEREN = (1 << 1),
|
||||
SBI_HART_HAS_SCOUNTEREN = (1 << 0),
|
||||
/** Hart has M-mode counter enable */
|
||||
SBI_HART_HAS_MCOUNTEREN = (1 << 2),
|
||||
SBI_HART_HAS_MCOUNTEREN = (1 << 1),
|
||||
/** HART has timer csr implementation in hardware */
|
||||
SBI_HART_HAS_TIME = (1 << 3),
|
||||
SBI_HART_HAS_TIME = (1 << 2),
|
||||
|
||||
/** Last index of Hart features*/
|
||||
SBI_HART_HAS_LAST_FEATURE = SBI_HART_HAS_TIME,
|
||||
@@ -29,7 +27,7 @@ enum sbi_hart_features {
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot);
|
||||
int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||
|
||||
extern void (*sbi_hart_expected_trap)(void);
|
||||
static inline ulong sbi_hart_expected_trap_addr(void)
|
||||
@@ -37,14 +35,13 @@ static inline ulong sbi_hart_expected_trap_addr(void)
|
||||
return (ulong)sbi_hart_expected_trap;
|
||||
}
|
||||
|
||||
void sbi_hart_delegation_dump(struct sbi_scratch *scratch);
|
||||
unsigned int sbi_hart_mhpm_count(struct sbi_scratch *scratch);
|
||||
void sbi_hart_delegation_dump(struct sbi_scratch *scratch,
|
||||
const char *prefix, const char *suffix);
|
||||
unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch);
|
||||
int sbi_hart_pmp_get(struct sbi_scratch *scratch, unsigned int n,
|
||||
unsigned long *prot_out, unsigned long *addr_out,
|
||||
unsigned long *size);
|
||||
void sbi_hart_pmp_dump(struct sbi_scratch *scratch);
|
||||
int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long daddr,
|
||||
unsigned long attr);
|
||||
unsigned long sbi_hart_pmp_granularity(struct sbi_scratch *scratch);
|
||||
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch);
|
||||
int sbi_hart_pmp_configure(struct sbi_scratch *scratch);
|
||||
bool sbi_hart_has_feature(struct sbi_scratch *scratch, unsigned long feature);
|
||||
void sbi_hart_get_features_str(struct sbi_scratch *scratch,
|
||||
char *features_str, int nfstr);
|
||||
|
@@ -67,7 +67,7 @@ static inline void sbi_hartmask_clear_hart(u32 h, struct sbi_hartmask *m)
|
||||
* @param h HART id to test
|
||||
* @param m the hartmask pointer
|
||||
*/
|
||||
static inline int sbi_hartmask_test_hart(u32 h, struct sbi_hartmask *m)
|
||||
static inline int sbi_hartmask_test_hart(u32 h, const struct sbi_hartmask *m)
|
||||
{
|
||||
if (h < SBI_HARTMASK_MAX_BITS)
|
||||
return __test_bit(h, m->bits);
|
||||
|
@@ -19,18 +19,20 @@
|
||||
#define SBI_HART_STARTED 3
|
||||
#define SBI_HART_UNKNOWN 4
|
||||
|
||||
struct sbi_domain;
|
||||
struct sbi_scratch;
|
||||
|
||||
int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot);
|
||||
void __noreturn sbi_hsm_exit(struct sbi_scratch *scratch);
|
||||
|
||||
int sbi_hsm_hart_start(struct sbi_scratch *scratch, u32 hartid,
|
||||
ulong saddr, ulong priv);
|
||||
int sbi_hsm_hart_start(struct sbi_scratch *scratch,
|
||||
const struct sbi_domain *dom,
|
||||
u32 hartid, ulong saddr, ulong smode, ulong priv);
|
||||
int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow);
|
||||
int sbi_hsm_hart_get_state(u32 hartid);
|
||||
int sbi_hsm_hart_get_state(const struct sbi_domain *dom, u32 hartid);
|
||||
int sbi_hsm_hart_state_to_status(int state);
|
||||
bool sbi_hsm_hart_started(u32 hartid);
|
||||
int sbi_hsm_hart_started_mask(ulong hbase, ulong *out_hmask);
|
||||
int sbi_hsm_hart_started_mask(const struct sbi_domain *dom,
|
||||
ulong hbase, ulong *out_hmask);
|
||||
void sbi_hsm_prepare_next_jump(struct sbi_scratch *scratch, u32 hartid);
|
||||
|
||||
#endif
|
||||
|
@@ -40,12 +40,15 @@
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
#include <sbi/sbi_version.h>
|
||||
|
||||
struct sbi_domain_memregion;
|
||||
struct sbi_trap_info;
|
||||
struct sbi_trap_regs;
|
||||
|
||||
/** Possible feature flags of a platform */
|
||||
enum sbi_platform_features {
|
||||
/** Platform has timer value */
|
||||
@@ -89,14 +92,10 @@ struct sbi_platform_operations {
|
||||
*/
|
||||
int (*misa_get_xlen)(void);
|
||||
|
||||
/** Get number of PMP regions for given HART */
|
||||
u32 (*pmp_region_count)(u32 hartid);
|
||||
/**
|
||||
* Get PMP regions details (namely: protection, base address,
|
||||
* and size) for given HART
|
||||
*/
|
||||
int (*pmp_region_info)(u32 hartid, u32 index, ulong *prot, ulong *addr,
|
||||
ulong *log2size);
|
||||
/** Get platform specific root domain memory regions */
|
||||
struct sbi_domain_memregion *(*domains_root_regions)(void);
|
||||
/** Initialize (or populate) domains for the platform */
|
||||
int (*domains_init)(void);
|
||||
|
||||
/** Write a character to the platform console output */
|
||||
void (*console_putc)(char ch);
|
||||
@@ -141,20 +140,19 @@ struct sbi_platform_operations {
|
||||
*/
|
||||
int (*hart_stop)(void);
|
||||
|
||||
/* Check whether reset type and reason supported by the platform */
|
||||
int (*system_reset_check)(u32 reset_type, u32 reset_reason);
|
||||
/** Reset the platform */
|
||||
#define SBI_PLATFORM_RESET_SHUTDOWN 0
|
||||
#define SBI_PLATFORM_RESET_COLD 1
|
||||
#define SBI_PLATFORM_RESET_WARM 2
|
||||
int (*system_reset)(u32 reset_type);
|
||||
void (*system_reset)(u32 reset_type, u32 reset_reason);
|
||||
|
||||
/** platform specific SBI extension implementation probe function */
|
||||
int (*vendor_ext_check)(long extid);
|
||||
/** platform specific SBI extension implementation provider */
|
||||
int (*vendor_ext_provider)(long extid, long funcid,
|
||||
unsigned long *args,
|
||||
const struct sbi_trap_regs *regs,
|
||||
unsigned long *out_value,
|
||||
struct sbi_trap_info *out_trap);
|
||||
} __packed;
|
||||
};
|
||||
|
||||
/** Platform default per-HART stack size for exception/interrupt handling */
|
||||
#define SBI_PLATFORM_DEFAULT_HART_STACK_SIZE 8192
|
||||
@@ -201,7 +199,7 @@ struct sbi_platform {
|
||||
* 2. HART id < SBI_HARTMASK_MAX_BITS
|
||||
*/
|
||||
const u32 *hart_index2id;
|
||||
} __packed;
|
||||
};
|
||||
|
||||
/** Get pointer to sbi_platform for sbi_scratch pointer */
|
||||
#define sbi_platform_ptr(__s) \
|
||||
@@ -457,43 +455,32 @@ static inline int sbi_platform_misa_xlen(const struct sbi_platform *plat)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of PMP regions of a HART
|
||||
* Get platform specific root domain memory regions
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param hartid HART ID
|
||||
*
|
||||
* @return number of PMP regions
|
||||
* @return an array of memory regions terminated by a region with order zero
|
||||
* or NULL for no memory regions
|
||||
*/
|
||||
static inline u32 sbi_platform_pmp_region_count(const struct sbi_platform *plat,
|
||||
u32 hartid)
|
||||
static inline struct sbi_domain_memregion *
|
||||
sbi_platform_domains_root_regions(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->pmp_region_count)
|
||||
return sbi_platform_ops(plat)->pmp_region_count(hartid);
|
||||
return 0;
|
||||
if (plat && sbi_platform_ops(plat)->domains_root_regions)
|
||||
return sbi_platform_ops(plat)->domains_root_regions();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get PMP regions details (namely: protection, base address,
|
||||
* and size) of a HART
|
||||
* Initialize (or populate) domains for the platform
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param hartid HART ID
|
||||
* @param index index of PMP region for which we want details
|
||||
* @param prot output pointer for PMP region protection
|
||||
* @param addr output pointer for PMP region base address
|
||||
* @param log2size output pointer for log-of-2 PMP region size
|
||||
*
|
||||
* @return 0 on success and negative error code on failure
|
||||
*/
|
||||
static inline int sbi_platform_pmp_region_info(const struct sbi_platform *plat,
|
||||
u32 hartid, u32 index,
|
||||
ulong *prot, ulong *addr,
|
||||
ulong *log2size)
|
||||
static inline int sbi_platform_domains_init(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->pmp_region_info)
|
||||
return sbi_platform_ops(plat)->pmp_region_info(hartid, index,
|
||||
prot, addr,
|
||||
log2size);
|
||||
if (plat && sbi_platform_ops(plat)->domains_init)
|
||||
return sbi_platform_ops(plat)->domains_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -685,19 +672,38 @@ static inline void sbi_platform_timer_exit(const struct sbi_platform *plat)
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the platform
|
||||
* Check whether reset type and reason supported by the platform
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param reset_type type of reset
|
||||
* @param reset_reason reason for reset
|
||||
*
|
||||
* @return 0 on success and negative error code on failure
|
||||
* @return 0 if reset type and reason not supported and 1 if supported
|
||||
*/
|
||||
static inline int sbi_platform_system_reset(const struct sbi_platform *plat,
|
||||
u32 reset_type)
|
||||
static inline int sbi_platform_system_reset_check(
|
||||
const struct sbi_platform *plat,
|
||||
u32 reset_type, u32 reset_reason)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->system_reset_check)
|
||||
return sbi_platform_ops(plat)->system_reset_check(reset_type,
|
||||
reset_reason);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the platform
|
||||
*
|
||||
* This function will not return for supported reset type and reset reason
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param reset_type type of reset
|
||||
* @param reset_reason reason for reset
|
||||
*/
|
||||
static inline void sbi_platform_system_reset(const struct sbi_platform *plat,
|
||||
u32 reset_type, u32 reset_reason)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->system_reset)
|
||||
return sbi_platform_ops(plat)->system_reset(reset_type);
|
||||
return 0;
|
||||
sbi_platform_ops(plat)->system_reset(reset_type, reset_reason);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -723,7 +729,7 @@ static inline int sbi_platform_vendor_ext_check(const struct sbi_platform *plat,
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param extid vendor SBI extension id
|
||||
* @param funcid SBI function id within the extension id
|
||||
* @param args pointer to arguments passed by the caller
|
||||
* @param regs pointer to trap registers passed by the caller
|
||||
* @param out_value output value that can be filled by the callee
|
||||
* @param out_trap trap info that can be filled by the callee
|
||||
*
|
||||
@@ -732,13 +738,13 @@ static inline int sbi_platform_vendor_ext_check(const struct sbi_platform *plat,
|
||||
static inline int sbi_platform_vendor_ext_provider(
|
||||
const struct sbi_platform *plat,
|
||||
long extid, long funcid,
|
||||
unsigned long *args,
|
||||
const struct sbi_trap_regs *regs,
|
||||
unsigned long *out_value,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->vendor_ext_provider) {
|
||||
return sbi_platform_ops(plat)->vendor_ext_provider(extid,
|
||||
funcid, args,
|
||||
funcid, regs,
|
||||
out_value,
|
||||
out_trap);
|
||||
}
|
||||
|
@@ -30,12 +30,14 @@
|
||||
#define SBI_SCRATCH_PLATFORM_ADDR_OFFSET (6 * __SIZEOF_POINTER__)
|
||||
/** Offset of hartid_to_scratch member in sbi_scratch */
|
||||
#define SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET (7 * __SIZEOF_POINTER__)
|
||||
/** Offset of trap_exit member in sbi_scratch */
|
||||
#define SBI_SCRATCH_TRAP_EXIT_OFFSET (8 * __SIZEOF_POINTER__)
|
||||
/** Offset of tmp0 member in sbi_scratch */
|
||||
#define SBI_SCRATCH_TMP0_OFFSET (8 * __SIZEOF_POINTER__)
|
||||
#define SBI_SCRATCH_TMP0_OFFSET (9 * __SIZEOF_POINTER__)
|
||||
/** Offset of options member in sbi_scratch */
|
||||
#define SBI_SCRATCH_OPTIONS_OFFSET (9 * __SIZEOF_POINTER__)
|
||||
#define SBI_SCRATCH_OPTIONS_OFFSET (10 * __SIZEOF_POINTER__)
|
||||
/** Offset of extra space in sbi_scratch */
|
||||
#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (10 * __SIZEOF_POINTER__)
|
||||
#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (11 * __SIZEOF_POINTER__)
|
||||
/** Maximum size of sbi_scratch (4KB) */
|
||||
#define SBI_SCRATCH_SIZE (0x1000)
|
||||
|
||||
@@ -63,11 +65,13 @@ struct sbi_scratch {
|
||||
unsigned long platform_addr;
|
||||
/** Address of HART ID to sbi_scratch conversion function */
|
||||
unsigned long hartid_to_scratch;
|
||||
/** Address of trap exit function */
|
||||
unsigned long trap_exit;
|
||||
/** Temporary storage */
|
||||
unsigned long tmp0;
|
||||
/** Options for OpenSBI library */
|
||||
unsigned long options;
|
||||
} __packed;
|
||||
};
|
||||
|
||||
/** Possible options for OpenSBI library */
|
||||
enum sbi_scratch_options {
|
||||
@@ -85,7 +89,7 @@ enum sbi_scratch_options {
|
||||
#define sbi_scratch_thishart_arg1_ptr() \
|
||||
((void *)(sbi_scratch_thishart_ptr()->next_arg1))
|
||||
|
||||
/** Initialize scatch table and allocator */
|
||||
/** Initialize scratch table and allocator */
|
||||
int sbi_scratch_init(struct sbi_scratch *scratch);
|
||||
|
||||
/**
|
||||
|
@@ -12,8 +12,15 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
/*
|
||||
Provides sbi_strcmp for the completeness of supporting string functions.
|
||||
it is not recommended to use sbi_strcmp() but use sbi_strncmp instead.
|
||||
*/
|
||||
|
||||
int sbi_strcmp(const char *a, const char *b);
|
||||
|
||||
int sbi_strncmp(const char *a, const char *b, size_t count);
|
||||
|
||||
size_t sbi_strlen(const char *str);
|
||||
|
||||
size_t sbi_strnlen(const char *str, size_t count);
|
||||
|
@@ -12,6 +12,8 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
void __noreturn sbi_system_reset(u32 platform_reset_type);
|
||||
bool sbi_system_reset_supported(u32 reset_type, u32 reset_reason);
|
||||
|
||||
void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason);
|
||||
|
||||
#endif
|
||||
|
@@ -22,16 +22,6 @@
|
||||
|
||||
#define SBI_TLB_FIFO_NUM_ENTRIES 8
|
||||
|
||||
enum sbi_tlb_info_types {
|
||||
SBI_TLB_FLUSH_VMA,
|
||||
SBI_TLB_FLUSH_VMA_ASID,
|
||||
SBI_TLB_FLUSH_GVMA,
|
||||
SBI_TLB_FLUSH_GVMA_VMID,
|
||||
SBI_TLB_FLUSH_VVMA,
|
||||
SBI_TLB_FLUSH_VVMA_ASID,
|
||||
SBI_ITLB_FLUSH
|
||||
};
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
struct sbi_tlb_info {
|
||||
@@ -39,17 +29,25 @@ struct sbi_tlb_info {
|
||||
unsigned long size;
|
||||
unsigned long asid;
|
||||
unsigned long vmid;
|
||||
unsigned long type;
|
||||
void (*local_fn)(struct sbi_tlb_info *tinfo);
|
||||
struct sbi_hartmask smask;
|
||||
};
|
||||
|
||||
#define SBI_TLB_INFO_INIT(__p, __start, __size, __asid, __vmid, __type, __src) \
|
||||
void sbi_tlb_local_hfence_vvma(struct sbi_tlb_info *tinfo);
|
||||
void sbi_tlb_local_hfence_gvma(struct sbi_tlb_info *tinfo);
|
||||
void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo);
|
||||
void sbi_tlb_local_hfence_vvma_asid(struct sbi_tlb_info *tinfo);
|
||||
void sbi_tlb_local_hfence_gvma_vmid(struct sbi_tlb_info *tinfo);
|
||||
void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo);
|
||||
void sbi_tlb_local_fence_i(struct sbi_tlb_info *tinfo);
|
||||
|
||||
#define SBI_TLB_INFO_INIT(__p, __start, __size, __asid, __vmid, __lfn, __src) \
|
||||
do { \
|
||||
(__p)->start = (__start); \
|
||||
(__p)->size = (__size); \
|
||||
(__p)->asid = (__asid); \
|
||||
(__p)->vmid = (__vmid); \
|
||||
(__p)->type = (__type); \
|
||||
(__p)->local_fn = (__lfn); \
|
||||
SBI_HARTMASK_INIT_EXCEPT(&(__p)->smask, (__src)); \
|
||||
} while (0)
|
||||
|
||||
|
@@ -186,7 +186,7 @@ struct sbi_trap_regs {
|
||||
unsigned long mstatus;
|
||||
/** mstatusH register state (only for 32-bit) */
|
||||
unsigned long mstatusH;
|
||||
} __packed;
|
||||
};
|
||||
|
||||
/** Representation of trap details */
|
||||
struct sbi_trap_info {
|
||||
@@ -207,6 +207,8 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
|
||||
|
||||
void sbi_trap_handler(struct sbi_trap_regs *regs);
|
||||
|
||||
void __noreturn sbi_trap_exit(const struct sbi_trap_regs *regs);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@@ -11,7 +11,7 @@
|
||||
#define __SBI_VERSION_H__
|
||||
|
||||
#define OPENSBI_VERSION_MAJOR 0
|
||||
#define OPENSBI_VERSION_MINOR 8
|
||||
#define OPENSBI_VERSION_MINOR 9
|
||||
|
||||
/**
|
||||
* OpenSBI 32-bit version with:
|
||||
|
73
include/sbi_utils/fdt/fdt_domain.h
Normal file
73
include/sbi_utils/fdt/fdt_domain.h
Normal file
@@ -0,0 +1,73 @@
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
/*
|
||||
* fdt_domain.c - Flat Device Tree Domain helper routines
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __FDT_DOMAIN_H__
|
||||
#define __FDT_DOMAIN_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
struct sbi_domain;
|
||||
|
||||
/**
|
||||
* Iterate over each domains in device tree
|
||||
*
|
||||
* @param fdt device tree blob
|
||||
* @param opaque private pointer for each iteration
|
||||
* @param fn callback function for each iteration
|
||||
*
|
||||
* @return 0 on success and negative error code on failure
|
||||
*/
|
||||
int fdt_iterate_each_domain(void *fdt, void *opaque,
|
||||
int (*fn)(void *fdt, int domain_offset,
|
||||
void *opaque));
|
||||
|
||||
/**
|
||||
* Iterate over each memregion of a domain in device tree
|
||||
*
|
||||
* @param fdt device tree blob
|
||||
* @param domain_offset domain DT node offset
|
||||
* @param opaque private pointer for each iteration
|
||||
* @param fn callback function for each iteration
|
||||
*
|
||||
* @return 0 on success and negative error code on failure
|
||||
*/
|
||||
int fdt_iterate_each_memregion(void *fdt, int domain_offset, void *opaque,
|
||||
int (*fn)(void *fdt, int domain_offset,
|
||||
int region_offset, u32 region_access,
|
||||
void *opaque));
|
||||
|
||||
/**
|
||||
* Fix up the domain configuration in the device tree
|
||||
*
|
||||
* This routine:
|
||||
* 1. Disables MMIO devices not accessible to the coldboot HART domain
|
||||
* 2. Removes "opensbi-domain" DT property from CPU DT nodes
|
||||
* 3. Removes domain configuration DT node under /chosen DT node
|
||||
*
|
||||
* It is recommended that platform support call this function in
|
||||
* their final_init() platform operation.
|
||||
*
|
||||
* @param fdt device tree blob
|
||||
*/
|
||||
void fdt_domain_fixup(void *fdt);
|
||||
|
||||
/**
|
||||
* Populate domains from device tree
|
||||
*
|
||||
* It is recommended that platform support call this function in
|
||||
* their domains_init() platform operation.
|
||||
*
|
||||
* @param fdt device tree blob
|
||||
*
|
||||
* @return 0 on success and negative error code on failure
|
||||
*/
|
||||
int fdt_domains_populate(void *fdt);
|
||||
|
||||
#endif /* __FDT_DOMAIN_H__ */
|
@@ -15,10 +15,13 @@
|
||||
struct fdt_reset {
|
||||
const struct fdt_match *match_table;
|
||||
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||
int (*system_reset)(u32 reset_type);
|
||||
int (*system_reset_check)(u32 reset_type, u32 reset_reason);
|
||||
void (*system_reset)(u32 reset_type, u32 reset_reason);
|
||||
};
|
||||
|
||||
int fdt_system_reset(u32 reset_type);
|
||||
int fdt_system_reset_check(u32 reset_type, u32 reset_reason);
|
||||
|
||||
void fdt_system_reset(u32 reset_type, u32 reset_reason);
|
||||
|
||||
int fdt_reset_init(void);
|
||||
|
||||
|
@@ -14,6 +14,8 @@ void htif_putc(char ch);
|
||||
|
||||
int htif_getc(void);
|
||||
|
||||
int htif_system_reset(u32 type);
|
||||
int htif_system_reset_check(u32 type, u32 reason);
|
||||
|
||||
void htif_system_reset(u32 type, u32 reason);
|
||||
|
||||
#endif
|
||||
|
@@ -12,7 +12,9 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
int sifive_test_system_reset(u32 type);
|
||||
int sifive_test_system_reset_check(u32 type, u32 reason);
|
||||
|
||||
void sifive_test_system_reset(u32 type, u32 reason);
|
||||
|
||||
int sifive_test_init(unsigned long base);
|
||||
|
||||
|
@@ -15,6 +15,7 @@ libsbi-objs-y += riscv_locks.o
|
||||
libsbi-objs-y += sbi_bitmap.o
|
||||
libsbi-objs-y += sbi_bitops.o
|
||||
libsbi-objs-y += sbi_console.o
|
||||
libsbi-objs-y += sbi_domain.o
|
||||
libsbi-objs-y += sbi_ecall.o
|
||||
libsbi-objs-y += sbi_ecall_base.o
|
||||
libsbi-objs-y += sbi_ecall_hsm.o
|
||||
|
@@ -90,142 +90,88 @@ void misa_string(int xlen, char *out, unsigned int out_sz)
|
||||
|
||||
unsigned long csr_read_num(int csr_num)
|
||||
{
|
||||
#define switchcase_csr_read(__csr_num, __val) \
|
||||
case __csr_num: \
|
||||
__val = csr_read(__csr_num); \
|
||||
break;
|
||||
#define switchcase_csr_read_2(__csr_num, __val) \
|
||||
switchcase_csr_read(__csr_num + 0, __val) \
|
||||
switchcase_csr_read(__csr_num + 1, __val)
|
||||
#define switchcase_csr_read_4(__csr_num, __val) \
|
||||
switchcase_csr_read_2(__csr_num + 0, __val) \
|
||||
switchcase_csr_read_2(__csr_num + 2, __val)
|
||||
#define switchcase_csr_read_8(__csr_num, __val) \
|
||||
switchcase_csr_read_4(__csr_num + 0, __val) \
|
||||
switchcase_csr_read_4(__csr_num + 4, __val)
|
||||
#define switchcase_csr_read_16(__csr_num, __val) \
|
||||
switchcase_csr_read_8(__csr_num + 0, __val) \
|
||||
switchcase_csr_read_8(__csr_num + 8, __val)
|
||||
#define switchcase_csr_read_32(__csr_num, __val) \
|
||||
switchcase_csr_read_16(__csr_num + 0, __val) \
|
||||
switchcase_csr_read_16(__csr_num + 16, __val)
|
||||
#define switchcase_csr_read_64(__csr_num, __val) \
|
||||
switchcase_csr_read_32(__csr_num + 0, __val) \
|
||||
switchcase_csr_read_32(__csr_num + 32, __val)
|
||||
|
||||
unsigned long ret = 0;
|
||||
|
||||
switch (csr_num) {
|
||||
case CSR_PMPCFG0:
|
||||
ret = csr_read(CSR_PMPCFG0);
|
||||
break;
|
||||
case CSR_PMPCFG1:
|
||||
ret = csr_read(CSR_PMPCFG1);
|
||||
break;
|
||||
case CSR_PMPCFG2:
|
||||
ret = csr_read(CSR_PMPCFG2);
|
||||
break;
|
||||
case CSR_PMPCFG3:
|
||||
ret = csr_read(CSR_PMPCFG3);
|
||||
break;
|
||||
case CSR_PMPADDR0:
|
||||
ret = csr_read(CSR_PMPADDR0);
|
||||
break;
|
||||
case CSR_PMPADDR1:
|
||||
ret = csr_read(CSR_PMPADDR1);
|
||||
break;
|
||||
case CSR_PMPADDR2:
|
||||
ret = csr_read(CSR_PMPADDR2);
|
||||
break;
|
||||
case CSR_PMPADDR3:
|
||||
ret = csr_read(CSR_PMPADDR3);
|
||||
break;
|
||||
case CSR_PMPADDR4:
|
||||
ret = csr_read(CSR_PMPADDR4);
|
||||
break;
|
||||
case CSR_PMPADDR5:
|
||||
ret = csr_read(CSR_PMPADDR5);
|
||||
break;
|
||||
case CSR_PMPADDR6:
|
||||
ret = csr_read(CSR_PMPADDR6);
|
||||
break;
|
||||
case CSR_PMPADDR7:
|
||||
ret = csr_read(CSR_PMPADDR7);
|
||||
break;
|
||||
case CSR_PMPADDR8:
|
||||
ret = csr_read(CSR_PMPADDR8);
|
||||
break;
|
||||
case CSR_PMPADDR9:
|
||||
ret = csr_read(CSR_PMPADDR9);
|
||||
break;
|
||||
case CSR_PMPADDR10:
|
||||
ret = csr_read(CSR_PMPADDR10);
|
||||
break;
|
||||
case CSR_PMPADDR11:
|
||||
ret = csr_read(CSR_PMPADDR11);
|
||||
break;
|
||||
case CSR_PMPADDR12:
|
||||
ret = csr_read(CSR_PMPADDR12);
|
||||
break;
|
||||
case CSR_PMPADDR13:
|
||||
ret = csr_read(CSR_PMPADDR13);
|
||||
break;
|
||||
case CSR_PMPADDR14:
|
||||
ret = csr_read(CSR_PMPADDR14);
|
||||
break;
|
||||
case CSR_PMPADDR15:
|
||||
ret = csr_read(CSR_PMPADDR15);
|
||||
break;
|
||||
switchcase_csr_read_16(CSR_PMPCFG0, ret)
|
||||
switchcase_csr_read_64(CSR_PMPADDR0, ret)
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
return ret;
|
||||
|
||||
#undef switchcase_csr_read_64
|
||||
#undef switchcase_csr_read_32
|
||||
#undef switchcase_csr_read_16
|
||||
#undef switchcase_csr_read_8
|
||||
#undef switchcase_csr_read_4
|
||||
#undef switchcase_csr_read_2
|
||||
#undef switchcase_csr_read
|
||||
}
|
||||
|
||||
void csr_write_num(int csr_num, unsigned long val)
|
||||
{
|
||||
#define switchcase_csr_write(__csr_num, __val) \
|
||||
case __csr_num: \
|
||||
csr_write(__csr_num, __val); \
|
||||
break;
|
||||
#define switchcase_csr_write_2(__csr_num, __val) \
|
||||
switchcase_csr_write(__csr_num + 0, __val) \
|
||||
switchcase_csr_write(__csr_num + 1, __val)
|
||||
#define switchcase_csr_write_4(__csr_num, __val) \
|
||||
switchcase_csr_write_2(__csr_num + 0, __val) \
|
||||
switchcase_csr_write_2(__csr_num + 2, __val)
|
||||
#define switchcase_csr_write_8(__csr_num, __val) \
|
||||
switchcase_csr_write_4(__csr_num + 0, __val) \
|
||||
switchcase_csr_write_4(__csr_num + 4, __val)
|
||||
#define switchcase_csr_write_16(__csr_num, __val) \
|
||||
switchcase_csr_write_8(__csr_num + 0, __val) \
|
||||
switchcase_csr_write_8(__csr_num + 8, __val)
|
||||
#define switchcase_csr_write_32(__csr_num, __val) \
|
||||
switchcase_csr_write_16(__csr_num + 0, __val) \
|
||||
switchcase_csr_write_16(__csr_num + 16, __val)
|
||||
#define switchcase_csr_write_64(__csr_num, __val) \
|
||||
switchcase_csr_write_32(__csr_num + 0, __val) \
|
||||
switchcase_csr_write_32(__csr_num + 32, __val)
|
||||
|
||||
switch (csr_num) {
|
||||
case CSR_PMPCFG0:
|
||||
csr_write(CSR_PMPCFG0, val);
|
||||
break;
|
||||
case CSR_PMPCFG1:
|
||||
csr_write(CSR_PMPCFG1, val);
|
||||
break;
|
||||
case CSR_PMPCFG2:
|
||||
csr_write(CSR_PMPCFG2, val);
|
||||
break;
|
||||
case CSR_PMPCFG3:
|
||||
csr_write(CSR_PMPCFG3, val);
|
||||
break;
|
||||
case CSR_PMPADDR0:
|
||||
csr_write(CSR_PMPADDR0, val);
|
||||
break;
|
||||
case CSR_PMPADDR1:
|
||||
csr_write(CSR_PMPADDR1, val);
|
||||
break;
|
||||
case CSR_PMPADDR2:
|
||||
csr_write(CSR_PMPADDR2, val);
|
||||
break;
|
||||
case CSR_PMPADDR3:
|
||||
csr_write(CSR_PMPADDR3, val);
|
||||
break;
|
||||
case CSR_PMPADDR4:
|
||||
csr_write(CSR_PMPADDR4, val);
|
||||
break;
|
||||
case CSR_PMPADDR5:
|
||||
csr_write(CSR_PMPADDR5, val);
|
||||
break;
|
||||
case CSR_PMPADDR6:
|
||||
csr_write(CSR_PMPADDR6, val);
|
||||
break;
|
||||
case CSR_PMPADDR7:
|
||||
csr_write(CSR_PMPADDR7, val);
|
||||
break;
|
||||
case CSR_PMPADDR8:
|
||||
csr_write(CSR_PMPADDR8, val);
|
||||
break;
|
||||
case CSR_PMPADDR9:
|
||||
csr_write(CSR_PMPADDR9, val);
|
||||
break;
|
||||
case CSR_PMPADDR10:
|
||||
csr_write(CSR_PMPADDR10, val);
|
||||
break;
|
||||
case CSR_PMPADDR11:
|
||||
csr_write(CSR_PMPADDR11, val);
|
||||
break;
|
||||
case CSR_PMPADDR12:
|
||||
csr_write(CSR_PMPADDR12, val);
|
||||
break;
|
||||
case CSR_PMPADDR13:
|
||||
csr_write(CSR_PMPADDR13, val);
|
||||
break;
|
||||
case CSR_PMPADDR14:
|
||||
csr_write(CSR_PMPADDR14, val);
|
||||
break;
|
||||
case CSR_PMPADDR15:
|
||||
csr_write(CSR_PMPADDR15, val);
|
||||
break;
|
||||
switchcase_csr_write_16(CSR_PMPCFG0, val)
|
||||
switchcase_csr_write_64(CSR_PMPADDR0, val)
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
#undef switchcase_csr_write_64
|
||||
#undef switchcase_csr_write_32
|
||||
#undef switchcase_csr_write_16
|
||||
#undef switchcase_csr_write_8
|
||||
#undef switchcase_csr_write_4
|
||||
#undef switchcase_csr_write_2
|
||||
#undef switchcase_csr_write
|
||||
}
|
||||
|
||||
static unsigned long ctz(unsigned long x)
|
||||
@@ -293,16 +239,16 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
|
||||
}
|
||||
|
||||
int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
|
||||
unsigned long *size)
|
||||
unsigned long *log2len)
|
||||
{
|
||||
int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr;
|
||||
unsigned long cfgmask, pmpcfg, prot;
|
||||
unsigned long t1, addr, log2len;
|
||||
unsigned long t1, addr, len;
|
||||
|
||||
/* check parameters */
|
||||
if (n >= PMP_COUNT || !prot_out || !addr_out || !size)
|
||||
if (n >= PMP_COUNT || !prot_out || !addr_out || !log2len)
|
||||
return SBI_EINVAL;
|
||||
*prot_out = *addr_out = *size = 0;
|
||||
*prot_out = *addr_out = *log2len = 0;
|
||||
|
||||
/* calculate PMP register and offset */
|
||||
#if __riscv_xlen == 32
|
||||
@@ -329,23 +275,21 @@ int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
|
||||
addr = csr_read_num(pmpaddr_csr);
|
||||
if (addr == -1UL) {
|
||||
addr = 0;
|
||||
log2len = __riscv_xlen;
|
||||
len = __riscv_xlen;
|
||||
} else {
|
||||
t1 = ctz(~addr);
|
||||
addr = (addr & ~((1UL << t1) - 1)) << PMP_SHIFT;
|
||||
log2len = (t1 + PMP_SHIFT + 1);
|
||||
len = (t1 + PMP_SHIFT + 1);
|
||||
}
|
||||
} else {
|
||||
addr = csr_read_num(pmpaddr_csr) << PMP_SHIFT;
|
||||
log2len = PMP_SHIFT;
|
||||
len = PMP_SHIFT;
|
||||
}
|
||||
|
||||
/* return details */
|
||||
*prot_out = prot;
|
||||
*addr_out = addr;
|
||||
|
||||
if (log2len < __riscv_xlen)
|
||||
*size = (1UL << log2len);
|
||||
*log2len = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
539
lib/sbi/sbi_domain.c
Normal file
539
lib/sbi/sbi_domain.c
Normal file
@@ -0,0 +1,539 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_domain.h>
|
||||
#include <sbi/sbi_hartmask.h>
|
||||
#include <sbi/sbi_hsm.h>
|
||||
#include <sbi/sbi_math.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/sbi_string.h>
|
||||
|
||||
struct sbi_domain *hartid_to_domain_table[SBI_HARTMASK_MAX_BITS] = { 0 };
|
||||
struct sbi_domain *domidx_to_domain_table[SBI_DOMAIN_MAX_INDEX] = { 0 };
|
||||
|
||||
static u32 domain_count = 0;
|
||||
|
||||
static struct sbi_hartmask root_hmask = { 0 };
|
||||
|
||||
#define ROOT_FW_REGION 0
|
||||
#define ROOT_ALL_REGION 1
|
||||
#define ROOT_END_REGION 2
|
||||
static struct sbi_domain_memregion root_memregs[ROOT_END_REGION + 1] = { 0 };
|
||||
|
||||
static struct sbi_domain root = {
|
||||
.name = "root",
|
||||
.possible_harts = &root_hmask,
|
||||
.regions = root_memregs,
|
||||
.system_reset_allowed = TRUE,
|
||||
};
|
||||
|
||||
bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid)
|
||||
{
|
||||
if (dom)
|
||||
return sbi_hartmask_test_hart(hartid, &dom->assigned_harts);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ulong sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom,
|
||||
ulong hbase)
|
||||
{
|
||||
ulong ret, bword, boff;
|
||||
|
||||
if (!dom)
|
||||
return 0;
|
||||
|
||||
bword = BIT_WORD(hbase);
|
||||
boff = BIT_WORD_OFFSET(hbase);
|
||||
|
||||
ret = sbi_hartmask_bits(&dom->assigned_harts)[bword++] >> boff;
|
||||
if (boff && bword < BIT_WORD(SBI_HARTMASK_MAX_BITS)) {
|
||||
ret |= (sbi_hartmask_bits(&dom->assigned_harts)[bword] &
|
||||
(BIT(boff) - 1UL)) << (BITS_PER_LONG - boff);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void sbi_domain_memregion_initfw(struct sbi_domain_memregion *reg)
|
||||
{
|
||||
if (!reg)
|
||||
return;
|
||||
|
||||
sbi_memcpy(reg, &root_memregs[ROOT_FW_REGION], sizeof(*reg));
|
||||
}
|
||||
|
||||
bool sbi_domain_check_addr(const struct sbi_domain *dom,
|
||||
unsigned long addr, unsigned long mode,
|
||||
unsigned long access_flags)
|
||||
{
|
||||
bool mmio = FALSE;
|
||||
struct sbi_domain_memregion *reg;
|
||||
unsigned long rstart, rend, rflags, rwx = 0;
|
||||
|
||||
if (!dom)
|
||||
return FALSE;
|
||||
|
||||
if (access_flags & SBI_DOMAIN_READ)
|
||||
rwx |= SBI_DOMAIN_MEMREGION_READABLE;
|
||||
if (access_flags & SBI_DOMAIN_WRITE)
|
||||
rwx |= SBI_DOMAIN_MEMREGION_WRITEABLE;
|
||||
if (access_flags & SBI_DOMAIN_EXECUTE)
|
||||
rwx |= SBI_DOMAIN_MEMREGION_EXECUTABLE;
|
||||
if (access_flags & SBI_DOMAIN_MMIO)
|
||||
mmio = TRUE;
|
||||
|
||||
sbi_domain_for_each_memregion(dom, reg) {
|
||||
rflags = reg->flags;
|
||||
if (mode == PRV_M && !(rflags & SBI_DOMAIN_MEMREGION_MMODE))
|
||||
continue;
|
||||
|
||||
rstart = reg->base;
|
||||
rend = (reg->order < __riscv_xlen) ?
|
||||
rstart + ((1UL << reg->order) - 1) : -1UL;
|
||||
if (rstart <= addr && addr <= rend) {
|
||||
if ((mmio && !(rflags & SBI_DOMAIN_MEMREGION_MMIO)) ||
|
||||
(!mmio && (rflags & SBI_DOMAIN_MEMREGION_MMIO)))
|
||||
return FALSE;
|
||||
return ((rflags & rwx) == rwx) ? TRUE : FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return (mode == PRV_M) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/* Check if region complies with constraints */
|
||||
static bool is_region_valid(const struct sbi_domain_memregion *reg)
|
||||
{
|
||||
if (reg->order < 3 || __riscv_xlen < reg->order)
|
||||
return FALSE;
|
||||
|
||||
if (reg->base & (BIT(reg->order) - 1))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/** Check if regionA is sub-region of regionB */
|
||||
static bool is_region_subset(const struct sbi_domain_memregion *regA,
|
||||
const struct sbi_domain_memregion *regB)
|
||||
{
|
||||
ulong regA_start = regA->base;
|
||||
ulong regA_end = regA->base + (BIT(regA->order) - 1);
|
||||
ulong regB_start = regB->base;
|
||||
ulong regB_end = regB->base + (BIT(regA->order) - 1);
|
||||
|
||||
if ((regB_start <= regA_start) &&
|
||||
(regA_start < regB_end) &&
|
||||
(regB_start < regA_end) &&
|
||||
(regA_end <= regB_end))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/** Check if regionA conflicts regionB */
|
||||
static bool is_region_conflict(const struct sbi_domain_memregion *regA,
|
||||
const struct sbi_domain_memregion *regB)
|
||||
{
|
||||
if ((is_region_subset(regA, regB) || is_region_subset(regB, regA)) &&
|
||||
regA->flags == regB->flags)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/** Check if regionA should be placed before regionB */
|
||||
static bool is_region_before(const struct sbi_domain_memregion *regA,
|
||||
const struct sbi_domain_memregion *regB)
|
||||
{
|
||||
if (regA->order < regB->order)
|
||||
return TRUE;
|
||||
|
||||
if ((regA->order == regB->order) &&
|
||||
(regA->base < regB->base))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int sanitize_domain(const struct sbi_platform *plat,
|
||||
struct sbi_domain *dom)
|
||||
{
|
||||
u32 i, j, count;
|
||||
bool have_fw_reg;
|
||||
struct sbi_domain_memregion treg, *reg, *reg1;
|
||||
|
||||
/* Check possible HARTs */
|
||||
if (!dom->possible_harts) {
|
||||
sbi_printf("%s: %s possible HART mask is NULL\n",
|
||||
__func__, dom->name);
|
||||
return SBI_EINVAL;
|
||||
}
|
||||
sbi_hartmask_for_each_hart(i, dom->possible_harts) {
|
||||
if (sbi_platform_hart_invalid(plat, i)) {
|
||||
sbi_printf("%s: %s possible HART mask has invalid "
|
||||
"hart %d\n", __func__, dom->name, i);
|
||||
return SBI_EINVAL;
|
||||
}
|
||||
};
|
||||
|
||||
/* Check memory regions */
|
||||
if (!dom->regions) {
|
||||
sbi_printf("%s: %s regions is NULL\n",
|
||||
__func__, dom->name);
|
||||
return SBI_EINVAL;
|
||||
}
|
||||
sbi_domain_for_each_memregion(dom, reg) {
|
||||
if (!is_region_valid(reg)) {
|
||||
sbi_printf("%s: %s has invalid region base=0x%lx "
|
||||
"order=%lu flags=0x%lx\n", __func__,
|
||||
dom->name, reg->base, reg->order,
|
||||
reg->flags);
|
||||
return SBI_EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Count memory regions and check presence of firmware region */
|
||||
count = 0;
|
||||
have_fw_reg = FALSE;
|
||||
sbi_domain_for_each_memregion(dom, reg) {
|
||||
if (reg->order == root_memregs[ROOT_FW_REGION].order &&
|
||||
reg->base == root_memregs[ROOT_FW_REGION].base &&
|
||||
reg->flags == root_memregs[ROOT_FW_REGION].flags)
|
||||
have_fw_reg = TRUE;
|
||||
count++;
|
||||
}
|
||||
if (!have_fw_reg) {
|
||||
sbi_printf("%s: %s does not have firmware region\n",
|
||||
__func__, dom->name);
|
||||
return SBI_EINVAL;
|
||||
}
|
||||
|
||||
/* Sort the memory regions */
|
||||
for (i = 0; i < (count - 1); i++) {
|
||||
reg = &dom->regions[i];
|
||||
for (j = i + 1; j < count; j++) {
|
||||
reg1 = &dom->regions[j];
|
||||
|
||||
if (is_region_conflict(reg1, reg)) {
|
||||
sbi_printf("%s: %s conflict between regions "
|
||||
"(base=0x%lx order=%lu flags=0x%lx) and "
|
||||
"(base=0x%lx order=%lu flags=0x%lx)\n",
|
||||
__func__, dom->name,
|
||||
reg->base, reg->order, reg->flags,
|
||||
reg1->base, reg1->order, reg1->flags);
|
||||
return SBI_EINVAL;
|
||||
}
|
||||
|
||||
if (!is_region_before(reg1, reg))
|
||||
continue;
|
||||
|
||||
sbi_memcpy(&treg, reg1, sizeof(treg));
|
||||
sbi_memcpy(reg1, reg, sizeof(treg));
|
||||
sbi_memcpy(reg, &treg, sizeof(treg));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't need to check boot HART id of domain because if boot
|
||||
* HART id is not possible/assigned to this domain then it won't
|
||||
* be started at boot-time by sbi_domain_finalize().
|
||||
*/
|
||||
|
||||
/*
|
||||
* Check next mode
|
||||
*
|
||||
* We only allow next mode to be S-mode or U-mode.so that we can
|
||||
* protect M-mode context and enforce checks on memory accesses.
|
||||
*/
|
||||
if (dom->next_mode != PRV_S &&
|
||||
dom->next_mode != PRV_U) {
|
||||
sbi_printf("%s: %s invalid next booting stage mode 0x%lx\n",
|
||||
__func__, dom->name, dom->next_mode);
|
||||
return SBI_EINVAL;
|
||||
}
|
||||
|
||||
/* Check next address and next mode*/
|
||||
if (!sbi_domain_check_addr(dom, dom->next_addr, dom->next_mode,
|
||||
SBI_DOMAIN_EXECUTE)) {
|
||||
sbi_printf("%s: %s next booting stage addres 0x%lx can't "
|
||||
"execute\n", __func__, dom->name, dom->next_addr);
|
||||
return SBI_EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
|
||||
{
|
||||
u32 i, k;
|
||||
unsigned long rstart, rend;
|
||||
struct sbi_domain_memregion *reg;
|
||||
|
||||
sbi_printf("Domain%d Name %s: %s\n",
|
||||
dom->index, suffix, dom->name);
|
||||
|
||||
sbi_printf("Domain%d Boot HART %s: %d\n",
|
||||
dom->index, suffix, dom->boot_hartid);
|
||||
|
||||
k = 0;
|
||||
sbi_printf("Domain%d HARTs %s: ", dom->index, suffix);
|
||||
sbi_hartmask_for_each_hart(i, dom->possible_harts)
|
||||
sbi_printf("%s%d%s", (k++) ? "," : "",
|
||||
i, sbi_domain_is_assigned_hart(dom, i) ? "*" : "");
|
||||
sbi_printf("\n");
|
||||
|
||||
i = 0;
|
||||
sbi_domain_for_each_memregion(dom, reg) {
|
||||
rstart = reg->base;
|
||||
rend = (reg->order < __riscv_xlen) ?
|
||||
rstart + ((1UL << reg->order) - 1) : -1UL;
|
||||
|
||||
#if __riscv_xlen == 32
|
||||
sbi_printf("Domain%d Region%02d %s: 0x%08lx-0x%08lx ",
|
||||
#else
|
||||
sbi_printf("Domain%d Region%02d %s: 0x%016lx-0x%016lx ",
|
||||
#endif
|
||||
dom->index, i, suffix, rstart, rend);
|
||||
|
||||
k = 0;
|
||||
if (reg->flags & SBI_DOMAIN_MEMREGION_MMODE)
|
||||
sbi_printf("%cM", (k++) ? ',' : '(');
|
||||
if (reg->flags & SBI_DOMAIN_MEMREGION_MMIO)
|
||||
sbi_printf("%cI", (k++) ? ',' : '(');
|
||||
if (reg->flags & SBI_DOMAIN_MEMREGION_READABLE)
|
||||
sbi_printf("%cR", (k++) ? ',' : '(');
|
||||
if (reg->flags & SBI_DOMAIN_MEMREGION_WRITEABLE)
|
||||
sbi_printf("%cW", (k++) ? ',' : '(');
|
||||
if (reg->flags & SBI_DOMAIN_MEMREGION_EXECUTABLE)
|
||||
sbi_printf("%cX", (k++) ? ',' : '(');
|
||||
sbi_printf("%s\n", (k++) ? ")" : "()");
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
#if __riscv_xlen == 32
|
||||
sbi_printf("Domain%d Next Address%s: 0x%08lx\n",
|
||||
#else
|
||||
sbi_printf("Domain%d Next Address%s: 0x%016lx\n",
|
||||
#endif
|
||||
dom->index, suffix, dom->next_addr);
|
||||
|
||||
#if __riscv_xlen == 32
|
||||
sbi_printf("Domain%d Next Arg1 %s: 0x%08lx\n",
|
||||
#else
|
||||
sbi_printf("Domain%d Next Arg1 %s: 0x%016lx\n",
|
||||
#endif
|
||||
dom->index, suffix, dom->next_arg1);
|
||||
|
||||
sbi_printf("Domain%d Next Mode %s: ", dom->index, suffix);
|
||||
switch (dom->next_mode) {
|
||||
case PRV_M:
|
||||
sbi_printf("M-mode\n");
|
||||
break;
|
||||
case PRV_S:
|
||||
sbi_printf("S-mode\n");
|
||||
break;
|
||||
case PRV_U:
|
||||
sbi_printf("U-mode\n");
|
||||
break;
|
||||
default:
|
||||
sbi_printf("Unknown\n");
|
||||
break;
|
||||
};
|
||||
|
||||
sbi_printf("Domain%d SysReset %s: %s\n",
|
||||
dom->index, suffix, (dom->system_reset_allowed) ? "yes" : "no");
|
||||
}
|
||||
|
||||
void sbi_domain_dump_all(const char *suffix)
|
||||
{
|
||||
u32 i;
|
||||
const struct sbi_domain *dom;
|
||||
|
||||
sbi_domain_for_each(i, dom) {
|
||||
sbi_domain_dump(dom, suffix);
|
||||
sbi_printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
int sbi_domain_register(struct sbi_domain *dom,
|
||||
const struct sbi_hartmask *assign_mask)
|
||||
{
|
||||
u32 i;
|
||||
int rc;
|
||||
struct sbi_domain *tdom;
|
||||
u32 cold_hartid = current_hartid();
|
||||
const struct sbi_platform *plat = sbi_platform_thishart_ptr();
|
||||
|
||||
if (!dom || !assign_mask)
|
||||
return SBI_EINVAL;
|
||||
|
||||
/* Check if domain already discovered */
|
||||
sbi_domain_for_each(i, tdom) {
|
||||
if (tdom == dom)
|
||||
return SBI_EALREADY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure that we have room for Domain Index to
|
||||
* HART ID mapping
|
||||
*/
|
||||
if (SBI_DOMAIN_MAX_INDEX <= domain_count) {
|
||||
sbi_printf("%s: No room for %s\n",
|
||||
__func__, dom->name);
|
||||
return SBI_ENOSPC;
|
||||
}
|
||||
|
||||
/* Sanitize discovered domain */
|
||||
rc = sanitize_domain(plat, dom);
|
||||
if (rc) {
|
||||
sbi_printf("%s: sanity checks failed for"
|
||||
" %s (error %d)\n", __func__,
|
||||
dom->name, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Assign index to domain */
|
||||
dom->index = domain_count++;
|
||||
domidx_to_domain_table[dom->index] = dom;
|
||||
|
||||
/* Clear assigned HARTs of domain */
|
||||
sbi_hartmask_clear_all(&dom->assigned_harts);
|
||||
|
||||
/* Assign domain to HART if HART is a possible HART */
|
||||
sbi_hartmask_for_each_hart(i, assign_mask) {
|
||||
if (!sbi_hartmask_test_hart(i, dom->possible_harts))
|
||||
continue;
|
||||
|
||||
tdom = hartid_to_domain_table[i];
|
||||
if (tdom)
|
||||
sbi_hartmask_clear_hart(i,
|
||||
&tdom->assigned_harts);
|
||||
hartid_to_domain_table[i] = dom;
|
||||
sbi_hartmask_set_hart(i, &dom->assigned_harts);
|
||||
|
||||
/*
|
||||
* If cold boot HART is assigned to this domain then
|
||||
* override boot HART of this domain.
|
||||
*/
|
||||
if (i == cold_hartid &&
|
||||
dom->boot_hartid != cold_hartid) {
|
||||
sbi_printf("Domain%d Boot HARTID forced to"
|
||||
" %d\n", dom->index, cold_hartid);
|
||||
dom->boot_hartid = cold_hartid;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
|
||||
{
|
||||
int rc;
|
||||
u32 i, dhart;
|
||||
struct sbi_domain *dom;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
/* Initialize and populate domains for the platform */
|
||||
rc = sbi_platform_domains_init(plat);
|
||||
if (rc) {
|
||||
sbi_printf("%s: platform domains_init() failed (error %d)\n",
|
||||
__func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Startup boot HART of domains */
|
||||
sbi_domain_for_each(i, dom) {
|
||||
/* Domain boot HART */
|
||||
dhart = dom->boot_hartid;
|
||||
|
||||
/* Ignore of boot HART is off limits */
|
||||
if (SBI_HARTMASK_MAX_BITS <= dhart)
|
||||
continue;
|
||||
|
||||
/* Ignore if boot HART not possible for this domain */
|
||||
if (!sbi_hartmask_test_hart(dhart, dom->possible_harts))
|
||||
continue;
|
||||
|
||||
/* Ignore if boot HART assigned different domain */
|
||||
if (sbi_hartid_to_domain(dhart) != dom ||
|
||||
!sbi_hartmask_test_hart(dhart, &dom->assigned_harts))
|
||||
continue;
|
||||
|
||||
/* Startup boot HART of domain */
|
||||
if (dhart == cold_hartid) {
|
||||
scratch->next_addr = dom->next_addr;
|
||||
scratch->next_mode = dom->next_mode;
|
||||
scratch->next_arg1 = dom->next_arg1;
|
||||
} else {
|
||||
rc = sbi_hsm_hart_start(scratch, NULL, dhart,
|
||||
dom->next_addr,
|
||||
dom->next_mode,
|
||||
dom->next_arg1);
|
||||
if (rc) {
|
||||
sbi_printf("%s: failed to start boot HART %d"
|
||||
" for %s (error %d)\n", __func__,
|
||||
dhart, dom->name, rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
|
||||
{
|
||||
u32 i;
|
||||
struct sbi_domain_memregion *memregs;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
/* Root domain firmware memory region */
|
||||
root_memregs[ROOT_FW_REGION].order = log2roundup(scratch->fw_size);
|
||||
root_memregs[ROOT_FW_REGION].base = scratch->fw_start &
|
||||
~((1UL << root_memregs[0].order) - 1UL);
|
||||
root_memregs[ROOT_FW_REGION].flags = 0;
|
||||
|
||||
/* Root domain allow everything memory region */
|
||||
root_memregs[ROOT_ALL_REGION].order = __riscv_xlen;
|
||||
root_memregs[ROOT_ALL_REGION].base = 0;
|
||||
root_memregs[ROOT_ALL_REGION].flags = (SBI_DOMAIN_MEMREGION_READABLE |
|
||||
SBI_DOMAIN_MEMREGION_WRITEABLE |
|
||||
SBI_DOMAIN_MEMREGION_EXECUTABLE);
|
||||
|
||||
/* Root domain memory region end */
|
||||
root_memregs[ROOT_END_REGION].order = 0;
|
||||
|
||||
/* Use platform specific root memory regions when available */
|
||||
memregs = sbi_platform_domains_root_regions(plat);
|
||||
if (memregs)
|
||||
root.regions = memregs;
|
||||
|
||||
/* Root domain boot HART id is same as coldboot HART id */
|
||||
root.boot_hartid = cold_hartid;
|
||||
|
||||
/* Root domain next booting stage details */
|
||||
root.next_arg1 = scratch->next_arg1;
|
||||
root.next_addr = scratch->next_addr;
|
||||
root.next_mode = scratch->next_mode;
|
||||
|
||||
/* Root domain possible and assigned HARTs */
|
||||
for (i = 0; i < SBI_HARTMASK_MAX_BITS; i++) {
|
||||
if (sbi_platform_hart_invalid(plat, i))
|
||||
continue;
|
||||
sbi_hartmask_set_hart(i, &root_hmask);
|
||||
}
|
||||
|
||||
return sbi_domain_register(&root, &root_hmask);
|
||||
}
|
@@ -101,19 +101,11 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs)
|
||||
struct sbi_trap_info trap = {0};
|
||||
unsigned long out_val = 0;
|
||||
bool is_0_1_spec = 0;
|
||||
unsigned long args[6];
|
||||
|
||||
args[0] = regs->a0;
|
||||
args[1] = regs->a1;
|
||||
args[2] = regs->a2;
|
||||
args[3] = regs->a3;
|
||||
args[4] = regs->a4;
|
||||
args[5] = regs->a5;
|
||||
|
||||
ext = sbi_ecall_find_extension(extension_id);
|
||||
if (ext && ext->handle) {
|
||||
ret = ext->handle(extension_id, func_id,
|
||||
args, &out_val, &trap);
|
||||
regs, &out_val, &trap);
|
||||
if (extension_id >= SBI_EXT_0_1_SET_TIMER &&
|
||||
extension_id <= SBI_EXT_0_1_SHUTDOWN)
|
||||
is_0_1_spec = 1;
|
||||
@@ -167,6 +159,9 @@ int sbi_ecall_init(void)
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = sbi_ecall_register_extension(&ecall_hsm);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = sbi_ecall_register_extension(&ecall_srst);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = sbi_ecall_register_extension(&ecall_legacy);
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
#include <sbi/sbi_version.h>
|
||||
#include <sbi/riscv_asm.h>
|
||||
|
||||
@@ -32,7 +33,8 @@ static int sbi_ecall_base_probe(unsigned long extid, unsigned long *out_val)
|
||||
}
|
||||
|
||||
static int sbi_ecall_base_handler(unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
const struct sbi_trap_regs *regs,
|
||||
unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -61,7 +63,7 @@ static int sbi_ecall_base_handler(unsigned long extid, unsigned long funcid,
|
||||
*out_val = csr_read(CSR_MIMPID);
|
||||
break;
|
||||
case SBI_EXT_BASE_PROBE_EXT:
|
||||
ret = sbi_ecall_base_probe(args[0], out_val);
|
||||
ret = sbi_ecall_base_probe(regs->a0, out_val);
|
||||
break;
|
||||
default:
|
||||
ret = SBI_ENOTSUPP;
|
||||
|
@@ -7,30 +7,38 @@
|
||||
* Atish Patra <atish.patra@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/sbi_domain.h>
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
#include <sbi/sbi_version.h>
|
||||
#include <sbi/sbi_hsm.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/riscv_asm.h>
|
||||
|
||||
static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
const struct sbi_trap_regs *regs,
|
||||
unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
ulong smode;
|
||||
int ret = 0, hstate;
|
||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||
|
||||
switch (funcid) {
|
||||
case SBI_EXT_HSM_HART_START:
|
||||
ret = sbi_hsm_hart_start(scratch, args[0], args[1], args[2]);
|
||||
smode = csr_read(CSR_MSTATUS);
|
||||
smode = (smode & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
|
||||
ret = sbi_hsm_hart_start(scratch, sbi_domain_thishart_ptr(),
|
||||
regs->a0, regs->a1, smode, regs->a2);
|
||||
break;
|
||||
case SBI_EXT_HSM_HART_STOP:
|
||||
ret = sbi_hsm_hart_stop(scratch, TRUE);
|
||||
break;
|
||||
case SBI_EXT_HSM_HART_GET_STATUS:
|
||||
hstate = sbi_hsm_hart_get_state(args[0]);
|
||||
hstate = sbi_hsm_hart_get_state(sbi_domain_thishart_ptr(),
|
||||
regs->a0);
|
||||
ret = sbi_hsm_hart_state_to_status(hstate);
|
||||
break;
|
||||
default:
|
||||
|
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_domain.h>
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
@@ -33,7 +34,8 @@ static int sbi_load_hart_mask_unpriv(ulong *pmask, ulong *hmask,
|
||||
if (uptrap->cause)
|
||||
return SBI_ETRAP;
|
||||
} else {
|
||||
sbi_hsm_hart_started_mask(0, &mask);
|
||||
sbi_hsm_hart_started_mask(sbi_domain_thishart_ptr(),
|
||||
0, &mask);
|
||||
}
|
||||
*hmask = mask;
|
||||
|
||||
@@ -41,7 +43,8 @@ static int sbi_load_hart_mask_unpriv(ulong *pmask, ulong *hmask,
|
||||
}
|
||||
|
||||
static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
const struct sbi_trap_regs *regs,
|
||||
unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -52,13 +55,13 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
|
||||
switch (extid) {
|
||||
case SBI_EXT_0_1_SET_TIMER:
|
||||
#if __riscv_xlen == 32
|
||||
sbi_timer_event_start((((u64)args[1] << 32) | (u64)args[0]));
|
||||
sbi_timer_event_start((((u64)regs->a1 << 32) | (u64)regs->a0));
|
||||
#else
|
||||
sbi_timer_event_start((u64)args[0]);
|
||||
sbi_timer_event_start((u64)regs->a0);
|
||||
#endif
|
||||
break;
|
||||
case SBI_EXT_0_1_CONSOLE_PUTCHAR:
|
||||
sbi_putc(args[0]);
|
||||
sbi_putc(regs->a0);
|
||||
break;
|
||||
case SBI_EXT_0_1_CONSOLE_GETCHAR:
|
||||
ret = sbi_getc();
|
||||
@@ -67,41 +70,45 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
|
||||
sbi_ipi_clear_smode();
|
||||
break;
|
||||
case SBI_EXT_0_1_SEND_IPI:
|
||||
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
|
||||
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
|
||||
&hmask, out_trap);
|
||||
if (ret != SBI_ETRAP)
|
||||
ret = sbi_ipi_send_smode(hmask, 0);
|
||||
break;
|
||||
case SBI_EXT_0_1_REMOTE_FENCE_I:
|
||||
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
|
||||
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
|
||||
&hmask, out_trap);
|
||||
if (ret != SBI_ETRAP) {
|
||||
SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, 0,
|
||||
SBI_ITLB_FLUSH, source_hart);
|
||||
sbi_tlb_local_fence_i,
|
||||
source_hart);
|
||||
ret = sbi_tlb_request(hmask, 0, &tlb_info);
|
||||
}
|
||||
break;
|
||||
case SBI_EXT_0_1_REMOTE_SFENCE_VMA:
|
||||
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
|
||||
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
|
||||
&hmask, out_trap);
|
||||
if (ret != SBI_ETRAP) {
|
||||
SBI_TLB_INFO_INIT(&tlb_info, args[1], args[2], 0, 0,
|
||||
SBI_TLB_FLUSH_VMA, source_hart);
|
||||
SBI_TLB_INFO_INIT(&tlb_info, regs->a1, regs->a2, 0, 0,
|
||||
sbi_tlb_local_sfence_vma,
|
||||
source_hart);
|
||||
ret = sbi_tlb_request(hmask, 0, &tlb_info);
|
||||
}
|
||||
break;
|
||||
case SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID:
|
||||
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
|
||||
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
|
||||
&hmask, out_trap);
|
||||
if (ret != SBI_ETRAP) {
|
||||
SBI_TLB_INFO_INIT(&tlb_info, args[1], args[2], args[3],
|
||||
0, SBI_TLB_FLUSH_VMA_ASID,
|
||||
SBI_TLB_INFO_INIT(&tlb_info, regs->a1,
|
||||
regs->a2, regs->a3, 0,
|
||||
sbi_tlb_local_sfence_vma_asid,
|
||||
source_hart);
|
||||
ret = sbi_tlb_request(hmask, 0, &tlb_info);
|
||||
}
|
||||
break;
|
||||
case SBI_EXT_0_1_SHUTDOWN:
|
||||
sbi_system_reset(SBI_PLATFORM_RESET_SHUTDOWN);
|
||||
sbi_system_reset(SBI_SRST_RESET_TYPE_SHUTDOWN,
|
||||
SBI_SRST_RESET_REASON_NONE);
|
||||
break;
|
||||
default:
|
||||
ret = SBI_ENOTSUPP;
|
||||
|
@@ -14,20 +14,23 @@
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_ipi.h>
|
||||
#include <sbi/sbi_system.h>
|
||||
#include <sbi/sbi_timer.h>
|
||||
#include <sbi/sbi_tlb.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
|
||||
static int sbi_ecall_time_handler(unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
const struct sbi_trap_regs *regs,
|
||||
unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (funcid == SBI_EXT_TIME_SET_TIMER) {
|
||||
#if __riscv_xlen == 32
|
||||
sbi_timer_event_start((((u64)args[1] << 32) | (u64)args[0]));
|
||||
sbi_timer_event_start((((u64)regs->a1 << 32) | (u64)regs->a0));
|
||||
#else
|
||||
sbi_timer_event_start((u64)args[0]);
|
||||
sbi_timer_event_start((u64)regs->a0);
|
||||
#endif
|
||||
} else
|
||||
ret = SBI_ENOTSUPP;
|
||||
@@ -42,7 +45,8 @@ struct sbi_ecall_extension ecall_time = {
|
||||
};
|
||||
|
||||
static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
const struct sbi_trap_regs *regs,
|
||||
unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -58,42 +62,44 @@ static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
|
||||
switch (funcid) {
|
||||
case SBI_EXT_RFENCE_REMOTE_FENCE_I:
|
||||
SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, 0,
|
||||
SBI_ITLB_FLUSH, source_hart);
|
||||
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
||||
sbi_tlb_local_fence_i, source_hart);
|
||||
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
|
||||
break;
|
||||
case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA:
|
||||
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0, 0,
|
||||
SBI_TLB_FLUSH_GVMA, source_hart);
|
||||
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
||||
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, 0,
|
||||
sbi_tlb_local_hfence_gvma, source_hart);
|
||||
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
|
||||
break;
|
||||
case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID:
|
||||
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0, args[4],
|
||||
SBI_TLB_FLUSH_GVMA_VMID, source_hart);
|
||||
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
||||
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, regs->a4,
|
||||
sbi_tlb_local_hfence_gvma_vmid,
|
||||
source_hart);
|
||||
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
|
||||
break;
|
||||
case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA:
|
||||
vmid = (csr_read(CSR_HGATP) & HGATP_VMID_MASK);
|
||||
vmid = vmid >> HGATP_VMID_SHIFT;
|
||||
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0, vmid,
|
||||
SBI_TLB_FLUSH_VVMA, source_hart);
|
||||
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
||||
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, vmid,
|
||||
sbi_tlb_local_hfence_vvma, source_hart);
|
||||
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
|
||||
break;
|
||||
case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID:
|
||||
vmid = (csr_read(CSR_HGATP) & HGATP_VMID_MASK);
|
||||
vmid = vmid >> HGATP_VMID_SHIFT;
|
||||
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], args[4], vmid,
|
||||
SBI_TLB_FLUSH_VVMA_ASID, source_hart);
|
||||
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
||||
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, regs->a4,
|
||||
vmid, sbi_tlb_local_hfence_vvma_asid,
|
||||
source_hart);
|
||||
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
|
||||
break;
|
||||
case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA:
|
||||
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0, 0,
|
||||
SBI_TLB_FLUSH_VMA, source_hart);
|
||||
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
||||
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, 0,
|
||||
sbi_tlb_local_sfence_vma, source_hart);
|
||||
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
|
||||
break;
|
||||
case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID:
|
||||
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], args[4], 0,
|
||||
SBI_TLB_FLUSH_VMA_ASID, source_hart);
|
||||
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
||||
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, regs->a4, 0,
|
||||
sbi_tlb_local_sfence_vma_asid, source_hart);
|
||||
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
|
||||
break;
|
||||
default:
|
||||
ret = SBI_ENOTSUPP;
|
||||
@@ -109,13 +115,14 @@ struct sbi_ecall_extension ecall_rfence = {
|
||||
};
|
||||
|
||||
static int sbi_ecall_ipi_handler(unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
const struct sbi_trap_regs *regs,
|
||||
unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (funcid == SBI_EXT_IPI_SEND_IPI)
|
||||
ret = sbi_ipi_send_smode(args[0], args[1]);
|
||||
ret = sbi_ipi_send_smode(regs->a0, regs->a1);
|
||||
else
|
||||
ret = SBI_ENOTSUPP;
|
||||
|
||||
@@ -127,3 +134,63 @@ struct sbi_ecall_extension ecall_ipi = {
|
||||
.extid_end = SBI_EXT_IPI,
|
||||
.handle = sbi_ecall_ipi_handler,
|
||||
};
|
||||
|
||||
static int sbi_ecall_srst_handler(unsigned long extid, unsigned long funcid,
|
||||
const struct sbi_trap_regs *regs,
|
||||
unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
if (funcid == SBI_EXT_SRST_RESET) {
|
||||
if ((((u32)-1U) <= ((u64)regs->a0)) ||
|
||||
(((u32)-1U) <= ((u64)regs->a1)))
|
||||
return SBI_EINVAL;
|
||||
|
||||
switch (regs->a0) {
|
||||
case SBI_SRST_RESET_TYPE_SHUTDOWN:
|
||||
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
|
||||
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
|
||||
break;
|
||||
default:
|
||||
return SBI_ENOTSUPP;
|
||||
}
|
||||
|
||||
switch (regs->a1) {
|
||||
case SBI_SRST_RESET_REASON_NONE:
|
||||
case SBI_SRST_RESET_REASON_SYSFAIL:
|
||||
break;
|
||||
default:
|
||||
return SBI_ENOTSUPP;
|
||||
}
|
||||
|
||||
if (sbi_system_reset_supported(regs->a0, regs->a1))
|
||||
sbi_system_reset(regs->a0, regs->a1);
|
||||
}
|
||||
|
||||
return SBI_ENOTSUPP;
|
||||
}
|
||||
|
||||
static int sbi_ecall_srst_probe(unsigned long extid, unsigned long *out_val)
|
||||
{
|
||||
u32 type, count = 0;
|
||||
|
||||
/*
|
||||
* At least one standard reset types should be supported by
|
||||
* the platform for SBI SRST extension to be usable.
|
||||
*/
|
||||
|
||||
for (type = 0; type <= SBI_SRST_RESET_TYPE_LAST; type++) {
|
||||
if (sbi_system_reset_supported(type,
|
||||
SBI_SRST_RESET_REASON_NONE))
|
||||
count++;
|
||||
}
|
||||
|
||||
*out_val = (count) ? 1 : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sbi_ecall_extension ecall_srst = {
|
||||
.extid_start = SBI_EXT_SRST,
|
||||
.extid_end = SBI_EXT_SRST,
|
||||
.handle = sbi_ecall_srst_handler,
|
||||
.probe = sbi_ecall_srst_probe,
|
||||
};
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
|
||||
static int sbi_ecall_vendor_probe(unsigned long extid,
|
||||
unsigned long *out_val)
|
||||
@@ -22,11 +23,12 @@ static int sbi_ecall_vendor_probe(unsigned long extid,
|
||||
}
|
||||
|
||||
static int sbi_ecall_vendor_handler(unsigned long extid, unsigned long funcid,
|
||||
unsigned long *args, unsigned long *out_val,
|
||||
const struct sbi_trap_regs *regs,
|
||||
unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
return sbi_platform_vendor_ext_provider(sbi_platform_thishart_ptr(),
|
||||
extid, funcid, args,
|
||||
extid, funcid, regs,
|
||||
out_val, out_trap);
|
||||
}
|
||||
|
||||
|
@@ -13,14 +13,31 @@
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_emulate_csr.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/sbi_timer.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
|
||||
static bool hpm_allowed(int hpm_num, ulong prev_mode, bool virt)
|
||||
{
|
||||
ulong cen = -1UL;
|
||||
|
||||
if (prev_mode <= PRV_S) {
|
||||
cen &= csr_read(CSR_MCOUNTEREN);
|
||||
if (virt)
|
||||
cen &= csr_read(CSR_HCOUNTEREN);
|
||||
}
|
||||
if (prev_mode == PRV_U)
|
||||
cen &= csr_read(CSR_SCOUNTEREN);
|
||||
|
||||
return ((cen >> hpm_num) & 1) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs,
|
||||
ulong *csr_val)
|
||||
{
|
||||
int ret = 0;
|
||||
ulong cen = -1UL;
|
||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||
ulong prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
|
||||
#if __riscv_xlen == 32
|
||||
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
|
||||
@@ -28,9 +45,6 @@ int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs,
|
||||
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
|
||||
#endif
|
||||
|
||||
if (prev_mode == PRV_U)
|
||||
cen = csr_read(CSR_SCOUNTEREN);
|
||||
|
||||
switch (csr_num) {
|
||||
case CSR_HTIMEDELTA:
|
||||
if (prev_mode == PRV_S && !virt)
|
||||
@@ -39,31 +53,27 @@ int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs,
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
case CSR_CYCLE:
|
||||
if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1))
|
||||
return -1;
|
||||
if (!hpm_allowed(csr_num - CSR_CYCLE, prev_mode, virt))
|
||||
return SBI_ENOTSUPP;
|
||||
*csr_val = csr_read(CSR_MCYCLE);
|
||||
break;
|
||||
case CSR_TIME:
|
||||
if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1))
|
||||
return -1;
|
||||
/*
|
||||
* We emulate TIME CSR for both Host (HS/U-mode) and
|
||||
* Guest (VS/VU-mode).
|
||||
*
|
||||
* Faster TIME CSR reads are critical for good performance
|
||||
* in S-mode software so we don't check CSR permissions.
|
||||
*/
|
||||
*csr_val = (virt) ? sbi_timer_virt_value():
|
||||
sbi_timer_value();
|
||||
break;
|
||||
case CSR_INSTRET:
|
||||
if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
|
||||
return -1;
|
||||
if (!hpm_allowed(csr_num - CSR_CYCLE, prev_mode, virt))
|
||||
return SBI_ENOTSUPP;
|
||||
*csr_val = csr_read(CSR_MINSTRET);
|
||||
break;
|
||||
case CSR_MHPMCOUNTER3:
|
||||
if (!((cen >> (3 + CSR_MHPMCOUNTER3 - CSR_MHPMCOUNTER3)) & 1))
|
||||
return -1;
|
||||
*csr_val = csr_read(CSR_MHPMCOUNTER3);
|
||||
break;
|
||||
case CSR_MHPMCOUNTER4:
|
||||
if (!((cen >> (3 + CSR_MHPMCOUNTER4 - CSR_MHPMCOUNTER3)) & 1))
|
||||
return -1;
|
||||
*csr_val = csr_read(CSR_MHPMCOUNTER4);
|
||||
break;
|
||||
|
||||
#if __riscv_xlen == 32
|
||||
case CSR_HTIMEDELTAH:
|
||||
if (prev_mode == PRV_S && !virt)
|
||||
@@ -72,38 +82,61 @@ int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs,
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
case CSR_CYCLEH:
|
||||
if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1))
|
||||
return -1;
|
||||
if (!hpm_allowed(csr_num - CSR_CYCLEH, prev_mode, virt))
|
||||
return SBI_ENOTSUPP;
|
||||
*csr_val = csr_read(CSR_MCYCLEH);
|
||||
break;
|
||||
case CSR_TIMEH:
|
||||
if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1))
|
||||
return -1;
|
||||
/* Refer comments on TIME CSR above. */
|
||||
*csr_val = (virt) ? sbi_timer_virt_value() >> 32:
|
||||
sbi_timer_value() >> 32;
|
||||
break;
|
||||
case CSR_INSTRETH:
|
||||
if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
|
||||
return -1;
|
||||
if (!hpm_allowed(csr_num - CSR_CYCLEH, prev_mode, virt))
|
||||
return SBI_ENOTSUPP;
|
||||
*csr_val = csr_read(CSR_MINSTRETH);
|
||||
break;
|
||||
case CSR_MHPMCOUNTER3H:
|
||||
if (!((cen >> (3 + CSR_MHPMCOUNTER3 - CSR_MHPMCOUNTER3)) & 1))
|
||||
return -1;
|
||||
*csr_val = csr_read(CSR_MHPMCOUNTER3H);
|
||||
break;
|
||||
case CSR_MHPMCOUNTER4H:
|
||||
if (!((cen >> (3 + CSR_MHPMCOUNTER4 - CSR_MHPMCOUNTER3)) & 1))
|
||||
return -1;
|
||||
*csr_val = csr_read(CSR_MHPMCOUNTER4H);
|
||||
break;
|
||||
#endif
|
||||
case CSR_MHPMEVENT3:
|
||||
*csr_val = csr_read(CSR_MHPMEVENT3);
|
||||
break;
|
||||
case CSR_MHPMEVENT4:
|
||||
*csr_val = csr_read(CSR_MHPMEVENT4);
|
||||
|
||||
#define switchcase_hpm(__uref, __mref, __csr) \
|
||||
case __csr: \
|
||||
if ((sbi_hart_mhpm_count(scratch) + 3) <= (__csr - __uref))\
|
||||
return SBI_ENOTSUPP; \
|
||||
if (!hpm_allowed(__csr - __uref, prev_mode, virt)) \
|
||||
return SBI_ENOTSUPP; \
|
||||
*csr_val = csr_read(__mref + __csr - __uref); \
|
||||
break;
|
||||
#define switchcase_hpm_2(__uref, __mref, __csr) \
|
||||
switchcase_hpm(__uref, __mref, __csr + 0) \
|
||||
switchcase_hpm(__uref, __mref, __csr + 1)
|
||||
#define switchcase_hpm_4(__uref, __mref, __csr) \
|
||||
switchcase_hpm_2(__uref, __mref, __csr + 0) \
|
||||
switchcase_hpm_2(__uref, __mref, __csr + 2)
|
||||
#define switchcase_hpm_8(__uref, __mref, __csr) \
|
||||
switchcase_hpm_4(__uref, __mref, __csr + 0) \
|
||||
switchcase_hpm_4(__uref, __mref, __csr + 4)
|
||||
#define switchcase_hpm_16(__uref, __mref, __csr) \
|
||||
switchcase_hpm_8(__uref, __mref, __csr + 0) \
|
||||
switchcase_hpm_8(__uref, __mref, __csr + 8)
|
||||
|
||||
switchcase_hpm(CSR_CYCLE, CSR_MCYCLE, CSR_HPMCOUNTER3)
|
||||
switchcase_hpm_4(CSR_CYCLE, CSR_MCYCLE, CSR_HPMCOUNTER4)
|
||||
switchcase_hpm_8(CSR_CYCLE, CSR_MCYCLE, CSR_HPMCOUNTER8)
|
||||
switchcase_hpm_16(CSR_CYCLE, CSR_MCYCLE, CSR_HPMCOUNTER16)
|
||||
|
||||
#if __riscv_xlen == 32
|
||||
switchcase_hpm(CSR_CYCLEH, CSR_MCYCLEH, CSR_HPMCOUNTER3H)
|
||||
switchcase_hpm_4(CSR_CYCLEH, CSR_MCYCLEH, CSR_HPMCOUNTER4H)
|
||||
switchcase_hpm_8(CSR_CYCLEH, CSR_MCYCLEH, CSR_HPMCOUNTER8H)
|
||||
switchcase_hpm_16(CSR_CYCLEH, CSR_MCYCLEH, CSR_HPMCOUNTER16H)
|
||||
#endif
|
||||
|
||||
#undef switchcase_hpm_16
|
||||
#undef switchcase_hpm_8
|
||||
#undef switchcase_hpm_4
|
||||
#undef switchcase_hpm_2
|
||||
#undef switchcase_hpm
|
||||
|
||||
default:
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
@@ -134,18 +167,6 @@ int sbi_emulate_csr_write(int csr_num, struct sbi_trap_regs *regs,
|
||||
else
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
case CSR_CYCLE:
|
||||
csr_write(CSR_MCYCLE, csr_val);
|
||||
break;
|
||||
case CSR_INSTRET:
|
||||
csr_write(CSR_MINSTRET, csr_val);
|
||||
break;
|
||||
case CSR_MHPMCOUNTER3:
|
||||
csr_write(CSR_MHPMCOUNTER3, csr_val);
|
||||
break;
|
||||
case CSR_MHPMCOUNTER4:
|
||||
csr_write(CSR_MHPMCOUNTER4, csr_val);
|
||||
break;
|
||||
#if __riscv_xlen == 32
|
||||
case CSR_HTIMEDELTAH:
|
||||
if (prev_mode == PRV_S && !virt)
|
||||
@@ -153,25 +174,7 @@ int sbi_emulate_csr_write(int csr_num, struct sbi_trap_regs *regs,
|
||||
else
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
case CSR_CYCLEH:
|
||||
csr_write(CSR_MCYCLEH, csr_val);
|
||||
break;
|
||||
case CSR_INSTRETH:
|
||||
csr_write(CSR_MINSTRETH, csr_val);
|
||||
break;
|
||||
case CSR_MHPMCOUNTER3H:
|
||||
csr_write(CSR_MHPMCOUNTER3H, csr_val);
|
||||
break;
|
||||
case CSR_MHPMCOUNTER4H:
|
||||
csr_write(CSR_MHPMCOUNTER4H, csr_val);
|
||||
break;
|
||||
#endif
|
||||
case CSR_MHPMEVENT3:
|
||||
csr_write(CSR_MHPMEVENT3, csr_val);
|
||||
break;
|
||||
case CSR_MHPMEVENT4:
|
||||
csr_write(CSR_MHPMEVENT4, csr_val);
|
||||
break;
|
||||
default:
|
||||
ret = SBI_ENOTSUPP;
|
||||
break;
|
||||
|
@@ -13,12 +13,14 @@
|
||||
#include <sbi/riscv_fp.h>
|
||||
#include <sbi/sbi_bitops.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_domain.h>
|
||||
#include <sbi/sbi_csr_detect.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_math.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_string.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
|
||||
extern void __sbi_expected_trap(void);
|
||||
extern void __sbi_expected_trap_hext(void);
|
||||
@@ -28,10 +30,13 @@ void (*sbi_hart_expected_trap)(void) = &__sbi_expected_trap;
|
||||
struct hart_features {
|
||||
unsigned long features;
|
||||
unsigned int pmp_count;
|
||||
unsigned int pmp_addr_bits;
|
||||
unsigned long pmp_gran;
|
||||
unsigned int mhpm_count;
|
||||
};
|
||||
static unsigned long hart_features_offset;
|
||||
|
||||
static void mstatus_init(struct sbi_scratch *scratch, u32 hartid)
|
||||
static void mstatus_init(struct sbi_scratch *scratch)
|
||||
{
|
||||
unsigned long mstatus_val = 0;
|
||||
|
||||
@@ -60,7 +65,7 @@ static void mstatus_init(struct sbi_scratch *scratch, u32 hartid)
|
||||
csr_write(CSR_SATP, 0);
|
||||
}
|
||||
|
||||
static int fp_init(u32 hartid)
|
||||
static int fp_init(struct sbi_scratch *scratch)
|
||||
{
|
||||
#ifdef __riscv_flen
|
||||
int i;
|
||||
@@ -81,7 +86,7 @@ static int fp_init(u32 hartid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
|
||||
static int delegate_traps(struct sbi_scratch *scratch)
|
||||
{
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
unsigned long interrupts, exceptions;
|
||||
@@ -107,7 +112,7 @@ static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
|
||||
* from VS-mode), Guest page faults and Virtual interrupts.
|
||||
*/
|
||||
if (misa_extension('H')) {
|
||||
exceptions |= (1U << CAUSE_SUPERVISOR_ECALL);
|
||||
exceptions |= (1U << CAUSE_VIRTUAL_SUPERVISOR_ECALL);
|
||||
exceptions |= (1U << CAUSE_FETCH_GUEST_PAGE_FAULT);
|
||||
exceptions |= (1U << CAUSE_LOAD_GUEST_PAGE_FAULT);
|
||||
exceptions |= (1U << CAUSE_VIRTUAL_INST_FAULT);
|
||||
@@ -120,21 +125,34 @@ static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sbi_hart_delegation_dump(struct sbi_scratch *scratch)
|
||||
void sbi_hart_delegation_dump(struct sbi_scratch *scratch,
|
||||
const char *prefix, const char *suffix)
|
||||
{
|
||||
if (!misa_extension('S'))
|
||||
/* No delegation possible as mideleg does not exist*/
|
||||
return;
|
||||
|
||||
#if __riscv_xlen == 32
|
||||
sbi_printf("MIDELEG : 0x%08lx\n", csr_read(CSR_MIDELEG));
|
||||
sbi_printf("MEDELEG : 0x%08lx\n", csr_read(CSR_MEDELEG));
|
||||
sbi_printf("%sMIDELEG%s: 0x%08lx\n",
|
||||
prefix, suffix, csr_read(CSR_MIDELEG));
|
||||
sbi_printf("%sMEDELEG%s: 0x%08lx\n",
|
||||
prefix, suffix, 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));
|
||||
sbi_printf("%sMIDELEG%s: 0x%016lx\n",
|
||||
prefix, suffix, csr_read(CSR_MIDELEG));
|
||||
sbi_printf("%sMEDELEG%s: 0x%016lx\n",
|
||||
prefix, suffix, csr_read(CSR_MEDELEG));
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned int sbi_hart_mhpm_count(struct sbi_scratch *scratch)
|
||||
{
|
||||
struct hart_features *hfeatures =
|
||||
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||
|
||||
return hfeatures->mhpm_count;
|
||||
}
|
||||
|
||||
unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch)
|
||||
{
|
||||
struct hart_features *hfeatures =
|
||||
@@ -143,102 +161,61 @@ unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch)
|
||||
return hfeatures->pmp_count;
|
||||
}
|
||||
|
||||
int sbi_hart_pmp_get(struct sbi_scratch *scratch, unsigned int n,
|
||||
unsigned long *prot_out, unsigned long *addr_out,
|
||||
unsigned long *size)
|
||||
unsigned long sbi_hart_pmp_granularity(struct sbi_scratch *scratch)
|
||||
{
|
||||
if (sbi_hart_pmp_count(scratch) <= n)
|
||||
return SBI_EINVAL;
|
||||
struct hart_features *hfeatures =
|
||||
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||
|
||||
return pmp_get(n, prot_out, addr_out, size);
|
||||
return hfeatures->pmp_gran;
|
||||
}
|
||||
|
||||
void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
|
||||
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch)
|
||||
{
|
||||
unsigned long prot, addr, size;
|
||||
unsigned int i, pmp_count;
|
||||
struct hart_features *hfeatures =
|
||||
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||
|
||||
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP))
|
||||
return;
|
||||
|
||||
pmp_count = sbi_hart_pmp_count(scratch);
|
||||
for (i = 0; i < pmp_count; i++) {
|
||||
pmp_get(i, &prot, &addr, &size);
|
||||
if (!(prot & PMP_A))
|
||||
continue;
|
||||
#if __riscv_xlen == 32
|
||||
sbi_printf("PMP%d : 0x%08lx-0x%08lx (A",
|
||||
#else
|
||||
sbi_printf("PMP%d : 0x%016lx-0x%016lx (A",
|
||||
#endif
|
||||
i, addr, addr + size - 1);
|
||||
if (prot & PMP_L)
|
||||
sbi_printf(",L");
|
||||
if (prot & PMP_R)
|
||||
sbi_printf(",R");
|
||||
if (prot & PMP_W)
|
||||
sbi_printf(",W");
|
||||
if (prot & PMP_X)
|
||||
sbi_printf(",X");
|
||||
sbi_printf(")\n");
|
||||
}
|
||||
return hfeatures->pmp_addr_bits;
|
||||
}
|
||||
|
||||
int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long addr,
|
||||
unsigned long attr)
|
||||
int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
|
||||
{
|
||||
unsigned long prot, size, tempaddr;
|
||||
unsigned int i, pmp_count;
|
||||
struct sbi_domain_memregion *reg;
|
||||
struct sbi_domain *dom = sbi_domain_thishart_ptr();
|
||||
unsigned int pmp_idx = 0, pmp_flags, pmp_bits, pmp_gran_log2;
|
||||
unsigned int pmp_count = sbi_hart_pmp_count(scratch);
|
||||
unsigned long pmp_addr = 0, pmp_addr_max = 0;
|
||||
|
||||
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP))
|
||||
return SBI_OK;
|
||||
|
||||
pmp_count = sbi_hart_pmp_count(scratch);
|
||||
for (i = 0; i < pmp_count; i++) {
|
||||
pmp_get(i, &prot, &tempaddr, &size);
|
||||
if (!(prot & PMP_A))
|
||||
continue;
|
||||
if (tempaddr <= addr && addr <= tempaddr + size)
|
||||
if (!(prot & attr))
|
||||
return SBI_EINVALID_ADDR;
|
||||
}
|
||||
|
||||
return SBI_OK;
|
||||
}
|
||||
|
||||
static int pmp_init(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
u32 i, pmp_idx = 0, pmp_count, count;
|
||||
unsigned long fw_start, fw_size_log2;
|
||||
ulong prot, addr, log2size;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP))
|
||||
if (!pmp_count)
|
||||
return 0;
|
||||
|
||||
/* Firmware PMP region to protect OpenSBI firmware */
|
||||
fw_size_log2 = log2roundup(scratch->fw_size);
|
||||
fw_start = scratch->fw_start & ~((1UL << fw_size_log2) - 1UL);
|
||||
pmp_set(pmp_idx++, 0, fw_start, fw_size_log2);
|
||||
pmp_gran_log2 = log2roundup(sbi_hart_pmp_granularity(scratch));
|
||||
pmp_bits = sbi_hart_pmp_addrbits(scratch) - 1;
|
||||
pmp_addr_max = (1UL << pmp_bits) | ((1UL << pmp_bits) - 1);
|
||||
|
||||
/* Platform specific PMP regions */
|
||||
count = sbi_platform_pmp_region_count(plat, hartid);
|
||||
pmp_count = sbi_hart_pmp_count(scratch);
|
||||
for (i = 0; i < count && pmp_idx < (pmp_count - 1); i++) {
|
||||
if (sbi_platform_pmp_region_info(plat, hartid, i, &prot, &addr,
|
||||
&log2size))
|
||||
continue;
|
||||
pmp_set(pmp_idx++, prot, addr, log2size);
|
||||
sbi_domain_for_each_memregion(dom, reg) {
|
||||
if (pmp_count <= pmp_idx)
|
||||
break;
|
||||
|
||||
pmp_flags = 0;
|
||||
if (reg->flags & SBI_DOMAIN_MEMREGION_READABLE)
|
||||
pmp_flags |= PMP_R;
|
||||
if (reg->flags & SBI_DOMAIN_MEMREGION_WRITEABLE)
|
||||
pmp_flags |= PMP_W;
|
||||
if (reg->flags & SBI_DOMAIN_MEMREGION_EXECUTABLE)
|
||||
pmp_flags |= PMP_X;
|
||||
if (reg->flags & SBI_DOMAIN_MEMREGION_MMODE)
|
||||
pmp_flags |= PMP_L;
|
||||
|
||||
pmp_addr = reg->base >> PMP_SHIFT;
|
||||
if (pmp_gran_log2 <= reg->order && pmp_addr < pmp_addr_max)
|
||||
pmp_set(pmp_idx++, pmp_flags, reg->base, reg->order);
|
||||
else {
|
||||
sbi_printf("Can not configure pmp for domain %s", dom->name);
|
||||
sbi_printf("because memory region address %lx or size %lx is not in range\n",
|
||||
reg->base, reg->order);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Default PMP region for allowing S-mode and U-mode access to
|
||||
* memory not covered by:
|
||||
* 1) Firmware PMP region
|
||||
* 2) Platform specific PMP regions
|
||||
*/
|
||||
pmp_set(pmp_idx++, PMP_R | PMP_W | PMP_X, 0, __riscv_xlen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -276,9 +253,6 @@ static inline char *sbi_hart_feature_id2string(unsigned long feature)
|
||||
return NULL;
|
||||
|
||||
switch (feature) {
|
||||
case SBI_HART_HAS_PMP:
|
||||
fstr = "pmp";
|
||||
break;
|
||||
case SBI_HART_HAS_SCOUNTEREN:
|
||||
fstr = "scounteren";
|
||||
break;
|
||||
@@ -338,6 +312,21 @@ done:
|
||||
sbi_strncpy(features_str, "none", nfstr);
|
||||
}
|
||||
|
||||
static unsigned long hart_pmp_get_allowed_addr(void)
|
||||
{
|
||||
unsigned long val = 0;
|
||||
struct sbi_trap_info trap = {0};
|
||||
|
||||
csr_write_allowed(CSR_PMPADDR0, (ulong)&trap, PMP_ADDR_MASK); \
|
||||
if (!trap.cause) {
|
||||
val = csr_read_allowed(CSR_PMPADDR0, (ulong)&trap);
|
||||
if (trap.cause)
|
||||
val = 0;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void hart_detect_features(struct sbi_scratch *scratch)
|
||||
{
|
||||
struct sbi_trap_info trap = {0};
|
||||
@@ -348,36 +337,73 @@ static void hart_detect_features(struct sbi_scratch *scratch)
|
||||
hfeatures = sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||
hfeatures->features = 0;
|
||||
hfeatures->pmp_count = 0;
|
||||
hfeatures->mhpm_count = 0;
|
||||
|
||||
/* Detect if hart supports PMP feature */
|
||||
#define __detect_pmp(__pmp_csr) \
|
||||
val = csr_read_allowed(__pmp_csr, (ulong)&trap); \
|
||||
if (!trap.cause) { \
|
||||
csr_write_allowed(__pmp_csr, (ulong)&trap, val);\
|
||||
if (!trap.cause) \
|
||||
hfeatures->pmp_count++; \
|
||||
#define __check_csr(__csr, __rdonly, __wrval, __field, __skip) \
|
||||
val = csr_read_allowed(__csr, (ulong)&trap); \
|
||||
if (!trap.cause) { \
|
||||
if (__rdonly) { \
|
||||
(hfeatures->__field)++; \
|
||||
} else { \
|
||||
csr_write_allowed(__csr, (ulong)&trap, __wrval);\
|
||||
if (!trap.cause) { \
|
||||
if (csr_swap(__csr, val) == __wrval) \
|
||||
(hfeatures->__field)++; \
|
||||
else \
|
||||
goto __skip; \
|
||||
} else { \
|
||||
goto __skip; \
|
||||
} \
|
||||
} \
|
||||
} else { \
|
||||
goto __skip; \
|
||||
}
|
||||
__detect_pmp(CSR_PMPADDR0);
|
||||
__detect_pmp(CSR_PMPADDR1);
|
||||
__detect_pmp(CSR_PMPADDR2);
|
||||
__detect_pmp(CSR_PMPADDR3);
|
||||
__detect_pmp(CSR_PMPADDR4);
|
||||
__detect_pmp(CSR_PMPADDR5);
|
||||
__detect_pmp(CSR_PMPADDR6);
|
||||
__detect_pmp(CSR_PMPADDR7);
|
||||
__detect_pmp(CSR_PMPADDR8);
|
||||
__detect_pmp(CSR_PMPADDR9);
|
||||
__detect_pmp(CSR_PMPADDR10);
|
||||
__detect_pmp(CSR_PMPADDR11);
|
||||
__detect_pmp(CSR_PMPADDR12);
|
||||
__detect_pmp(CSR_PMPADDR13);
|
||||
__detect_pmp(CSR_PMPADDR14);
|
||||
__detect_pmp(CSR_PMPADDR15);
|
||||
#undef __detect_pmp
|
||||
#define __check_csr_2(__csr, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr(__csr + 0, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr(__csr + 1, __rdonly, __wrval, __field, __skip)
|
||||
#define __check_csr_4(__csr, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr_2(__csr + 0, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr_2(__csr + 2, __rdonly, __wrval, __field, __skip)
|
||||
#define __check_csr_8(__csr, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr_4(__csr + 0, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr_4(__csr + 4, __rdonly, __wrval, __field, __skip)
|
||||
#define __check_csr_16(__csr, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr_8(__csr + 0, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr_8(__csr + 8, __rdonly, __wrval, __field, __skip)
|
||||
#define __check_csr_32(__csr, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr_16(__csr + 0, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr_16(__csr + 16, __rdonly, __wrval, __field, __skip)
|
||||
#define __check_csr_64(__csr, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr_32(__csr + 0, __rdonly, __wrval, __field, __skip) \
|
||||
__check_csr_32(__csr + 32, __rdonly, __wrval, __field, __skip)
|
||||
|
||||
/* Set hart PMP feature if we have at least one PMP region */
|
||||
if (hfeatures->pmp_count)
|
||||
hfeatures->features |= SBI_HART_HAS_PMP;
|
||||
/**
|
||||
* Detect the allowed address bits & granularity. At least PMPADDR0
|
||||
* should be implemented.
|
||||
*/
|
||||
val = hart_pmp_get_allowed_addr();
|
||||
if (val) {
|
||||
hfeatures->pmp_gran = 1 << (__ffs(val) + 2);
|
||||
hfeatures->pmp_addr_bits = __fls(val) + 1;
|
||||
/* Detect number of PMP regions. At least PMPADDR0 should be implemented*/
|
||||
__check_csr_64(CSR_PMPADDR0, 0, val, pmp_count, __pmp_skip);
|
||||
}
|
||||
__pmp_skip:
|
||||
|
||||
/* Detect number of MHPM counters */
|
||||
__check_csr(CSR_MHPMCOUNTER3, 0, 1UL, mhpm_count, __mhpm_skip);
|
||||
__check_csr_4(CSR_MHPMCOUNTER4, 0, 1UL, mhpm_count, __mhpm_skip);
|
||||
__check_csr_8(CSR_MHPMCOUNTER8, 0, 1UL, mhpm_count, __mhpm_skip);
|
||||
__check_csr_16(CSR_MHPMCOUNTER16, 0, 1UL, mhpm_count, __mhpm_skip);
|
||||
__mhpm_skip:
|
||||
|
||||
#undef __check_csr_64
|
||||
#undef __check_csr_32
|
||||
#undef __check_csr_16
|
||||
#undef __check_csr_8
|
||||
#undef __check_csr_4
|
||||
#undef __check_csr_2
|
||||
#undef __check_csr
|
||||
|
||||
/* Detect if hart supports SCOUNTEREN feature */
|
||||
trap.cause = 0;
|
||||
@@ -404,7 +430,7 @@ static void hart_detect_features(struct sbi_scratch *scratch)
|
||||
hfeatures->features |= SBI_HART_HAS_TIME;
|
||||
}
|
||||
|
||||
int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
|
||||
int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||
{
|
||||
int rc;
|
||||
|
||||
@@ -421,17 +447,17 @@ int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
|
||||
|
||||
hart_detect_features(scratch);
|
||||
|
||||
mstatus_init(scratch, hartid);
|
||||
mstatus_init(scratch);
|
||||
|
||||
rc = fp_init(hartid);
|
||||
rc = fp_init(scratch);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = delegate_traps(scratch, hartid);
|
||||
rc = delegate_traps(scratch);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return pmp_init(scratch, hartid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __attribute__((noreturn)) sbi_hart_hang(void)
|
||||
@@ -496,9 +522,11 @@ sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
|
||||
csr_write(CSR_SIE, 0);
|
||||
csr_write(CSR_SATP, 0);
|
||||
} else if (next_mode == PRV_U) {
|
||||
csr_write(CSR_UTVEC, next_addr);
|
||||
csr_write(CSR_USCRATCH, 0);
|
||||
csr_write(CSR_UIE, 0);
|
||||
if (misa_extension('N')) {
|
||||
csr_write(CSR_UTVEC, next_addr);
|
||||
csr_write(CSR_USCRATCH, 0);
|
||||
csr_write(CSR_UIE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
register unsigned long a0 asm("a0") = arg0;
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include <sbi/riscv_atomic.h>
|
||||
#include <sbi/sbi_bitops.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_domain.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
@@ -56,7 +57,7 @@ int sbi_hsm_hart_state_to_status(int state)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sbi_hsm_hart_get_state(u32 hartid)
|
||||
static inline int __sbi_hsm_hart_get_state(u32 hartid)
|
||||
{
|
||||
struct sbi_hsm_data *hdata;
|
||||
struct sbi_scratch *scratch;
|
||||
@@ -66,13 +67,20 @@ int sbi_hsm_hart_get_state(u32 hartid)
|
||||
return SBI_HART_UNKNOWN;
|
||||
|
||||
hdata = sbi_scratch_offset_ptr(scratch, hart_data_offset);
|
||||
|
||||
return atomic_read(&hdata->state);
|
||||
}
|
||||
|
||||
bool sbi_hsm_hart_started(u32 hartid)
|
||||
int sbi_hsm_hart_get_state(const struct sbi_domain *dom, u32 hartid)
|
||||
{
|
||||
if (sbi_hsm_hart_get_state(hartid) == SBI_HART_STARTED)
|
||||
if (!sbi_domain_is_assigned_hart(dom, hartid))
|
||||
return SBI_HART_UNKNOWN;
|
||||
|
||||
return __sbi_hsm_hart_get_state(hartid);
|
||||
}
|
||||
|
||||
static bool sbi_hsm_hart_started(const struct sbi_domain *dom, u32 hartid)
|
||||
{
|
||||
if (sbi_hsm_hart_get_state(dom, hartid) == SBI_HART_STARTED)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
@@ -80,25 +88,30 @@ bool sbi_hsm_hart_started(u32 hartid)
|
||||
|
||||
/**
|
||||
* Get ulong HART mask for given HART base ID
|
||||
* @param dom the domain to be used for output HART mask
|
||||
* @param hbase the HART base ID
|
||||
* @param out_hmask the output ulong HART mask
|
||||
* @return 0 on success and SBI_Exxx (< 0) on failure
|
||||
* Note: the output HART mask will be set to zero on failure as well.
|
||||
*/
|
||||
int sbi_hsm_hart_started_mask(ulong hbase, ulong *out_hmask)
|
||||
int sbi_hsm_hart_started_mask(const struct sbi_domain *dom,
|
||||
ulong hbase, ulong *out_hmask)
|
||||
{
|
||||
ulong i;
|
||||
ulong hcount = sbi_scratch_last_hartid() + 1;
|
||||
ulong i, hmask, dmask;
|
||||
ulong hend = sbi_scratch_last_hartid() + 1;
|
||||
|
||||
*out_hmask = 0;
|
||||
if (hcount <= hbase)
|
||||
if (hend <= hbase)
|
||||
return SBI_EINVAL;
|
||||
if (BITS_PER_LONG < (hcount - hbase))
|
||||
hcount = BITS_PER_LONG;
|
||||
if (BITS_PER_LONG < (hend - hbase))
|
||||
hend = hbase + BITS_PER_LONG;
|
||||
|
||||
for (i = hbase; i < hcount; i++) {
|
||||
if (sbi_hsm_hart_get_state(i) == SBI_HART_STARTED)
|
||||
*out_hmask |= 1UL << (i - hbase);
|
||||
dmask = sbi_domain_get_assigned_hartmask(dom, hbase);
|
||||
for (i = hbase; i < hend; i++) {
|
||||
hmask = 1UL << (i - hbase);
|
||||
if ((dmask & hmask) &&
|
||||
(__sbi_hsm_hart_get_state(i) == SBI_HART_STARTED))
|
||||
*out_hmask |= hmask;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -202,16 +215,25 @@ fail_exit:
|
||||
sbi_hart_hang();
|
||||
}
|
||||
|
||||
int sbi_hsm_hart_start(struct sbi_scratch *scratch, u32 hartid,
|
||||
ulong saddr, ulong priv)
|
||||
int sbi_hsm_hart_start(struct sbi_scratch *scratch,
|
||||
const struct sbi_domain *dom,
|
||||
u32 hartid, ulong saddr, ulong smode, ulong priv)
|
||||
{
|
||||
int rc;
|
||||
unsigned long init_count;
|
||||
unsigned int hstate;
|
||||
struct sbi_scratch *rscratch;
|
||||
struct sbi_hsm_data *hdata;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
/* For now, we only allow start mode to be S-mode or U-mode. */
|
||||
if (smode != PRV_S && smode != PRV_U)
|
||||
return SBI_EINVAL;
|
||||
if (dom && !sbi_domain_is_assigned_hart(dom, hartid))
|
||||
return SBI_EINVAL;
|
||||
if (dom && !sbi_domain_check_addr(dom, saddr, smode,
|
||||
SBI_DOMAIN_EXECUTE))
|
||||
return SBI_EINVAL;
|
||||
|
||||
rscratch = sbi_hartid_to_scratch(hartid);
|
||||
if (!rscratch)
|
||||
return SBI_EINVAL;
|
||||
@@ -228,14 +250,10 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch, u32 hartid,
|
||||
if (hstate != SBI_HART_STOPPED)
|
||||
return SBI_EINVAL;
|
||||
|
||||
rc = sbi_hart_pmp_check_addr(scratch, saddr, PMP_X);
|
||||
if (rc)
|
||||
return rc;
|
||||
//TODO: We also need to check saddr for valid physical address as well.
|
||||
|
||||
init_count = sbi_init_count(hartid);
|
||||
rscratch->next_arg1 = priv;
|
||||
rscratch->next_addr = saddr;
|
||||
rscratch->next_mode = smode;
|
||||
|
||||
if (sbi_platform_has_hart_hotplug(plat) ||
|
||||
(sbi_platform_has_hart_secondary_boot(plat) && !init_count)) {
|
||||
@@ -255,7 +273,7 @@ int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow)
|
||||
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
|
||||
hart_data_offset);
|
||||
|
||||
if (!sbi_hsm_hart_started(hartid))
|
||||
if (!sbi_hsm_hart_started(sbi_domain_thishart_ptr(), hartid))
|
||||
return SBI_EINVAL;
|
||||
|
||||
oldstate = atomic_cmpxchg(&hdata->state, SBI_HART_STARTED,
|
||||
|
@@ -118,13 +118,22 @@ int sbi_illegal_insn_handler(ulong insn, struct sbi_trap_regs *regs)
|
||||
{
|
||||
struct sbi_trap_info uptrap;
|
||||
|
||||
/*
|
||||
* We only deal with 32-bit (or longer) illegal instructions. If we
|
||||
* see instruction is zero OR instruction is 16-bit then we fetch and
|
||||
* check the instruction encoding using unprivilege access.
|
||||
*
|
||||
* The program counter (PC) in RISC-V world is always 2-byte aligned
|
||||
* so handling only 32-bit (or longer) illegal instructions also help
|
||||
* the case where MTVAL CSR contains instruction address for illegal
|
||||
* instruction trap.
|
||||
*/
|
||||
|
||||
if (unlikely((insn & 3) != 3)) {
|
||||
if (insn == 0) {
|
||||
insn = sbi_get_insn(regs->mepc, &uptrap);
|
||||
if (uptrap.cause) {
|
||||
uptrap.epc = regs->mepc;
|
||||
return sbi_trap_redirect(regs, &uptrap);
|
||||
}
|
||||
insn = sbi_get_insn(regs->mepc, &uptrap);
|
||||
if (uptrap.cause) {
|
||||
uptrap.epc = regs->mepc;
|
||||
return sbi_trap_redirect(regs, &uptrap);
|
||||
}
|
||||
if ((insn & 3) != 3)
|
||||
return truly_illegal_insn(insn, regs);
|
||||
|
@@ -9,8 +9,10 @@
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/riscv_atomic.h>
|
||||
#include <sbi/riscv_barrier.h>
|
||||
#include <sbi/riscv_locks.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_domain.h>
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_hartmask.h>
|
||||
@@ -33,11 +35,10 @@
|
||||
" | |\n" \
|
||||
" |_|\n\n"
|
||||
|
||||
static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
|
||||
static void sbi_boot_print_banner(struct sbi_scratch *scratch)
|
||||
{
|
||||
int xlen;
|
||||
char str[128];
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS)
|
||||
return;
|
||||
|
||||
#ifdef OPENSBI_VERSION_GIT
|
||||
sbi_printf("\nOpenSBI %s\n", OPENSBI_VERSION_GIT);
|
||||
@@ -47,6 +48,52 @@ static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
|
||||
#endif
|
||||
|
||||
sbi_printf(BANNER);
|
||||
}
|
||||
|
||||
static void sbi_boot_print_general(struct sbi_scratch *scratch)
|
||||
{
|
||||
char str[128];
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS)
|
||||
return;
|
||||
|
||||
/* Platform details */
|
||||
sbi_printf("Platform Name : %s\n",
|
||||
sbi_platform_name(plat));
|
||||
sbi_platform_get_features_str(plat, str, sizeof(str));
|
||||
sbi_printf("Platform Features : %s\n", str);
|
||||
sbi_printf("Platform HART Count : %u\n",
|
||||
sbi_platform_hart_count(plat));
|
||||
|
||||
/* Firmware details */
|
||||
sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start);
|
||||
sbi_printf("Firmware Size : %d KB\n",
|
||||
(u32)(scratch->fw_size / 1024));
|
||||
|
||||
/* SBI details */
|
||||
sbi_printf("Runtime SBI Version : %d.%d\n",
|
||||
sbi_ecall_version_major(), sbi_ecall_version_minor());
|
||||
sbi_printf("\n");
|
||||
}
|
||||
|
||||
static void sbi_boot_print_domains(struct sbi_scratch *scratch)
|
||||
{
|
||||
if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS)
|
||||
return;
|
||||
|
||||
/* Domain details */
|
||||
sbi_domain_dump_all(" ");
|
||||
}
|
||||
|
||||
static void sbi_boot_print_hart(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
int xlen;
|
||||
char str[128];
|
||||
const struct sbi_domain *dom = sbi_domain_thishart_ptr();
|
||||
|
||||
if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS)
|
||||
return;
|
||||
|
||||
/* Determine MISA XLEN and MISA string */
|
||||
xlen = misa_xlen();
|
||||
@@ -55,39 +102,31 @@ static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
|
||||
sbi_hart_hang();
|
||||
}
|
||||
|
||||
/* Platform details */
|
||||
sbi_printf("Platform Name : %s\n", sbi_platform_name(plat));
|
||||
sbi_platform_get_features_str(plat, str, sizeof(str));
|
||||
sbi_printf("Platform Features : %s\n", str);
|
||||
sbi_printf("Platform HART Count : %u\n",
|
||||
sbi_platform_hart_count(plat));
|
||||
|
||||
/* Boot HART details */
|
||||
sbi_printf("Boot HART ID : %u\n", hartid);
|
||||
sbi_printf("Boot HART ID : %u\n", hartid);
|
||||
sbi_printf("Boot HART Domain : %s\n", dom->name);
|
||||
misa_string(xlen, str, sizeof(str));
|
||||
sbi_printf("Boot HART ISA : %s\n", str);
|
||||
sbi_printf("Boot HART ISA : %s\n", str);
|
||||
sbi_hart_get_features_str(scratch, str, sizeof(str));
|
||||
sbi_printf("BOOT HART Features : %s\n", str);
|
||||
sbi_printf("BOOT HART PMP Count : %d\n", sbi_hart_pmp_count(scratch));
|
||||
|
||||
/* Firmware details */
|
||||
sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start);
|
||||
sbi_printf("Firmware Size : %d KB\n",
|
||||
(u32)(scratch->fw_size / 1024));
|
||||
|
||||
/* Generic details */
|
||||
sbi_printf("Runtime SBI Version : %d.%d\n",
|
||||
sbi_ecall_version_major(), sbi_ecall_version_minor());
|
||||
sbi_printf("\n");
|
||||
|
||||
sbi_hart_delegation_dump(scratch);
|
||||
sbi_hart_pmp_dump(scratch);
|
||||
sbi_printf("Boot HART Features : %s\n", str);
|
||||
sbi_printf("Boot HART PMP Count : %d\n",
|
||||
sbi_hart_pmp_count(scratch));
|
||||
sbi_printf("Boot HART PMP Granularity : %lu\n",
|
||||
sbi_hart_pmp_granularity(scratch));
|
||||
sbi_printf("Boot HART PMP Address Bits: %d\n",
|
||||
sbi_hart_pmp_addrbits(scratch));
|
||||
sbi_printf("Boot HART MHPM Count : %d\n",
|
||||
sbi_hart_mhpm_count(scratch));
|
||||
sbi_printf("Boot HART MHPM Count : %d\n",
|
||||
sbi_hart_mhpm_count(scratch));
|
||||
sbi_hart_delegation_dump(scratch, "Boot HART ", " ");
|
||||
}
|
||||
|
||||
static spinlock_t coldboot_lock = SPIN_LOCK_INITIALIZER;
|
||||
static unsigned long coldboot_done = 0;
|
||||
static struct sbi_hartmask coldboot_wait_hmask = { 0 };
|
||||
|
||||
static unsigned long coldboot_done;
|
||||
|
||||
static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
unsigned long saved_mie, cmip;
|
||||
@@ -105,16 +144,20 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
/* Mark current HART as waiting */
|
||||
sbi_hartmask_set_hart(hartid, &coldboot_wait_hmask);
|
||||
|
||||
/* Release coldboot lock */
|
||||
spin_unlock(&coldboot_lock);
|
||||
|
||||
/* Wait for coldboot to finish using WFI */
|
||||
while (!coldboot_done) {
|
||||
spin_unlock(&coldboot_lock);
|
||||
while (!__smp_load_acquire(&coldboot_done)) {
|
||||
do {
|
||||
wfi();
|
||||
cmip = csr_read(CSR_MIP);
|
||||
} while (!(cmip & MIP_MSIP));
|
||||
spin_lock(&coldboot_lock);
|
||||
};
|
||||
|
||||
/* Acquire coldboot lock */
|
||||
spin_lock(&coldboot_lock);
|
||||
|
||||
/* Unmark current HART as waiting */
|
||||
sbi_hartmask_clear_hart(hartid, &coldboot_wait_hmask);
|
||||
|
||||
@@ -132,12 +175,12 @@ static void wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
/* Mark coldboot done */
|
||||
__smp_store_release(&coldboot_done, 1);
|
||||
|
||||
/* Acquire coldboot lock */
|
||||
spin_lock(&coldboot_lock);
|
||||
|
||||
/* Mark coldboot done */
|
||||
coldboot_done = 1;
|
||||
|
||||
/* Send an IPI to all HARTs waiting for coldboot */
|
||||
for (int i = 0; i <= sbi_scratch_last_hartid(); i++) {
|
||||
if ((i != hartid) &&
|
||||
@@ -162,6 +205,11 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
/* Note: This has to be second thing in coldboot init sequence */
|
||||
rc = sbi_domain_init(scratch, hartid);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
init_count_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__,
|
||||
"INIT_COUNT");
|
||||
if (!init_count_offset)
|
||||
@@ -175,7 +223,7 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_hart_init(scratch, hartid, TRUE);
|
||||
rc = sbi_hart_init(scratch, TRUE);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
@@ -183,32 +231,75 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
sbi_boot_print_banner(scratch);
|
||||
|
||||
rc = sbi_platform_irqchip_init(plat, TRUE);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
sbi_printf("%s: platform irqchip init failed (error %d)\n",
|
||||
__func__, rc);
|
||||
sbi_hart_hang();
|
||||
}
|
||||
|
||||
rc = sbi_ipi_init(scratch, TRUE);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
sbi_printf("%s: ipi init failed (error %d)\n", __func__, rc);
|
||||
sbi_hart_hang();
|
||||
}
|
||||
|
||||
rc = sbi_tlb_init(scratch, TRUE);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
sbi_printf("%s: tlb init failed (error %d)\n", __func__, rc);
|
||||
sbi_hart_hang();
|
||||
}
|
||||
|
||||
rc = sbi_timer_init(scratch, TRUE);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
sbi_printf("%s: timer init failed (error %d)\n", __func__, rc);
|
||||
sbi_hart_hang();
|
||||
}
|
||||
|
||||
rc = sbi_ecall_init();
|
||||
if (rc)
|
||||
if (rc) {
|
||||
sbi_printf("%s: ecall init failed (error %d)\n", __func__, rc);
|
||||
sbi_hart_hang();
|
||||
}
|
||||
|
||||
sbi_boot_print_general(scratch);
|
||||
|
||||
/*
|
||||
* Note: Finalize domains after HSM initialization so that we
|
||||
* can startup non-root domains.
|
||||
* Note: Finalize domains before HART PMP configuration so
|
||||
* that we use correct domain for configuring PMP.
|
||||
*/
|
||||
rc = sbi_domain_finalize(scratch, hartid);
|
||||
if (rc) {
|
||||
sbi_printf("%s: domain finalize failed (error %d)\n",
|
||||
__func__, rc);
|
||||
sbi_hart_hang();
|
||||
}
|
||||
|
||||
sbi_boot_print_domains(scratch);
|
||||
|
||||
rc = sbi_hart_pmp_configure(scratch);
|
||||
if (rc) {
|
||||
sbi_printf("%s: PMP configure failed (error %d)\n",
|
||||
__func__, rc);
|
||||
sbi_hart_hang();
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: Platform final initialization should be last so that
|
||||
* it sees correct domain assignment and PMP configuration.
|
||||
*/
|
||||
rc = sbi_platform_final_init(plat, TRUE);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
sbi_printf("%s: platform final init failed (error %d)\n",
|
||||
__func__, rc);
|
||||
sbi_hart_hang();
|
||||
}
|
||||
|
||||
if (!(scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS))
|
||||
sbi_boot_prints(scratch, hartid);
|
||||
sbi_boot_print_hart(scratch, hartid);
|
||||
|
||||
wake_coldboot_harts(scratch, hartid);
|
||||
|
||||
@@ -239,7 +330,7 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_hart_init(scratch, hartid, FALSE);
|
||||
rc = sbi_hart_init(scratch, FALSE);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
@@ -259,6 +350,10 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_hart_pmp_configure(scratch);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_platform_final_init(plat, FALSE);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
@@ -288,6 +383,7 @@ static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);
|
||||
*/
|
||||
void __noreturn sbi_init(struct sbi_scratch *scratch)
|
||||
{
|
||||
bool next_mode_supported = FALSE;
|
||||
bool coldboot = FALSE;
|
||||
u32 hartid = current_hartid();
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
@@ -296,7 +392,33 @@ void __noreturn sbi_init(struct sbi_scratch *scratch)
|
||||
sbi_platform_hart_invalid(plat, hartid))
|
||||
sbi_hart_hang();
|
||||
|
||||
if (atomic_xchg(&coldboot_lottery, 1) == 0)
|
||||
switch (scratch->next_mode) {
|
||||
case PRV_M:
|
||||
next_mode_supported = TRUE;
|
||||
break;
|
||||
case PRV_S:
|
||||
if (misa_extension('S'))
|
||||
next_mode_supported = TRUE;
|
||||
break;
|
||||
case PRV_U:
|
||||
if (misa_extension('U'))
|
||||
next_mode_supported = TRUE;
|
||||
break;
|
||||
default:
|
||||
sbi_hart_hang();
|
||||
}
|
||||
|
||||
/*
|
||||
* Only the HART supporting privilege mode specified in the
|
||||
* scratch->next_mode should be allowed to become the coldboot
|
||||
* HART because the coldboot HART will be directly jumping to
|
||||
* the next booting stage.
|
||||
*
|
||||
* We use a lottery mechanism to select coldboot HART among
|
||||
* HARTs which satisfy above condition.
|
||||
*/
|
||||
|
||||
if (next_mode_supported && atomic_xchg(&coldboot_lottery, 1) == 0)
|
||||
coldboot = TRUE;
|
||||
|
||||
if (coldboot)
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include <sbi/riscv_atomic.h>
|
||||
#include <sbi/riscv_barrier.h>
|
||||
#include <sbi/sbi_bitops.h>
|
||||
#include <sbi/sbi_domain.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_hsm.h>
|
||||
@@ -77,10 +78,11 @@ int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
|
||||
{
|
||||
int rc;
|
||||
ulong i, m;
|
||||
struct sbi_domain *dom = sbi_domain_thishart_ptr();
|
||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||
|
||||
if (hbase != -1UL) {
|
||||
rc = sbi_hsm_hart_started_mask(hbase, &m);
|
||||
rc = sbi_hsm_hart_started_mask(dom, hbase, &m);
|
||||
if (rc)
|
||||
return rc;
|
||||
m &= hmask;
|
||||
@@ -92,7 +94,7 @@ int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
|
||||
}
|
||||
} else {
|
||||
hbase = 0;
|
||||
while (!sbi_hsm_hart_started_mask(hbase, &m)) {
|
||||
while (!sbi_hsm_hart_started_mask(dom, hbase, &m)) {
|
||||
/* Send IPIs */
|
||||
for (i = hbase; m; i++, m >>= 1) {
|
||||
if (m & 1UL)
|
||||
|
@@ -24,7 +24,7 @@ union reg_data {
|
||||
int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
|
||||
struct sbi_trap_regs *regs)
|
||||
{
|
||||
ulong insn;
|
||||
ulong insn, insn_len;
|
||||
union reg_data val;
|
||||
struct sbi_trap_info uptrap;
|
||||
int i, fp = 0, shift = 0, len = 0;
|
||||
@@ -35,6 +35,7 @@ int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
|
||||
* transformed instruction or custom instruction.
|
||||
*/
|
||||
insn = tinst | INSN_16BIT_MASK;
|
||||
insn_len = (tinst & 0x2) ? INSN_LEN(insn) : 2;
|
||||
} else {
|
||||
/*
|
||||
* Bit[0] == 0 implies trapped instruction value is
|
||||
@@ -45,6 +46,7 @@ int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
|
||||
uptrap.epc = regs->mepc;
|
||||
return sbi_trap_redirect(regs, &uptrap);
|
||||
}
|
||||
insn_len = INSN_LEN(insn);
|
||||
}
|
||||
|
||||
if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) {
|
||||
@@ -126,7 +128,7 @@ int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
|
||||
}
|
||||
|
||||
if (!fp)
|
||||
SET_RD(insn, regs, val.data_ulong << shift >> shift);
|
||||
SET_RD(insn, regs, ((long)(val.data_ulong << shift)) >> shift);
|
||||
#ifdef __riscv_flen
|
||||
else if (len == 8)
|
||||
SET_F64_RD(insn, regs, val.data_u64);
|
||||
@@ -134,7 +136,7 @@ int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
|
||||
SET_F32_RD(insn, regs, val.data_ulong);
|
||||
#endif
|
||||
|
||||
regs->mepc += INSN_LEN(insn);
|
||||
regs->mepc += insn_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -142,7 +144,7 @@ int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
|
||||
int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
|
||||
struct sbi_trap_regs *regs)
|
||||
{
|
||||
ulong insn;
|
||||
ulong insn, insn_len;
|
||||
union reg_data val;
|
||||
struct sbi_trap_info uptrap;
|
||||
int i, len = 0;
|
||||
@@ -153,6 +155,7 @@ int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
|
||||
* transformed instruction or custom instruction.
|
||||
*/
|
||||
insn = tinst | INSN_16BIT_MASK;
|
||||
insn_len = (tinst & 0x2) ? INSN_LEN(insn) : 2;
|
||||
} else {
|
||||
/*
|
||||
* Bit[0] == 0 implies trapped instruction value is
|
||||
@@ -163,6 +166,7 @@ int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
|
||||
uptrap.epc = regs->mepc;
|
||||
return sbi_trap_redirect(regs, &uptrap);
|
||||
}
|
||||
insn_len = INSN_LEN(insn);
|
||||
}
|
||||
|
||||
val.data_ulong = GET_RS2(insn, regs);
|
||||
@@ -233,7 +237,7 @@ int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
|
||||
}
|
||||
}
|
||||
|
||||
regs->mepc += INSN_LEN(insn);
|
||||
regs->mepc += insn_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -14,6 +14,10 @@
|
||||
|
||||
#include <sbi/sbi_string.h>
|
||||
|
||||
/*
|
||||
Provides sbi_strcmp for the completeness of supporting string functions.
|
||||
it is not recommended to use sbi_strcmp() but use sbi_strncmp instead.
|
||||
*/
|
||||
int sbi_strcmp(const char *a, const char *b)
|
||||
{
|
||||
/* search first diff or end of string */
|
||||
@@ -23,6 +27,15 @@ int sbi_strcmp(const char *a, const char *b)
|
||||
return *a - *b;
|
||||
}
|
||||
|
||||
int sbi_strncmp(const char *a, const char *b, size_t count)
|
||||
{
|
||||
/* search first diff or end of string */
|
||||
for (; count > 0 && *a == *b && *a != '\0'; a++, b++, count--)
|
||||
;
|
||||
|
||||
return *a - *b;
|
||||
}
|
||||
|
||||
size_t sbi_strlen(const char *str)
|
||||
{
|
||||
unsigned long ret = 0;
|
||||
|
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/sbi_bitops.h>
|
||||
#include <sbi/sbi_domain.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_hsm.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
@@ -17,14 +18,24 @@
|
||||
#include <sbi/sbi_ipi.h>
|
||||
#include <sbi/sbi_init.h>
|
||||
|
||||
void __noreturn sbi_system_reset(u32 platform_reset_type)
|
||||
bool sbi_system_reset_supported(u32 reset_type, u32 reset_reason)
|
||||
{
|
||||
if (sbi_platform_system_reset_check(sbi_platform_thishart_ptr(),
|
||||
reset_type, reset_reason))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason)
|
||||
{
|
||||
ulong hbase = 0, hmask;
|
||||
u32 cur_hartid = current_hartid();
|
||||
struct sbi_domain *dom = sbi_domain_thishart_ptr();
|
||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||
|
||||
/* Send HALT IPI to every hart other than the current hart */
|
||||
while (!sbi_hsm_hart_started_mask(hbase, &hmask)) {
|
||||
while (!sbi_hsm_hart_started_mask(dom, hbase, &hmask)) {
|
||||
if (hbase <= cur_hartid)
|
||||
hmask &= ~(1UL << (cur_hartid - hbase));
|
||||
if (hmask)
|
||||
@@ -35,9 +46,10 @@ void __noreturn sbi_system_reset(u32 platform_reset_type)
|
||||
/* Stop current HART */
|
||||
sbi_hsm_hart_stop(scratch, FALSE);
|
||||
|
||||
/* Platform specific reset */
|
||||
sbi_platform_system_reset(sbi_platform_ptr(scratch),
|
||||
platform_reset_type);
|
||||
/* Platform specific reset if domain allowed system reset */
|
||||
if (dom->system_reset_allowed)
|
||||
sbi_platform_system_reset(sbi_platform_ptr(scratch),
|
||||
reset_type, reset_reason);
|
||||
|
||||
/* If platform specific reset did not work then do sbi_exit() */
|
||||
sbi_exit(scratch);
|
||||
|
@@ -32,7 +32,7 @@ static void sbi_tlb_flush_all(void)
|
||||
__asm__ __volatile("sfence.vma");
|
||||
}
|
||||
|
||||
static void sbi_tlb_hfence_vvma(struct sbi_tlb_info *tinfo)
|
||||
void sbi_tlb_local_hfence_vvma(struct sbi_tlb_info *tinfo)
|
||||
{
|
||||
unsigned long start = tinfo->start;
|
||||
unsigned long size = tinfo->size;
|
||||
@@ -55,7 +55,7 @@ done:
|
||||
csr_write(CSR_HGATP, hgatp);
|
||||
}
|
||||
|
||||
static void sbi_tlb_hfence_gvma(struct sbi_tlb_info *tinfo)
|
||||
void sbi_tlb_local_hfence_gvma(struct sbi_tlb_info *tinfo)
|
||||
{
|
||||
unsigned long start = tinfo->start;
|
||||
unsigned long size = tinfo->size;
|
||||
@@ -71,7 +71,7 @@ static void sbi_tlb_hfence_gvma(struct sbi_tlb_info *tinfo)
|
||||
}
|
||||
}
|
||||
|
||||
static void sbi_tlb_sfence_vma(struct sbi_tlb_info *tinfo)
|
||||
void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo)
|
||||
{
|
||||
unsigned long start = tinfo->start;
|
||||
unsigned long size = tinfo->size;
|
||||
@@ -90,7 +90,7 @@ static void sbi_tlb_sfence_vma(struct sbi_tlb_info *tinfo)
|
||||
}
|
||||
}
|
||||
|
||||
static void sbi_tlb_hfence_vvma_asid(struct sbi_tlb_info *tinfo)
|
||||
void sbi_tlb_local_hfence_vvma_asid(struct sbi_tlb_info *tinfo)
|
||||
{
|
||||
unsigned long start = tinfo->start;
|
||||
unsigned long size = tinfo->size;
|
||||
@@ -119,7 +119,7 @@ done:
|
||||
csr_write(CSR_HGATP, hgatp);
|
||||
}
|
||||
|
||||
static void sbi_tlb_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
|
||||
void sbi_tlb_local_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
|
||||
{
|
||||
unsigned long start = tinfo->start;
|
||||
unsigned long size = tinfo->size;
|
||||
@@ -141,7 +141,7 @@ static void sbi_tlb_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
|
||||
}
|
||||
}
|
||||
|
||||
static void sbi_tlb_sfence_vma_asid(struct sbi_tlb_info *tinfo)
|
||||
void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo)
|
||||
{
|
||||
unsigned long start = tinfo->start;
|
||||
unsigned long size = tinfo->size;
|
||||
@@ -170,35 +170,9 @@ static void sbi_tlb_sfence_vma_asid(struct sbi_tlb_info *tinfo)
|
||||
}
|
||||
}
|
||||
|
||||
static void sbi_tlb_local_flush(struct sbi_tlb_info *tinfo)
|
||||
void sbi_tlb_local_fence_i(struct sbi_tlb_info *tinfo)
|
||||
{
|
||||
switch (tinfo->type) {
|
||||
case SBI_TLB_FLUSH_VMA:
|
||||
sbi_tlb_sfence_vma(tinfo);
|
||||
break;
|
||||
case SBI_TLB_FLUSH_VMA_ASID:
|
||||
sbi_tlb_sfence_vma_asid(tinfo);
|
||||
break;
|
||||
case SBI_TLB_FLUSH_GVMA:
|
||||
sbi_tlb_hfence_gvma(tinfo);
|
||||
break;
|
||||
case SBI_TLB_FLUSH_GVMA_VMID:
|
||||
sbi_tlb_hfence_gvma_vmid(tinfo);
|
||||
break;
|
||||
case SBI_TLB_FLUSH_VVMA:
|
||||
sbi_tlb_hfence_vvma(tinfo);
|
||||
break;
|
||||
case SBI_TLB_FLUSH_VVMA_ASID:
|
||||
sbi_tlb_hfence_vvma_asid(tinfo);
|
||||
break;
|
||||
case SBI_ITLB_FLUSH:
|
||||
__asm__ __volatile("fence.i");
|
||||
break;
|
||||
default:
|
||||
sbi_printf("Invalid tlb flush request type [%lu]\n",
|
||||
tinfo->type);
|
||||
}
|
||||
return;
|
||||
__asm__ __volatile("fence.i");
|
||||
}
|
||||
|
||||
static void sbi_tlb_entry_process(struct sbi_tlb_info *tinfo)
|
||||
@@ -207,7 +181,7 @@ static void sbi_tlb_entry_process(struct sbi_tlb_info *tinfo)
|
||||
struct sbi_scratch *rscratch = NULL;
|
||||
unsigned long *rtlb_sync = NULL;
|
||||
|
||||
sbi_tlb_local_flush(tinfo);
|
||||
tinfo->local_fn(tinfo);
|
||||
|
||||
sbi_hartmask_for_each_hart(rhartid, &tinfo->smask) {
|
||||
rscratch = sbi_hartid_to_scratch(rhartid);
|
||||
@@ -316,13 +290,13 @@ static int sbi_tlb_update_cb(void *in, void *data)
|
||||
curr = (struct sbi_tlb_info *)data;
|
||||
next = (struct sbi_tlb_info *)in;
|
||||
|
||||
if (next->type == SBI_TLB_FLUSH_VMA_ASID &&
|
||||
curr->type == SBI_TLB_FLUSH_VMA_ASID) {
|
||||
if (next->local_fn == sbi_tlb_local_sfence_vma_asid &&
|
||||
curr->local_fn == sbi_tlb_local_sfence_vma_asid) {
|
||||
if (next->asid == curr->asid)
|
||||
ret = __sbi_tlb_range_check(curr, next);
|
||||
} else if (next->type == SBI_TLB_FLUSH_VMA &&
|
||||
curr->type == SBI_TLB_FLUSH_VMA) {
|
||||
ret = __sbi_tlb_range_check(curr, next);
|
||||
} else if (next->local_fn == sbi_tlb_local_sfence_vma &&
|
||||
curr->local_fn == sbi_tlb_local_sfence_vma) {
|
||||
ret = __sbi_tlb_range_check(curr, next);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -352,7 +326,7 @@ static int sbi_tlb_update(struct sbi_scratch *scratch,
|
||||
* then just do a local flush and return;
|
||||
*/
|
||||
if (remote_hartid == curr_hartid) {
|
||||
sbi_tlb_local_flush(tinfo);
|
||||
tinfo->local_fn(tinfo);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -391,6 +365,9 @@ static u32 tlb_event = SBI_IPI_EVENT_MAX;
|
||||
|
||||
int sbi_tlb_request(ulong hmask, ulong hbase, struct sbi_tlb_info *tinfo)
|
||||
{
|
||||
if (!tinfo->local_fn)
|
||||
return SBI_EINVAL;
|
||||
|
||||
return sbi_ipi_send_many(hmask, hbase, tlb_event, tinfo);
|
||||
}
|
||||
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include <sbi/sbi_illegal_insn.h>
|
||||
#include <sbi/sbi_ipi.h>
|
||||
#include <sbi/sbi_misaligned_ldst.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/sbi_timer.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
|
||||
@@ -123,7 +124,7 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
|
||||
/* Update HSTATUS SPVP and SPV bits */
|
||||
hstatus = csr_read(CSR_HSTATUS);
|
||||
hstatus &= ~HSTATUS_SPVP;
|
||||
hstatus |= (regs->mstatus & MSTATUS_SPP) ? HSTATUS_SPVP : 0;
|
||||
hstatus |= (prev_mode == PRV_S) ? HSTATUS_SPVP : 0;
|
||||
hstatus &= ~HSTATUS_SPV;
|
||||
hstatus |= (prev_virt) ? HSTATUS_SPV : 0;
|
||||
csr_write(CSR_HSTATUS, hstatus);
|
||||
@@ -252,7 +253,7 @@ void sbi_trap_handler(struct sbi_trap_regs *regs)
|
||||
msg = "misaligned store handler failed";
|
||||
break;
|
||||
case CAUSE_SUPERVISOR_ECALL:
|
||||
case CAUSE_HYPERVISOR_ECALL:
|
||||
case CAUSE_MACHINE_ECALL:
|
||||
rc = sbi_ecall_handler(regs);
|
||||
msg = "ecall handler failed";
|
||||
break;
|
||||
@@ -271,3 +272,22 @@ trap_error:
|
||||
if (rc)
|
||||
sbi_trap_error(msg, rc, mcause, mtval, mtval2, mtinst, regs);
|
||||
}
|
||||
|
||||
typedef void (*trap_exit_t)(const struct sbi_trap_regs *regs);
|
||||
|
||||
/**
|
||||
* Exit trap/interrupt handling
|
||||
*
|
||||
* This function is called by non-firmware code to abruptly exit
|
||||
* trap/interrupt handling and resume execution at context pointed
|
||||
* by given register state.
|
||||
*
|
||||
* @param regs pointer to register state
|
||||
*/
|
||||
void __noreturn sbi_trap_exit(const struct sbi_trap_regs *regs)
|
||||
{
|
||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||
|
||||
((trap_exit_t)scratch->trap_exit)(regs);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
455
lib/utils/fdt/fdt_domain.c
Normal file
455
lib/utils/fdt/fdt_domain.c
Normal file
@@ -0,0 +1,455 @@
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
/*
|
||||
* fdt_domain.c - Flat Device Tree Domain helper routines
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#include <libfdt.h>
|
||||
#include <sbi/sbi_domain.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_hartmask.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi_utils/fdt/fdt_domain.h>
|
||||
#include <sbi_utils/fdt/fdt_helper.h>
|
||||
|
||||
int fdt_iterate_each_domain(void *fdt, void *opaque,
|
||||
int (*fn)(void *fdt, int domain_offset,
|
||||
void *opaque))
|
||||
{
|
||||
int rc, doffset, poffset;
|
||||
|
||||
if (!fdt || !fn)
|
||||
return SBI_EINVAL;
|
||||
|
||||
poffset = fdt_path_offset(fdt, "/chosen");
|
||||
if (poffset < 0)
|
||||
return 0;
|
||||
poffset = fdt_node_offset_by_compatible(fdt, poffset,
|
||||
"opensbi,domain,config");
|
||||
if (poffset < 0)
|
||||
return 0;
|
||||
|
||||
fdt_for_each_subnode(doffset, fdt, poffset) {
|
||||
if (fdt_node_check_compatible(fdt, doffset,
|
||||
"opensbi,domain,instance"))
|
||||
continue;
|
||||
|
||||
rc = fn(fdt, doffset, opaque);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_iterate_each_memregion(void *fdt, int domain_offset, void *opaque,
|
||||
int (*fn)(void *fdt, int domain_offset,
|
||||
int region_offset, u32 region_access,
|
||||
void *opaque))
|
||||
{
|
||||
u32 i, rcount;
|
||||
int rc, len, region_offset;
|
||||
const u32 *regions;
|
||||
|
||||
if (!fdt || (domain_offset < 0) || !fn)
|
||||
return SBI_EINVAL;
|
||||
|
||||
if (fdt_node_check_compatible(fdt, domain_offset,
|
||||
"opensbi,domain,instance"))
|
||||
return SBI_EINVAL;
|
||||
|
||||
regions = fdt_getprop(fdt, domain_offset, "regions", &len);
|
||||
if (!regions)
|
||||
return 0;
|
||||
|
||||
rcount = (u32)len / (sizeof(u32) * 2);
|
||||
for (i = 0; i < rcount; i++) {
|
||||
region_offset = fdt_node_offset_by_phandle(fdt,
|
||||
fdt32_to_cpu(regions[2 * i]));
|
||||
if (region_offset < 0)
|
||||
return region_offset;
|
||||
|
||||
if (fdt_node_check_compatible(fdt, region_offset,
|
||||
"opensbi,domain,memregion"))
|
||||
return SBI_EINVAL;
|
||||
|
||||
rc = fn(fdt, domain_offset, region_offset,
|
||||
fdt32_to_cpu(regions[(2 * i) + 1]), opaque);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct __fixup_find_domain_offset_info {
|
||||
const char *name;
|
||||
int *doffset;
|
||||
};
|
||||
|
||||
static int __fixup_find_domain_offset(void *fdt, int doff, void *p)
|
||||
{
|
||||
struct __fixup_find_domain_offset_info *fdo = p;
|
||||
|
||||
if (!sbi_strcmp(fdo->name, fdt_get_name(fdt, doff, NULL)))
|
||||
*fdo->doffset = doff;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DISABLE_DEVICES_MASK (SBI_DOMAIN_MEMREGION_READABLE | \
|
||||
SBI_DOMAIN_MEMREGION_WRITEABLE | \
|
||||
SBI_DOMAIN_MEMREGION_EXECUTABLE)
|
||||
|
||||
static int __fixup_count_disable_devices(void *fdt, int doff, int roff,
|
||||
u32 perm, void *p)
|
||||
{
|
||||
int len;
|
||||
u32 *dcount = p;
|
||||
|
||||
if (perm & DISABLE_DEVICES_MASK)
|
||||
return 0;
|
||||
|
||||
len = 0;
|
||||
if (fdt_getprop(fdt, roff, "devices", &len))
|
||||
*dcount += len / sizeof(u32);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __fixup_disable_devices(void *fdt, int doff, int roff,
|
||||
u32 raccess, void *p)
|
||||
{
|
||||
int i, len, coff;
|
||||
const u32 *devices;
|
||||
|
||||
if (raccess & DISABLE_DEVICES_MASK)
|
||||
return 0;
|
||||
|
||||
len = 0;
|
||||
devices = fdt_getprop(fdt, roff, "devices", &len);
|
||||
if (!devices)
|
||||
return 0;
|
||||
len = len / sizeof(u32);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
coff = fdt_node_offset_by_phandle(fdt,
|
||||
fdt32_to_cpu(devices[i]));
|
||||
if (coff < 0)
|
||||
return coff;
|
||||
|
||||
fdt_setprop_string(fdt, coff, "status", "disabled");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fdt_domain_fixup(void *fdt)
|
||||
{
|
||||
u32 i, dcount;
|
||||
int err, poffset, doffset;
|
||||
struct sbi_domain *dom = sbi_domain_thishart_ptr();
|
||||
struct __fixup_find_domain_offset_info fdo;
|
||||
|
||||
/* Remove the domain assignment DT property from CPU DT nodes */
|
||||
poffset = fdt_path_offset(fdt, "/cpus");
|
||||
if (poffset < 0)
|
||||
return;
|
||||
fdt_for_each_subnode(doffset, fdt, poffset) {
|
||||
err = fdt_parse_hart_id(fdt, doffset, &i);
|
||||
if (err)
|
||||
continue;
|
||||
|
||||
fdt_nop_property(fdt, doffset, "opensbi-domain");
|
||||
}
|
||||
|
||||
/* Skip device disable for root domain */
|
||||
if (!dom->index)
|
||||
goto skip_device_disable;
|
||||
|
||||
/* Find current domain DT node */
|
||||
doffset = -1;
|
||||
fdo.name = dom->name;
|
||||
fdo.doffset = &doffset;
|
||||
fdt_iterate_each_domain(fdt, &fdo, __fixup_find_domain_offset);
|
||||
if (doffset < 0)
|
||||
goto skip_device_disable;
|
||||
|
||||
/* Count current domain device DT nodes to be disabled */
|
||||
dcount = 0;
|
||||
fdt_iterate_each_memregion(fdt, doffset, &dcount,
|
||||
__fixup_count_disable_devices);
|
||||
if (!dcount)
|
||||
goto skip_device_disable;
|
||||
|
||||
/* Expand FDT based on device DT nodes to be disabled */
|
||||
err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + dcount * 32);
|
||||
if (err < 0)
|
||||
return;
|
||||
|
||||
/* Again find current domain DT node */
|
||||
doffset = -1;
|
||||
fdo.name = dom->name;
|
||||
fdo.doffset = &doffset;
|
||||
fdt_iterate_each_domain(fdt, &fdo, __fixup_find_domain_offset);
|
||||
if (doffset < 0)
|
||||
goto skip_device_disable;
|
||||
|
||||
/* Disable device DT nodes for current domain */
|
||||
fdt_iterate_each_memregion(fdt, doffset, NULL,
|
||||
__fixup_disable_devices);
|
||||
skip_device_disable:
|
||||
|
||||
/* Remove the OpenSBI domain config DT node */
|
||||
poffset = fdt_path_offset(fdt, "/chosen");
|
||||
if (poffset < 0)
|
||||
return;
|
||||
poffset = fdt_node_offset_by_compatible(fdt, poffset,
|
||||
"opensbi,domain,config");
|
||||
if (poffset < 0)
|
||||
return;
|
||||
fdt_nop_node(fdt, poffset);
|
||||
}
|
||||
|
||||
#define FDT_DOMAIN_MAX_COUNT 8
|
||||
#define FDT_DOMAIN_REGION_MAX_COUNT 16
|
||||
|
||||
static u32 fdt_domains_count;
|
||||
static struct sbi_domain fdt_domains[FDT_DOMAIN_MAX_COUNT];
|
||||
static struct sbi_hartmask fdt_masks[FDT_DOMAIN_MAX_COUNT];
|
||||
static struct sbi_domain_memregion
|
||||
fdt_regions[FDT_DOMAIN_MAX_COUNT][FDT_DOMAIN_REGION_MAX_COUNT + 2];
|
||||
|
||||
static int __fdt_parse_region(void *fdt, int domain_offset,
|
||||
int region_offset, u32 region_access,
|
||||
void *opaque)
|
||||
{
|
||||
int len;
|
||||
u32 val32;
|
||||
u64 val64;
|
||||
const u32 *val;
|
||||
u32 *region_count = opaque;
|
||||
struct sbi_domain_memregion *region;
|
||||
|
||||
/* Find next region of the domain */
|
||||
if (FDT_DOMAIN_REGION_MAX_COUNT <= *region_count)
|
||||
return SBI_EINVAL;
|
||||
region = &fdt_regions[fdt_domains_count][*region_count];
|
||||
|
||||
/* Read "base" DT property */
|
||||
val = fdt_getprop(fdt, region_offset, "base", &len);
|
||||
if (!val && len >= 8)
|
||||
return SBI_EINVAL;
|
||||
val64 = fdt32_to_cpu(val[0]);
|
||||
val64 = (val64 << 32) | fdt32_to_cpu(val[1]);
|
||||
region->base = val64;
|
||||
|
||||
/* Read "order" DT property */
|
||||
val = fdt_getprop(fdt, region_offset, "order", &len);
|
||||
if (!val && len >= 4)
|
||||
return SBI_EINVAL;
|
||||
val32 = fdt32_to_cpu(*val);
|
||||
if (val32 < 3 || __riscv_xlen < val32)
|
||||
return SBI_EINVAL;
|
||||
region->order = val32;
|
||||
|
||||
/* Read "mmio" DT property */
|
||||
region->flags = region_access & SBI_DOMAIN_MEMREGION_ACCESS_MASK;
|
||||
if (fdt_get_property(fdt, region_offset, "mmio", NULL))
|
||||
region->flags |= SBI_DOMAIN_MEMREGION_MMIO;
|
||||
|
||||
(*region_count)++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
|
||||
{
|
||||
u32 val32;
|
||||
u64 val64;
|
||||
const u32 *val;
|
||||
struct sbi_domain *dom;
|
||||
struct sbi_hartmask *mask;
|
||||
struct sbi_hartmask assign_mask;
|
||||
int *cold_domain_offset = opaque;
|
||||
struct sbi_domain_memregion *regions;
|
||||
int i, err, len, cpus_offset, cpu_offset, doffset;
|
||||
|
||||
/* Sanity check on maximum domains we can handle */
|
||||
if (FDT_DOMAIN_MAX_COUNT <= fdt_domains_count)
|
||||
return SBI_EINVAL;
|
||||
dom = &fdt_domains[fdt_domains_count];
|
||||
mask = &fdt_masks[fdt_domains_count];
|
||||
regions = &fdt_regions[fdt_domains_count][0];
|
||||
|
||||
/* Read DT node name */
|
||||
sbi_strncpy(dom->name, fdt_get_name(fdt, domain_offset, NULL),
|
||||
sizeof(dom->name));
|
||||
dom->name[sizeof(dom->name) - 1] = '\0';
|
||||
|
||||
/* Setup possible HARTs mask */
|
||||
SBI_HARTMASK_INIT(mask);
|
||||
dom->possible_harts = mask;
|
||||
val = fdt_getprop(fdt, domain_offset, "possible-harts", &len);
|
||||
len = len / sizeof(u32);
|
||||
if (val && len) {
|
||||
for (i = 0; i < len; i++) {
|
||||
cpu_offset = fdt_node_offset_by_phandle(fdt,
|
||||
fdt32_to_cpu(val[i]));
|
||||
if (cpu_offset < 0)
|
||||
return cpu_offset;
|
||||
|
||||
err = fdt_parse_hart_id(fdt, cpu_offset, &val32);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
sbi_hartmask_set_hart(val32, mask);
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup memregions from DT */
|
||||
val32 = 0;
|
||||
sbi_memset(regions, 0,
|
||||
sizeof(*regions) * (FDT_DOMAIN_REGION_MAX_COUNT + 2));
|
||||
dom->regions = regions;
|
||||
err = fdt_iterate_each_memregion(fdt, domain_offset, &val32,
|
||||
__fdt_parse_region);
|
||||
if (err)
|
||||
return err;
|
||||
sbi_domain_memregion_initfw(®ions[val32]);
|
||||
|
||||
/* Read "boot-hart" DT property */
|
||||
val32 = -1U;
|
||||
val = fdt_getprop(fdt, domain_offset, "boot-hart", &len);
|
||||
if (val && len >= 4) {
|
||||
cpu_offset = fdt_node_offset_by_phandle(fdt,
|
||||
fdt32_to_cpu(*val));
|
||||
if (cpu_offset >= 0)
|
||||
fdt_parse_hart_id(fdt, cpu_offset, &val32);
|
||||
} else {
|
||||
if (domain_offset == *cold_domain_offset)
|
||||
val32 = current_hartid();
|
||||
}
|
||||
dom->boot_hartid = val32;
|
||||
|
||||
/* Read "next-arg1" DT property */
|
||||
val64 = 0;
|
||||
val = fdt_getprop(fdt, domain_offset, "next-arg1", &len);
|
||||
if (val && len >= 8) {
|
||||
val64 = fdt32_to_cpu(val[0]);
|
||||
val64 = (val64 << 32) | fdt32_to_cpu(val[1]);
|
||||
} else {
|
||||
if (domain_offset == *cold_domain_offset)
|
||||
val64 = sbi_scratch_thishart_ptr()->next_arg1;
|
||||
}
|
||||
dom->next_arg1 = val64;
|
||||
|
||||
/* Read "next-addr" DT property */
|
||||
val64 = 0;
|
||||
val = fdt_getprop(fdt, domain_offset, "next-addr", &len);
|
||||
if (val && len >= 8) {
|
||||
val64 = fdt32_to_cpu(val[0]);
|
||||
val64 = (val64 << 32) | fdt32_to_cpu(val[1]);
|
||||
} else {
|
||||
if (domain_offset == *cold_domain_offset)
|
||||
val64 = sbi_scratch_thishart_ptr()->next_addr;
|
||||
}
|
||||
dom->next_addr = val64;
|
||||
|
||||
/* Read "next-mode" DT property */
|
||||
val32 = 0x1;
|
||||
val = fdt_getprop(fdt, domain_offset, "next-mode", &len);
|
||||
if (val && len >= 4) {
|
||||
val32 = fdt32_to_cpu(val[0]);
|
||||
if (val32 != 0x0 && val32 != 0x1)
|
||||
val32 = 0x1;
|
||||
} else {
|
||||
if (domain_offset == *cold_domain_offset)
|
||||
val32 = sbi_scratch_thishart_ptr()->next_mode;
|
||||
}
|
||||
dom->next_mode = val32;
|
||||
|
||||
/* Read "system-reset-allowed" DT property */
|
||||
if (fdt_get_property(fdt, domain_offset,
|
||||
"system-reset-allowed", NULL))
|
||||
dom->system_reset_allowed = TRUE;
|
||||
else
|
||||
dom->system_reset_allowed = FALSE;
|
||||
|
||||
/* Find /cpus DT node */
|
||||
cpus_offset = fdt_path_offset(fdt, "/cpus");
|
||||
if (cpus_offset < 0)
|
||||
return cpus_offset;
|
||||
|
||||
/* HART to domain assignment mask based on CPU DT nodes */
|
||||
sbi_hartmask_clear_all(&assign_mask);
|
||||
fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
|
||||
err = fdt_parse_hart_id(fdt, cpu_offset, &val32);
|
||||
if (err)
|
||||
continue;
|
||||
|
||||
if (SBI_HARTMASK_MAX_BITS <= val32)
|
||||
continue;
|
||||
|
||||
val = fdt_getprop(fdt, cpu_offset, "opensbi-domain", &len);
|
||||
if (!val || len < 4)
|
||||
return SBI_EINVAL;
|
||||
|
||||
doffset = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
|
||||
if (doffset < 0)
|
||||
return doffset;
|
||||
|
||||
if (doffset == domain_offset)
|
||||
sbi_hartmask_set_hart(val32, &assign_mask);
|
||||
}
|
||||
|
||||
/* Increment domains count */
|
||||
fdt_domains_count++;
|
||||
|
||||
/* Register the domain */
|
||||
return sbi_domain_register(dom, &assign_mask);
|
||||
}
|
||||
|
||||
int fdt_domains_populate(void *fdt)
|
||||
{
|
||||
const u32 *val;
|
||||
int cold_domain_offset;
|
||||
u32 hartid, cold_hartid;
|
||||
int err, len, cpus_offset, cpu_offset;
|
||||
|
||||
/* Sanity checks */
|
||||
if (!fdt)
|
||||
return SBI_EINVAL;
|
||||
|
||||
/* Find /cpus DT node */
|
||||
cpus_offset = fdt_path_offset(fdt, "/cpus");
|
||||
if (cpus_offset < 0)
|
||||
return cpus_offset;
|
||||
|
||||
/* Find coldboot HART domain DT node offset */
|
||||
cold_domain_offset = -1;
|
||||
cold_hartid = current_hartid();
|
||||
fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
|
||||
err = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
|
||||
if (err)
|
||||
continue;
|
||||
|
||||
if (hartid != cold_hartid)
|
||||
continue;
|
||||
|
||||
val = fdt_getprop(fdt, cpu_offset, "opensbi-domain", &len);
|
||||
if (val && len >= 4)
|
||||
cold_domain_offset = fdt_node_offset_by_phandle(fdt,
|
||||
fdt32_to_cpu(*val));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Iterate over each domain in FDT and populate details */
|
||||
return fdt_iterate_each_domain(fdt, &cold_domain_offset,
|
||||
__fdt_parse_domain);
|
||||
}
|
@@ -9,9 +9,9 @@
|
||||
|
||||
#include <libfdt.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_domain.h>
|
||||
#include <sbi/sbi_math.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/sbi_string.h>
|
||||
#include <sbi_utils/fdt/fdt_fixup.h>
|
||||
@@ -19,9 +19,9 @@
|
||||
|
||||
void fdt_cpu_fixup(void *fdt)
|
||||
{
|
||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
int err, cpu_offset, cpus_offset;
|
||||
struct sbi_domain *dom = sbi_domain_thishart_ptr();
|
||||
int err, cpu_offset, cpus_offset, len;
|
||||
const char *mmu_type;
|
||||
u32 hartid;
|
||||
|
||||
err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 32);
|
||||
@@ -37,7 +37,15 @@ void fdt_cpu_fixup(void *fdt)
|
||||
if (err)
|
||||
continue;
|
||||
|
||||
if (sbi_platform_hart_invalid(plat, hartid))
|
||||
/*
|
||||
* Disable a HART DT node if one of the following is true:
|
||||
* 1. The HART is not assigned to the current domain
|
||||
* 2. MMU is not available for the HART
|
||||
*/
|
||||
|
||||
mmu_type = fdt_getprop(fdt, cpu_offset, "mmu-type", &len);
|
||||
if (!sbi_domain_is_assigned_hart(dom, hartid) ||
|
||||
!mmu_type || !len)
|
||||
fdt_setprop_string(fdt, cpu_offset, "status",
|
||||
"disabled");
|
||||
}
|
||||
@@ -88,11 +96,11 @@ static int fdt_resv_memory_update_node(void *fdt, unsigned long addr,
|
||||
|
||||
if (na > 1 && addr_high)
|
||||
sbi_snprintf(name, sizeof(name),
|
||||
"mmode_pmp%d@%x,%x", index,
|
||||
"mmode_resv%d@%x,%x", index,
|
||||
addr_high, addr_low);
|
||||
else
|
||||
sbi_snprintf(name, sizeof(name),
|
||||
"mmode_pmp%d@%x", index,
|
||||
"mmode_resv%d@%x", index,
|
||||
addr_low);
|
||||
|
||||
subnode = fdt_add_subnode(fdt, parent, name);
|
||||
@@ -144,15 +152,22 @@ static int fdt_resv_memory_update_node(void *fdt, unsigned long addr,
|
||||
*/
|
||||
int fdt_reserved_memory_fixup(void *fdt)
|
||||
{
|
||||
struct sbi_domain_memregion *reg;
|
||||
struct sbi_domain *dom = sbi_domain_thishart_ptr();
|
||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||
unsigned long prot, addr, size;
|
||||
int parent, i, j;
|
||||
int err;
|
||||
unsigned long addr, size;
|
||||
int err, parent, i;
|
||||
int na = fdt_address_cells(fdt, 0);
|
||||
int ns = fdt_size_cells(fdt, 0);
|
||||
|
||||
/* expand the device tree to accommodate new node */
|
||||
err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 256);
|
||||
/*
|
||||
* Expand the device tree to accommodate new node
|
||||
* by the following estimated size:
|
||||
*
|
||||
* Each PMP memory region entry occupies 64 bytes.
|
||||
* With 16 PMP memory regions we need 64 * 16 = 1024 bytes.
|
||||
*/
|
||||
err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 1024);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
@@ -188,34 +203,29 @@ int fdt_reserved_memory_fixup(void *fdt)
|
||||
* We assume the given device tree does not contain any memory region
|
||||
* child node protected by PMP. Normally PMP programming happens at
|
||||
* M-mode firmware. The memory space used by OpenSBI is protected.
|
||||
* Some additional memory spaces may be protected by platform codes.
|
||||
* Some additional memory spaces may be protected by domain memory
|
||||
* regions.
|
||||
*
|
||||
* With above assumption, we create child nodes directly.
|
||||
*/
|
||||
|
||||
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP)) {
|
||||
/*
|
||||
* Update the DT with firmware start & size even if PMP is not
|
||||
* supported. This makes sure that supervisor OS is always
|
||||
* aware of OpenSBI resident memory area.
|
||||
*/
|
||||
addr = scratch->fw_start & ~(scratch->fw_size - 1UL);
|
||||
size = (1UL << log2roundup(scratch->fw_size));
|
||||
return fdt_resv_memory_update_node(fdt, addr, size,
|
||||
0, parent, true);
|
||||
}
|
||||
|
||||
for (i = 0, j = 0; i < sbi_hart_pmp_count(scratch); i++) {
|
||||
err = sbi_hart_pmp_get(scratch, i, &prot, &addr, &size);
|
||||
if (err)
|
||||
i = 0;
|
||||
sbi_domain_for_each_memregion(dom, reg) {
|
||||
/* Ignore MMIO or READABLE or WRITABLE or EXECUTABLE regions */
|
||||
if (reg->flags & SBI_DOMAIN_MEMREGION_MMIO)
|
||||
continue;
|
||||
if (!(prot & PMP_A))
|
||||
if (reg->flags & SBI_DOMAIN_MEMREGION_READABLE)
|
||||
continue;
|
||||
if (prot & (PMP_R | PMP_W | PMP_X))
|
||||
if (reg->flags & SBI_DOMAIN_MEMREGION_WRITEABLE)
|
||||
continue;
|
||||
if (reg->flags & SBI_DOMAIN_MEMREGION_EXECUTABLE)
|
||||
continue;
|
||||
|
||||
fdt_resv_memory_update_node(fdt, addr, size, j, parent, false);
|
||||
j++;
|
||||
addr = reg->base;
|
||||
size = 1UL << reg->order;
|
||||
fdt_resv_memory_update_node(fdt, addr, size, i, parent,
|
||||
(sbi_hart_pmp_count(scratch)) ? false : true);
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@@ -71,10 +71,48 @@ int fdt_find_match(void *fdt, int startoff,
|
||||
return SBI_ENODEV;
|
||||
}
|
||||
|
||||
static int fdt_translate_address(void *fdt, uint64_t reg, int parent,
|
||||
unsigned long *addr)
|
||||
{
|
||||
int i, rlen;
|
||||
int cell_addr, cell_size;
|
||||
const fdt32_t *ranges;
|
||||
uint64_t offset = 0, caddr = 0, paddr = 0, rsize = 0;
|
||||
|
||||
cell_addr = fdt_address_cells(fdt, parent);
|
||||
if (cell_addr < 1)
|
||||
return SBI_ENODEV;
|
||||
|
||||
cell_size = fdt_size_cells(fdt, parent);
|
||||
if (cell_size < 0)
|
||||
return SBI_ENODEV;
|
||||
|
||||
ranges = fdt_getprop(fdt, parent, "ranges", &rlen);
|
||||
if (ranges && rlen > 0) {
|
||||
for (i = 0; i < cell_addr; i++)
|
||||
caddr = (caddr << 32) | fdt32_to_cpu(*ranges++);
|
||||
for (i = 0; i < cell_addr; i++)
|
||||
paddr = (paddr << 32) | fdt32_to_cpu(*ranges++);
|
||||
for (i = 0; i < cell_size; i++)
|
||||
rsize = (rsize << 32) | fdt32_to_cpu(*ranges++);
|
||||
if (reg < caddr || caddr >= (reg + rsize )) {
|
||||
sbi_printf("invalid address translation\n");
|
||||
return SBI_ENODEV;
|
||||
}
|
||||
offset = reg - caddr;
|
||||
*addr = paddr + offset;
|
||||
} else {
|
||||
/* No translation required */
|
||||
*addr = reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_get_node_addr_size(void *fdt, int node, unsigned long *addr,
|
||||
unsigned long *size)
|
||||
{
|
||||
int parent, len, i;
|
||||
int parent, len, i, rc;
|
||||
int cell_addr, cell_size;
|
||||
const fdt32_t *prop_addr, *prop_size;
|
||||
uint64_t temp = 0;
|
||||
@@ -98,7 +136,15 @@ int fdt_get_node_addr_size(void *fdt, int node, unsigned long *addr,
|
||||
if (addr) {
|
||||
for (i = 0; i < cell_addr; i++)
|
||||
temp = (temp << 32) | fdt32_to_cpu(*prop_addr++);
|
||||
*addr = temp;
|
||||
do {
|
||||
if (parent < 0)
|
||||
break;
|
||||
rc = fdt_translate_address(fdt, temp, parent, addr);
|
||||
if (rc)
|
||||
break;
|
||||
parent = fdt_parent_offset(fdt, parent);
|
||||
temp = *addr;
|
||||
} while (1);
|
||||
}
|
||||
temp = 0;
|
||||
|
||||
@@ -123,7 +169,7 @@ int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid)
|
||||
prop = fdt_getprop(fdt, cpu_offset, "device_type", &len);
|
||||
if (!prop || !len)
|
||||
return SBI_EINVAL;
|
||||
if (sbi_strcmp(prop, "cpu"))
|
||||
if (strncmp (prop, "cpu", strlen ("cpu")))
|
||||
return SBI_EINVAL;
|
||||
|
||||
val = fdt_getprop(fdt, cpu_offset, "reg", &len);
|
||||
|
@@ -4,5 +4,6 @@
|
||||
# Copyright (C) 2020 Bin Meng <bmeng.cn@gmail.com>
|
||||
#
|
||||
|
||||
libsbiutils-objs-y += fdt/fdt_domain.o
|
||||
libsbiutils-objs-y += fdt/fdt_helper.o
|
||||
libsbiutils-objs-y += fdt/fdt_fixup.o
|
||||
|
@@ -8,7 +8,7 @@ LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1
|
||||
LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h
|
||||
LIBFDT_VERSION = version.lds
|
||||
LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \
|
||||
fdt_addresses.c fdt_overlay.c
|
||||
fdt_addresses.c fdt_overlay.c fdt_check.c
|
||||
LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
|
||||
LIBFDT_LIB = libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT)
|
||||
|
||||
|
@@ -19,15 +19,21 @@ int32_t fdt_ro_probe_(const void *fdt)
|
||||
{
|
||||
uint32_t totalsize = fdt_totalsize(fdt);
|
||||
|
||||
if (can_assume(VALID_DTB))
|
||||
return totalsize;
|
||||
|
||||
if (fdt_magic(fdt) == FDT_MAGIC) {
|
||||
/* Complete tree */
|
||||
if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
|
||||
return -FDT_ERR_BADVERSION;
|
||||
if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
|
||||
return -FDT_ERR_BADVERSION;
|
||||
if (!can_assume(LATEST)) {
|
||||
if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
|
||||
return -FDT_ERR_BADVERSION;
|
||||
if (fdt_last_comp_version(fdt) >
|
||||
FDT_LAST_SUPPORTED_VERSION)
|
||||
return -FDT_ERR_BADVERSION;
|
||||
}
|
||||
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
|
||||
/* Unfinished sequential-write blob */
|
||||
if (fdt_size_dt_struct(fdt) == 0)
|
||||
if (!can_assume(VALID_INPUT) && fdt_size_dt_struct(fdt) == 0)
|
||||
return -FDT_ERR_BADSTATE;
|
||||
} else {
|
||||
return -FDT_ERR_BADMAGIC;
|
||||
@@ -70,43 +76,58 @@ size_t fdt_header_size_(uint32_t version)
|
||||
return FDT_V17_SIZE;
|
||||
}
|
||||
|
||||
size_t fdt_header_size(const void *fdt)
|
||||
{
|
||||
return can_assume(LATEST) ? FDT_V17_SIZE :
|
||||
fdt_header_size_(fdt_version(fdt));
|
||||
}
|
||||
|
||||
int fdt_check_header(const void *fdt)
|
||||
{
|
||||
size_t hdrsize;
|
||||
|
||||
if (fdt_magic(fdt) != FDT_MAGIC)
|
||||
return -FDT_ERR_BADMAGIC;
|
||||
if (!can_assume(LATEST)) {
|
||||
if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
|
||||
|| (fdt_last_comp_version(fdt) >
|
||||
FDT_LAST_SUPPORTED_VERSION))
|
||||
return -FDT_ERR_BADVERSION;
|
||||
if (fdt_version(fdt) < fdt_last_comp_version(fdt))
|
||||
return -FDT_ERR_BADVERSION;
|
||||
}
|
||||
hdrsize = fdt_header_size(fdt);
|
||||
if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
|
||||
|| (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION))
|
||||
return -FDT_ERR_BADVERSION;
|
||||
if (fdt_version(fdt) < fdt_last_comp_version(fdt))
|
||||
return -FDT_ERR_BADVERSION;
|
||||
if (!can_assume(VALID_DTB)) {
|
||||
|
||||
if ((fdt_totalsize(fdt) < hdrsize)
|
||||
|| (fdt_totalsize(fdt) > INT_MAX))
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
|
||||
/* Bounds check memrsv block */
|
||||
if (!check_off_(hdrsize, fdt_totalsize(fdt), fdt_off_mem_rsvmap(fdt)))
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
|
||||
/* Bounds check structure block */
|
||||
if (fdt_version(fdt) < 17) {
|
||||
if (!check_off_(hdrsize, fdt_totalsize(fdt),
|
||||
fdt_off_dt_struct(fdt)))
|
||||
if ((fdt_totalsize(fdt) < hdrsize)
|
||||
|| (fdt_totalsize(fdt) > INT_MAX))
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
} else {
|
||||
if (!check_block_(hdrsize, fdt_totalsize(fdt),
|
||||
fdt_off_dt_struct(fdt),
|
||||
fdt_size_dt_struct(fdt)))
|
||||
|
||||
/* Bounds check memrsv block */
|
||||
if (!check_off_(hdrsize, fdt_totalsize(fdt),
|
||||
fdt_off_mem_rsvmap(fdt)))
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
}
|
||||
|
||||
/* Bounds check strings block */
|
||||
if (!check_block_(hdrsize, fdt_totalsize(fdt),
|
||||
fdt_off_dt_strings(fdt), fdt_size_dt_strings(fdt)))
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
if (!can_assume(VALID_DTB)) {
|
||||
/* Bounds check structure block */
|
||||
if (!can_assume(LATEST) && fdt_version(fdt) < 17) {
|
||||
if (!check_off_(hdrsize, fdt_totalsize(fdt),
|
||||
fdt_off_dt_struct(fdt)))
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
} else {
|
||||
if (!check_block_(hdrsize, fdt_totalsize(fdt),
|
||||
fdt_off_dt_struct(fdt),
|
||||
fdt_size_dt_struct(fdt)))
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
}
|
||||
|
||||
/* Bounds check strings block */
|
||||
if (!check_block_(hdrsize, fdt_totalsize(fdt),
|
||||
fdt_off_dt_strings(fdt),
|
||||
fdt_size_dt_strings(fdt)))
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -115,12 +136,13 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
|
||||
{
|
||||
unsigned absoffset = offset + fdt_off_dt_struct(fdt);
|
||||
|
||||
if ((absoffset < offset)
|
||||
|| ((absoffset + len) < absoffset)
|
||||
|| (absoffset + len) > fdt_totalsize(fdt))
|
||||
return NULL;
|
||||
if (!can_assume(VALID_INPUT))
|
||||
if ((absoffset < offset)
|
||||
|| ((absoffset + len) < absoffset)
|
||||
|| (absoffset + len) > fdt_totalsize(fdt))
|
||||
return NULL;
|
||||
|
||||
if (fdt_version(fdt) >= 0x11)
|
||||
if (can_assume(LATEST) || fdt_version(fdt) >= 0x11)
|
||||
if (((offset + len) < offset)
|
||||
|| ((offset + len) > fdt_size_dt_struct(fdt)))
|
||||
return NULL;
|
||||
@@ -137,7 +159,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
|
||||
|
||||
*nextoffset = -FDT_ERR_TRUNCATED;
|
||||
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
|
||||
if (!tagp)
|
||||
if (!can_assume(VALID_DTB) && !tagp)
|
||||
return FDT_END; /* premature end */
|
||||
tag = fdt32_to_cpu(*tagp);
|
||||
offset += FDT_TAGSIZE;
|
||||
@@ -149,18 +171,19 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
|
||||
do {
|
||||
p = fdt_offset_ptr(fdt, offset++, 1);
|
||||
} while (p && (*p != '\0'));
|
||||
if (!p)
|
||||
if (!can_assume(VALID_DTB) && !p)
|
||||
return FDT_END; /* premature end */
|
||||
break;
|
||||
|
||||
case FDT_PROP:
|
||||
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
|
||||
if (!lenp)
|
||||
if (!can_assume(VALID_DTB) && !lenp)
|
||||
return FDT_END; /* premature end */
|
||||
/* skip-name offset, length and value */
|
||||
offset += sizeof(struct fdt_property) - FDT_TAGSIZE
|
||||
+ fdt32_to_cpu(*lenp);
|
||||
if (fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
|
||||
if (!can_assume(LATEST) &&
|
||||
fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
|
||||
((offset - fdt32_to_cpu(*lenp)) % 8) != 0)
|
||||
offset += 4;
|
||||
break;
|
||||
@@ -183,6 +206,8 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
|
||||
|
||||
int fdt_check_node_offset_(const void *fdt, int offset)
|
||||
{
|
||||
if (can_assume(VALID_INPUT))
|
||||
return offset;
|
||||
if ((offset < 0) || (offset % FDT_TAGSIZE)
|
||||
|| (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
|
74
lib/utils/libfdt/fdt_check.c
Normal file
74
lib/utils/libfdt/fdt_check.c
Normal file
@@ -0,0 +1,74 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
int fdt_check_full(const void *fdt, size_t bufsize)
|
||||
{
|
||||
int err;
|
||||
int num_memrsv;
|
||||
int offset, nextoffset = 0;
|
||||
uint32_t tag;
|
||||
unsigned int depth = 0;
|
||||
const void *prop;
|
||||
const char *propname;
|
||||
|
||||
if (bufsize < FDT_V1_SIZE)
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
err = fdt_check_header(fdt);
|
||||
if (err != 0)
|
||||
return err;
|
||||
if (bufsize < fdt_totalsize(fdt))
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
|
||||
num_memrsv = fdt_num_mem_rsv(fdt);
|
||||
if (num_memrsv < 0)
|
||||
return num_memrsv;
|
||||
|
||||
while (1) {
|
||||
offset = nextoffset;
|
||||
tag = fdt_next_tag(fdt, offset, &nextoffset);
|
||||
|
||||
if (nextoffset < 0)
|
||||
return nextoffset;
|
||||
|
||||
switch (tag) {
|
||||
case FDT_NOP:
|
||||
break;
|
||||
|
||||
case FDT_END:
|
||||
if (depth != 0)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
return 0;
|
||||
|
||||
case FDT_BEGIN_NODE:
|
||||
depth++;
|
||||
if (depth > INT_MAX)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
break;
|
||||
|
||||
case FDT_END_NODE:
|
||||
if (depth == 0)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
depth--;
|
||||
break;
|
||||
|
||||
case FDT_PROP:
|
||||
prop = fdt_getprop_by_offset(fdt, offset, &propname,
|
||||
&err);
|
||||
if (!prop)
|
||||
return err;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -FDT_ERR_INTERNAL;
|
||||
}
|
||||
}
|
||||
}
|
@@ -752,7 +752,7 @@ static int overlay_symbol_update(void *fdt, void *fdto)
|
||||
if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) {
|
||||
/* /<fragment-name>/__overlay__/<relative-subnode-path> */
|
||||
rel_path = s + len;
|
||||
rel_path_len = e - rel_path;
|
||||
rel_path_len = e - rel_path - 1;
|
||||
} else if ((e - s) == len
|
||||
&& (memcmp(s, "/__overlay__", len - 1) == 0)) {
|
||||
/* /<fragment-name>/__overlay__ */
|
||||
|
@@ -33,17 +33,26 @@ static int fdt_nodename_eq_(const void *fdt, int offset,
|
||||
|
||||
const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
|
||||
{
|
||||
int32_t totalsize = fdt_ro_probe_(fdt);
|
||||
uint32_t absoffset = stroffset + fdt_off_dt_strings(fdt);
|
||||
int32_t totalsize;
|
||||
uint32_t absoffset;
|
||||
size_t len;
|
||||
int err;
|
||||
const char *s, *n;
|
||||
|
||||
if (can_assume(VALID_INPUT)) {
|
||||
s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
|
||||
|
||||
if (lenp)
|
||||
*lenp = strlen(s);
|
||||
return s;
|
||||
}
|
||||
totalsize = fdt_ro_probe_(fdt);
|
||||
err = totalsize;
|
||||
if (totalsize < 0)
|
||||
goto fail;
|
||||
|
||||
err = -FDT_ERR_BADOFFSET;
|
||||
absoffset = stroffset + fdt_off_dt_strings(fdt);
|
||||
if (absoffset >= totalsize)
|
||||
goto fail;
|
||||
len = totalsize - absoffset;
|
||||
@@ -51,7 +60,7 @@ const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
|
||||
if (fdt_magic(fdt) == FDT_MAGIC) {
|
||||
if (stroffset < 0)
|
||||
goto fail;
|
||||
if (fdt_version(fdt) >= 17) {
|
||||
if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
|
||||
if (stroffset >= fdt_size_dt_strings(fdt))
|
||||
goto fail;
|
||||
if ((fdt_size_dt_strings(fdt) - stroffset) < len)
|
||||
@@ -151,10 +160,13 @@ static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
|
||||
int offset = n * sizeof(struct fdt_reserve_entry);
|
||||
int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
|
||||
|
||||
if (absoffset < fdt_off_mem_rsvmap(fdt))
|
||||
return NULL;
|
||||
if (absoffset > fdt_totalsize(fdt) - sizeof(struct fdt_reserve_entry))
|
||||
return NULL;
|
||||
if (!can_assume(VALID_INPUT)) {
|
||||
if (absoffset < fdt_off_mem_rsvmap(fdt))
|
||||
return NULL;
|
||||
if (absoffset > fdt_totalsize(fdt) -
|
||||
sizeof(struct fdt_reserve_entry))
|
||||
return NULL;
|
||||
}
|
||||
return fdt_mem_rsv_(fdt, n);
|
||||
}
|
||||
|
||||
@@ -164,7 +176,7 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
|
||||
|
||||
FDT_RO_PROBE(fdt);
|
||||
re = fdt_mem_rsv(fdt, n);
|
||||
if (!re)
|
||||
if (!can_assume(VALID_INPUT) && !re)
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
|
||||
*address = fdt64_ld(&re->address);
|
||||
@@ -295,7 +307,7 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
|
||||
|
||||
nameptr = nh->name;
|
||||
|
||||
if (fdt_version(fdt) < 0x10) {
|
||||
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
|
||||
/*
|
||||
* For old FDT versions, match the naming conventions of V16:
|
||||
* give only the leaf name (after all /). The actual tree
|
||||
@@ -346,7 +358,8 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
|
||||
int err;
|
||||
const struct fdt_property *prop;
|
||||
|
||||
if ((err = fdt_check_prop_offset_(fdt, offset)) < 0) {
|
||||
if (!can_assume(VALID_INPUT) &&
|
||||
(err = fdt_check_prop_offset_(fdt, offset)) < 0) {
|
||||
if (lenp)
|
||||
*lenp = err;
|
||||
return NULL;
|
||||
@@ -367,7 +380,7 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
|
||||
/* Prior to version 16, properties may need realignment
|
||||
* and this API does not work. fdt_getprop_*() will, however. */
|
||||
|
||||
if (fdt_version(fdt) < 0x10) {
|
||||
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
|
||||
if (lenp)
|
||||
*lenp = -FDT_ERR_BADVERSION;
|
||||
return NULL;
|
||||
@@ -388,7 +401,8 @@ static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
|
||||
(offset = fdt_next_property_offset(fdt, offset))) {
|
||||
const struct fdt_property *prop;
|
||||
|
||||
if (!(prop = fdt_get_property_by_offset_(fdt, offset, lenp))) {
|
||||
prop = fdt_get_property_by_offset_(fdt, offset, lenp);
|
||||
if (!can_assume(LIBFDT_FLAWLESS) && !prop) {
|
||||
offset = -FDT_ERR_INTERNAL;
|
||||
break;
|
||||
}
|
||||
@@ -413,7 +427,7 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt,
|
||||
{
|
||||
/* Prior to version 16, properties may need realignment
|
||||
* and this API does not work. fdt_getprop_*() will, however. */
|
||||
if (fdt_version(fdt) < 0x10) {
|
||||
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
|
||||
if (lenp)
|
||||
*lenp = -FDT_ERR_BADVERSION;
|
||||
return NULL;
|
||||
@@ -444,8 +458,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
|
||||
return NULL;
|
||||
|
||||
/* Handle realignment */
|
||||
if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 &&
|
||||
fdt32_ld(&prop->len) >= 8)
|
||||
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
|
||||
(poffset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
|
||||
return prop->data + 4;
|
||||
return prop->data;
|
||||
}
|
||||
@@ -461,19 +475,24 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
|
||||
if (namep) {
|
||||
const char *name;
|
||||
int namelen;
|
||||
name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
|
||||
&namelen);
|
||||
if (!name) {
|
||||
if (lenp)
|
||||
*lenp = namelen;
|
||||
return NULL;
|
||||
|
||||
if (!can_assume(VALID_INPUT)) {
|
||||
name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
|
||||
&namelen);
|
||||
if (!name) {
|
||||
if (lenp)
|
||||
*lenp = namelen;
|
||||
return NULL;
|
||||
}
|
||||
*namep = name;
|
||||
} else {
|
||||
*namep = fdt_string(fdt, fdt32_ld(&prop->nameoff));
|
||||
}
|
||||
*namep = name;
|
||||
}
|
||||
|
||||
/* Handle realignment */
|
||||
if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 &&
|
||||
fdt32_ld(&prop->len) >= 8)
|
||||
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
|
||||
(offset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
|
||||
return prop->data + 4;
|
||||
return prop->data;
|
||||
}
|
||||
@@ -598,10 +617,12 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
|
||||
}
|
||||
}
|
||||
|
||||
if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
else if (offset == -FDT_ERR_BADOFFSET)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
if (!can_assume(VALID_INPUT)) {
|
||||
if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
else if (offset == -FDT_ERR_BADOFFSET)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
}
|
||||
|
||||
return offset; /* error from fdt_next_node() */
|
||||
}
|
||||
@@ -613,7 +634,8 @@ int fdt_node_depth(const void *fdt, int nodeoffset)
|
||||
|
||||
err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
|
||||
if (err)
|
||||
return (err < 0) ? err : -FDT_ERR_INTERNAL;
|
||||
return (can_assume(LIBFDT_FLAWLESS) || err < 0) ? err :
|
||||
-FDT_ERR_INTERNAL;
|
||||
return nodedepth;
|
||||
}
|
||||
|
||||
@@ -833,66 +855,3 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
|
||||
|
||||
return offset; /* error from fdt_next_node() */
|
||||
}
|
||||
|
||||
int fdt_check_full(const void *fdt, size_t bufsize)
|
||||
{
|
||||
int err;
|
||||
int num_memrsv;
|
||||
int offset, nextoffset = 0;
|
||||
uint32_t tag;
|
||||
unsigned depth = 0;
|
||||
const void *prop;
|
||||
const char *propname;
|
||||
|
||||
if (bufsize < FDT_V1_SIZE)
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
err = fdt_check_header(fdt);
|
||||
if (err != 0)
|
||||
return err;
|
||||
if (bufsize < fdt_totalsize(fdt))
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
|
||||
num_memrsv = fdt_num_mem_rsv(fdt);
|
||||
if (num_memrsv < 0)
|
||||
return num_memrsv;
|
||||
|
||||
while (1) {
|
||||
offset = nextoffset;
|
||||
tag = fdt_next_tag(fdt, offset, &nextoffset);
|
||||
|
||||
if (nextoffset < 0)
|
||||
return nextoffset;
|
||||
|
||||
switch (tag) {
|
||||
case FDT_NOP:
|
||||
break;
|
||||
|
||||
case FDT_END:
|
||||
if (depth != 0)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
return 0;
|
||||
|
||||
case FDT_BEGIN_NODE:
|
||||
depth++;
|
||||
if (depth > INT_MAX)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
break;
|
||||
|
||||
case FDT_END_NODE:
|
||||
if (depth == 0)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
depth--;
|
||||
break;
|
||||
|
||||
case FDT_PROP:
|
||||
prop = fdt_getprop_by_offset(fdt, offset, &propname,
|
||||
&err);
|
||||
if (!prop)
|
||||
return err;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -FDT_ERR_INTERNAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -24,14 +24,16 @@ static int fdt_blocks_misordered_(const void *fdt,
|
||||
|
||||
static int fdt_rw_probe_(void *fdt)
|
||||
{
|
||||
if (can_assume(VALID_DTB))
|
||||
return 0;
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
if (fdt_version(fdt) < 17)
|
||||
if (!can_assume(LATEST) && fdt_version(fdt) < 17)
|
||||
return -FDT_ERR_BADVERSION;
|
||||
if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry),
|
||||
fdt_size_dt_struct(fdt)))
|
||||
return -FDT_ERR_BADLAYOUT;
|
||||
if (fdt_version(fdt) > 17)
|
||||
if (!can_assume(LATEST) && fdt_version(fdt) > 17)
|
||||
fdt_set_version(fdt, 17);
|
||||
|
||||
return 0;
|
||||
@@ -112,6 +114,15 @@ static int fdt_splice_string_(void *fdt, int newlen)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fdt_find_add_string_() - Find or allocate a string
|
||||
*
|
||||
* @fdt: pointer to the device tree to check/adjust
|
||||
* @s: string to find/add
|
||||
* @allocated: Set to 0 if the string was found, 1 if not found and so
|
||||
* allocated. Ignored if can_assume(NO_ROLLBACK)
|
||||
* @return offset of string in the string table (whether found or added)
|
||||
*/
|
||||
static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
|
||||
{
|
||||
char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
|
||||
@@ -120,7 +131,8 @@ static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
|
||||
int len = strlen(s) + 1;
|
||||
int err;
|
||||
|
||||
*allocated = 0;
|
||||
if (!can_assume(NO_ROLLBACK))
|
||||
*allocated = 0;
|
||||
|
||||
p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s);
|
||||
if (p)
|
||||
@@ -132,7 +144,8 @@ static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
*allocated = 1;
|
||||
if (!can_assume(NO_ROLLBACK))
|
||||
*allocated = 1;
|
||||
|
||||
memcpy(new, s, len);
|
||||
return (new - strtab);
|
||||
@@ -206,7 +219,8 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
|
||||
|
||||
err = fdt_splice_struct_(fdt, *prop, 0, proplen);
|
||||
if (err) {
|
||||
if (allocated)
|
||||
/* Delete the string if we failed to add it */
|
||||
if (!can_assume(NO_ROLLBACK) && allocated)
|
||||
fdt_del_last_string_(fdt, name);
|
||||
return err;
|
||||
}
|
||||
@@ -411,7 +425,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
|
||||
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
|
||||
* sizeof(struct fdt_reserve_entry);
|
||||
|
||||
if (fdt_version(fdt) >= 17) {
|
||||
if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
|
||||
struct_size = fdt_size_dt_struct(fdt);
|
||||
} else {
|
||||
struct_size = 0;
|
||||
@@ -421,7 +435,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
|
||||
return struct_size;
|
||||
}
|
||||
|
||||
if (!fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) {
|
||||
if (can_assume(LIBFDT_ORDER) |
|
||||
!fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) {
|
||||
/* no further work necessary */
|
||||
err = fdt_move(fdt, buf, bufsize);
|
||||
if (err)
|
||||
|
@@ -12,10 +12,13 @@
|
||||
|
||||
static int fdt_sw_probe_(void *fdt)
|
||||
{
|
||||
if (fdt_magic(fdt) == FDT_MAGIC)
|
||||
return -FDT_ERR_BADSTATE;
|
||||
else if (fdt_magic(fdt) != FDT_SW_MAGIC)
|
||||
return -FDT_ERR_BADMAGIC;
|
||||
if (!can_assume(VALID_INPUT)) {
|
||||
if (fdt_magic(fdt) == FDT_MAGIC)
|
||||
return -FDT_ERR_BADSTATE;
|
||||
else if (fdt_magic(fdt) != FDT_SW_MAGIC)
|
||||
return -FDT_ERR_BADMAGIC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -38,7 +41,7 @@ static int fdt_sw_probe_memrsv_(void *fdt)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (fdt_off_dt_strings(fdt) != 0)
|
||||
if (!can_assume(VALID_INPUT) && fdt_off_dt_strings(fdt) != 0)
|
||||
return -FDT_ERR_BADSTATE;
|
||||
return 0;
|
||||
}
|
||||
@@ -64,7 +67,8 @@ static int fdt_sw_probe_struct_(void *fdt)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (fdt_off_dt_strings(fdt) != fdt_totalsize(fdt))
|
||||
if (!can_assume(VALID_INPUT) &&
|
||||
fdt_off_dt_strings(fdt) != fdt_totalsize(fdt))
|
||||
return -FDT_ERR_BADSTATE;
|
||||
return 0;
|
||||
}
|
||||
@@ -151,7 +155,8 @@ int fdt_resize(void *fdt, void *buf, int bufsize)
|
||||
headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
|
||||
tailsize = fdt_size_dt_strings(fdt);
|
||||
|
||||
if ((headsize + tailsize) > fdt_totalsize(fdt))
|
||||
if (!can_assume(VALID_DTB) &&
|
||||
headsize + tailsize > fdt_totalsize(fdt))
|
||||
return -FDT_ERR_INTERNAL;
|
||||
|
||||
if ((headsize + tailsize) > bufsize)
|
||||
|
@@ -136,7 +136,7 @@ static inline uint32_t fdt32_ld(const fdt32_t *p)
|
||||
|
||||
static inline void fdt32_st(void *property, uint32_t value)
|
||||
{
|
||||
uint8_t *bp = property;
|
||||
uint8_t *bp = (uint8_t *)property;
|
||||
|
||||
bp[0] = value >> 24;
|
||||
bp[1] = (value >> 16) & 0xff;
|
||||
@@ -160,7 +160,7 @@ static inline uint64_t fdt64_ld(const fdt64_t *p)
|
||||
|
||||
static inline void fdt64_st(void *property, uint64_t value)
|
||||
{
|
||||
uint8_t *bp = property;
|
||||
uint8_t *bp = (uint8_t *)property;
|
||||
|
||||
bp[0] = value >> 56;
|
||||
bp[1] = (value >> 48) & 0xff;
|
||||
@@ -266,11 +266,12 @@ fdt_set_hdr_(size_dt_struct);
|
||||
* fdt_header_size - return the size of the tree's header
|
||||
* @fdt: pointer to a flattened device tree
|
||||
*/
|
||||
size_t fdt_header_size(const void *fdt);
|
||||
|
||||
/**
|
||||
* fdt_header_size_ - internal function which takes a version number
|
||||
*/
|
||||
size_t fdt_header_size_(uint32_t version);
|
||||
static inline size_t fdt_header_size(const void *fdt)
|
||||
{
|
||||
return fdt_header_size_(fdt_version(fdt));
|
||||
}
|
||||
|
||||
/**
|
||||
* fdt_check_header - sanity check a device tree header
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#define strrchr sbi_strrchr
|
||||
#define strcpy sbi_strcpy
|
||||
#define strcmp sbi_strcmp
|
||||
#define strncmp sbi_strncmp
|
||||
#define strlen sbi_strlen
|
||||
#define strnlen sbi_strnlen
|
||||
|
||||
|
@@ -10,10 +10,10 @@
|
||||
#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
|
||||
#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
|
||||
|
||||
int fdt_ro_probe_(const void *fdt);
|
||||
int32_t fdt_ro_probe_(const void *fdt);
|
||||
#define FDT_RO_PROBE(fdt) \
|
||||
{ \
|
||||
int totalsize_; \
|
||||
int32_t totalsize_; \
|
||||
if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \
|
||||
return totalsize_; \
|
||||
}
|
||||
@@ -48,4 +48,126 @@ static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n)
|
||||
|
||||
#define FDT_SW_MAGIC (~FDT_MAGIC)
|
||||
|
||||
/**********************************************************************/
|
||||
/* Checking controls */
|
||||
/**********************************************************************/
|
||||
|
||||
#ifndef FDT_ASSUME_MASK
|
||||
#define FDT_ASSUME_MASK 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Defines assumptions which can be enabled. Each of these can be enabled
|
||||
* individually. For maximum safety, don't enable any assumptions!
|
||||
*
|
||||
* For minimal code size and no safety, use ASSUME_PERFECT at your own risk.
|
||||
* You should have another method of validating the device tree, such as a
|
||||
* signature or hash check before using libfdt.
|
||||
*
|
||||
* For situations where security is not a concern it may be safe to enable
|
||||
* ASSUME_SANE.
|
||||
*/
|
||||
enum {
|
||||
/*
|
||||
* This does essentially no checks. Only the latest device-tree
|
||||
* version is correctly handled. Inconsistencies or errors in the device
|
||||
* tree may cause undefined behaviour or crashes. Invalid parameters
|
||||
* passed to libfdt may do the same.
|
||||
*
|
||||
* If an error occurs when modifying the tree it may leave the tree in
|
||||
* an intermediate (but valid) state. As an example, adding a property
|
||||
* where there is insufficient space may result in the property name
|
||||
* being added to the string table even though the property itself is
|
||||
* not added to the struct section.
|
||||
*
|
||||
* Only use this if you have a fully validated device tree with
|
||||
* the latest supported version and wish to minimise code size.
|
||||
*/
|
||||
ASSUME_PERFECT = 0xff,
|
||||
|
||||
/*
|
||||
* This assumes that the device tree is sane. i.e. header metadata
|
||||
* and basic hierarchy are correct.
|
||||
*
|
||||
* With this assumption enabled, normal device trees produced by libfdt
|
||||
* and the compiler should be handled safely. Malicious device trees and
|
||||
* complete garbage may cause libfdt to behave badly or crash. Truncated
|
||||
* device trees (e.g. those only partially loaded) can also cause
|
||||
* problems.
|
||||
*
|
||||
* Note: Only checks that relate exclusively to the device tree itself
|
||||
* (not the parameters passed to libfdt) are disabled by this
|
||||
* assumption. This includes checking headers, tags and the like.
|
||||
*/
|
||||
ASSUME_VALID_DTB = 1 << 0,
|
||||
|
||||
/*
|
||||
* This builds on ASSUME_VALID_DTB and further assumes that libfdt
|
||||
* functions are called with valid parameters, i.e. not trigger
|
||||
* FDT_ERR_BADOFFSET or offsets that are out of bounds. It disables any
|
||||
* extensive checking of parameters and the device tree, making various
|
||||
* assumptions about correctness.
|
||||
*
|
||||
* It doesn't make sense to enable this assumption unless
|
||||
* ASSUME_VALID_DTB is also enabled.
|
||||
*/
|
||||
ASSUME_VALID_INPUT = 1 << 1,
|
||||
|
||||
/*
|
||||
* This disables checks for device-tree version and removes all code
|
||||
* which handles older versions.
|
||||
*
|
||||
* Only enable this if you know you have a device tree with the latest
|
||||
* version.
|
||||
*/
|
||||
ASSUME_LATEST = 1 << 2,
|
||||
|
||||
/*
|
||||
* This assumes that it is OK for a failed addition to the device tree,
|
||||
* due to lack of space or some other problem, to skip any rollback
|
||||
* steps (such as dropping the property name from the string table).
|
||||
* This is safe to enable in most circumstances, even though it may
|
||||
* leave the tree in a sub-optimal state.
|
||||
*/
|
||||
ASSUME_NO_ROLLBACK = 1 << 3,
|
||||
|
||||
/*
|
||||
* This assumes that the device tree components appear in a 'convenient'
|
||||
* order, i.e. the memory reservation block first, then the structure
|
||||
* block and finally the string block.
|
||||
*
|
||||
* This order is not specified by the device-tree specification,
|
||||
* but is expected by libfdt. The device-tree compiler always created
|
||||
* device trees with this order.
|
||||
*
|
||||
* This assumption disables a check in fdt_open_into() and removes the
|
||||
* ability to fix the problem there. This is safe if you know that the
|
||||
* device tree is correctly ordered. See fdt_blocks_misordered_().
|
||||
*/
|
||||
ASSUME_LIBFDT_ORDER = 1 << 4,
|
||||
|
||||
/*
|
||||
* This assumes that libfdt itself does not have any internal bugs. It
|
||||
* drops certain checks that should never be needed unless libfdt has an
|
||||
* undiscovered bug.
|
||||
*
|
||||
* This can generally be considered safe to enable.
|
||||
*/
|
||||
ASSUME_LIBFDT_FLAWLESS = 1 << 5,
|
||||
};
|
||||
|
||||
/**
|
||||
* can_assume_() - check if a particular assumption is enabled
|
||||
*
|
||||
* @mask: Mask to check (ASSUME_...)
|
||||
* @return true if that assumption is enabled, else false
|
||||
*/
|
||||
static inline bool can_assume_(int mask)
|
||||
{
|
||||
return FDT_ASSUME_MASK & mask;
|
||||
}
|
||||
|
||||
/** helper macros for checking assumptions */
|
||||
#define can_assume(_assume) can_assume_(ASSUME_ ## _assume)
|
||||
|
||||
#endif /* LIBFDT_INTERNAL_H */
|
||||
|
@@ -7,7 +7,7 @@
|
||||
# Atish Patra<atish.patra@wdc.com>
|
||||
#
|
||||
|
||||
libfdt_files = fdt.o fdt_addresses.o fdt_empty_tree.o fdt_ro.o fdt_rw.o \
|
||||
libfdt_files = fdt.o fdt_addresses.o fdt_check.o fdt_empty_tree.o fdt_ro.o fdt_rw.o \
|
||||
fdt_strerror.o fdt_sw.o fdt_wip.o
|
||||
$(foreach file, $(libfdt_files), \
|
||||
$(eval CFLAGS_$(file) = -I$(src)/../../utils/libfdt))
|
||||
|
@@ -20,6 +20,7 @@ LIBFDT_1.2 {
|
||||
fdt_get_alias_namelen;
|
||||
fdt_get_alias;
|
||||
fdt_get_path;
|
||||
fdt_header_size;
|
||||
fdt_supernode_atdepth_offset;
|
||||
fdt_node_depth;
|
||||
fdt_parent_offset;
|
||||
|
@@ -21,11 +21,18 @@ static struct fdt_reset *reset_drivers[] = {
|
||||
|
||||
static struct fdt_reset *current_driver = NULL;
|
||||
|
||||
int fdt_system_reset(u32 reset_type)
|
||||
int fdt_system_reset_check(u32 reset_type, u32 reset_reason)
|
||||
{
|
||||
if (current_driver && current_driver->system_reset_check)
|
||||
return current_driver->system_reset_check(reset_type,
|
||||
reset_reason);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fdt_system_reset(u32 reset_type, u32 reset_reason)
|
||||
{
|
||||
if (current_driver && current_driver->system_reset)
|
||||
return current_driver->system_reset(reset_type);
|
||||
return 0;
|
||||
current_driver->system_reset(reset_type, reset_reason);
|
||||
}
|
||||
|
||||
int fdt_reset_init(void)
|
||||
|
@@ -18,5 +18,6 @@ static const struct fdt_match htif_reset_match[] = {
|
||||
|
||||
struct fdt_reset fdt_reset_htif = {
|
||||
.match_table = htif_reset_match,
|
||||
.system_reset_check = htif_system_reset_check,
|
||||
.system_reset = htif_system_reset
|
||||
};
|
||||
|
@@ -33,5 +33,6 @@ static const struct fdt_match sifive_test_reset_match[] = {
|
||||
struct fdt_reset fdt_reset_sifive = {
|
||||
.match_table = sifive_test_reset_match,
|
||||
.init = sifive_test_reset_init,
|
||||
.system_reset_check = sifive_test_system_reset_check,
|
||||
.system_reset = sifive_test_system_reset
|
||||
};
|
||||
|
@@ -18,18 +18,22 @@
|
||||
#define REG_IQ_CYCLES 0x1C
|
||||
#define REG_RX_THRES 0x20
|
||||
|
||||
#define UART_TX_FULL 0x2
|
||||
#define UART_RX_FULL 0x8
|
||||
|
||||
static volatile void *uart_base;
|
||||
|
||||
void shakti_uart_putc(char ch)
|
||||
{
|
||||
while((readw(uart_base + REG_STATUS) & 0x2) == 0);
|
||||
while((readw(uart_base + REG_STATUS) & UART_TX_FULL))
|
||||
;
|
||||
writeb(ch, uart_base + REG_TX);
|
||||
}
|
||||
|
||||
int shakti_uart_getc(void)
|
||||
{
|
||||
u16 status = readw(uart_base + REG_STATUS);
|
||||
if (status & 0x8)
|
||||
if (status & UART_RX_FULL)
|
||||
return readb(uart_base + REG_RX);
|
||||
return -1;
|
||||
}
|
||||
|
@@ -140,7 +140,12 @@ int htif_getc(void)
|
||||
return ch - 1;
|
||||
}
|
||||
|
||||
int htif_system_reset(u32 type)
|
||||
int htif_system_reset_check(u32 type, u32 reason)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void htif_system_reset(u32 type, u32 reason)
|
||||
{
|
||||
while (1) {
|
||||
fromhost = 0;
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_io.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi_utils/sys/sifive_test.h>
|
||||
|
||||
#define FINISHER_FAIL 0x3333
|
||||
@@ -17,23 +17,36 @@
|
||||
|
||||
static void *sifive_test_base;
|
||||
|
||||
int sifive_test_system_reset(u32 type)
|
||||
int sifive_test_system_reset_check(u32 type, u32 reason)
|
||||
{
|
||||
switch (type) {
|
||||
case SBI_SRST_RESET_TYPE_SHUTDOWN:
|
||||
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
|
||||
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sifive_test_system_reset(u32 type, u32 reason)
|
||||
{
|
||||
/*
|
||||
* Tell the "finisher" that the simulation
|
||||
* was successful so that QEMU exits
|
||||
*/
|
||||
switch (type) {
|
||||
case SBI_PLATFORM_RESET_SHUTDOWN:
|
||||
writew(FINISHER_PASS, sifive_test_base);
|
||||
case SBI_SRST_RESET_TYPE_SHUTDOWN:
|
||||
if (reason == SBI_SRST_RESET_REASON_NONE)
|
||||
writew(FINISHER_PASS, sifive_test_base);
|
||||
else
|
||||
writew(FINISHER_FAIL, sifive_test_base);
|
||||
break;
|
||||
case SBI_PLATFORM_RESET_COLD:
|
||||
case SBI_PLATFORM_RESET_WARM:
|
||||
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
|
||||
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
|
||||
writew(FINISHER_RESET, sifive_test_base);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sifive_test_init(unsigned long base)
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_const.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
#include <sbi_utils/fdt/fdt_fixup.h>
|
||||
#include <sbi_utils/irqchip/plic.h>
|
||||
#include <sbi_utils/serial/uart8250.h>
|
||||
@@ -114,17 +115,9 @@ static int ae350_timer_init(bool cold_boot)
|
||||
return plmt_warm_timer_init();
|
||||
}
|
||||
|
||||
/* Reset the platform. */
|
||||
static int ae350_system_reset(u32 type)
|
||||
{
|
||||
/* For now nothing to do. */
|
||||
sbi_printf("System reset\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Vendor-Specific SBI handler */
|
||||
static int ae350_vendor_ext_provider(long extid, long funcid,
|
||||
unsigned long *args, unsigned long *out_value,
|
||||
const struct sbi_trap_regs *regs, unsigned long *out_value,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -136,28 +129,28 @@ static int ae350_vendor_ext_provider(long extid, long funcid,
|
||||
*out_value = csr_read(CSR_MMISCCTL);
|
||||
break;
|
||||
case SBI_EXT_ANDES_SET_MCACHE_CTL:
|
||||
ret = mcall_set_mcache_ctl(args[0]);
|
||||
ret = mcall_set_mcache_ctl(regs->a0);
|
||||
break;
|
||||
case SBI_EXT_ANDES_SET_MMISC_CTL:
|
||||
ret = mcall_set_mmisc_ctl(args[0]);
|
||||
ret = mcall_set_mmisc_ctl(regs->a0);
|
||||
break;
|
||||
case SBI_EXT_ANDES_ICACHE_OP:
|
||||
ret = mcall_icache_op(args[0]);
|
||||
ret = mcall_icache_op(regs->a0);
|
||||
break;
|
||||
case SBI_EXT_ANDES_DCACHE_OP:
|
||||
ret = mcall_dcache_op(args[0]);
|
||||
ret = mcall_dcache_op(regs->a0);
|
||||
break;
|
||||
case SBI_EXT_ANDES_L1CACHE_I_PREFETCH:
|
||||
ret = mcall_l1_cache_i_prefetch_op(args[0]);
|
||||
ret = mcall_l1_cache_i_prefetch_op(regs->a0);
|
||||
break;
|
||||
case SBI_EXT_ANDES_L1CACHE_D_PREFETCH:
|
||||
ret = mcall_l1_cache_d_prefetch_op(args[0]);
|
||||
ret = mcall_l1_cache_d_prefetch_op(regs->a0);
|
||||
break;
|
||||
case SBI_EXT_ANDES_NON_BLOCKING_LOAD_STORE:
|
||||
ret = mcall_non_blocking_load_store(args[0]);
|
||||
ret = mcall_non_blocking_load_store(regs->a0);
|
||||
break;
|
||||
case SBI_EXT_ANDES_WRITE_AROUND:
|
||||
ret = mcall_write_around(args[0]);
|
||||
ret = mcall_write_around(regs->a0);
|
||||
break;
|
||||
default:
|
||||
sbi_printf("Unsupported vendor sbi call : %ld\n", funcid);
|
||||
@@ -185,8 +178,6 @@ const struct sbi_platform_operations platform_ops = {
|
||||
.timer_event_start = plmt_timer_event_start,
|
||||
.timer_event_stop = plmt_timer_event_stop,
|
||||
|
||||
.system_reset = ae350_system_reset,
|
||||
|
||||
.vendor_ext_provider = ae350_vendor_ext_provider
|
||||
};
|
||||
|
||||
|
@@ -147,16 +147,6 @@ static int ariane_timer_init(bool cold_boot)
|
||||
return clint_warm_timer_init();
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the ariane.
|
||||
*/
|
||||
static int ariane_system_reset(u32 type)
|
||||
{
|
||||
/* For now nothing to do. */
|
||||
sbi_printf("System reset\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Platform descriptor.
|
||||
*/
|
||||
@@ -174,7 +164,6 @@ const struct sbi_platform_operations platform_ops = {
|
||||
.timer_value = clint_timer_value,
|
||||
.timer_event_start = clint_timer_event_start,
|
||||
.timer_event_stop = clint_timer_event_stop,
|
||||
.system_reset = ariane_system_reset
|
||||
};
|
||||
|
||||
const struct sbi_platform platform = {
|
||||
|
@@ -173,16 +173,6 @@ static int openpiton_timer_init(bool cold_boot)
|
||||
return clint_warm_timer_init();
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the openpiton.
|
||||
*/
|
||||
static int openpiton_system_reset(u32 type)
|
||||
{
|
||||
/* For now nothing to do. */
|
||||
sbi_printf("System reset\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Platform descriptor.
|
||||
*/
|
||||
@@ -200,7 +190,6 @@ const struct sbi_platform_operations platform_ops = {
|
||||
.timer_value = clint_timer_value,
|
||||
.timer_event_start = clint_timer_event_start,
|
||||
.timer_event_stop = clint_timer_event_stop,
|
||||
.system_reset = openpiton_system_reset
|
||||
};
|
||||
|
||||
const struct sbi_platform platform = {
|
||||
|
@@ -15,7 +15,7 @@ platform-ldflags-y =
|
||||
|
||||
# Command for platform specific "make run"
|
||||
platform-runcmd = qemu-system-riscv$(PLATFORM_RISCV_XLEN) -M virt -m 256M \
|
||||
-nographic -kernel $(build_dir)/platform/generic/firmware/fw_payload.elf
|
||||
-nographic -bios $(build_dir)/platform/generic/firmware/fw_payload.elf
|
||||
|
||||
# Blobs to build
|
||||
FW_TEXT_START=0x80000000
|
||||
|
@@ -20,7 +20,10 @@ struct platform_override {
|
||||
int (*final_init)(bool cold_boot, const struct fdt_match *match);
|
||||
void (*early_exit)(const struct fdt_match *match);
|
||||
void (*final_exit)(const struct fdt_match *match);
|
||||
int (*system_reset)(u32 reset_type, const struct fdt_match *match);
|
||||
int (*system_reset_check)(u32 reset_type, u32 reset_reason,
|
||||
const struct fdt_match *match);
|
||||
void (*system_reset)(u32 reset_type, u32 reset_reason,
|
||||
const struct fdt_match *match);
|
||||
int (*fdt_fixup)(void *fdt, const struct fdt_match *match);
|
||||
};
|
||||
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include <sbi/sbi_hartmask.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_string.h>
|
||||
#include <sbi_utils/fdt/fdt_domain.h>
|
||||
#include <sbi_utils/fdt/fdt_fixup.h>
|
||||
#include <sbi_utils/fdt/fdt_helper.h>
|
||||
#include <sbi_utils/irqchip/fdt_irqchip.h>
|
||||
@@ -71,7 +72,7 @@ unsigned long fw_platform_init(unsigned long arg0, unsigned long arg1,
|
||||
unsigned long arg2, unsigned long arg3,
|
||||
unsigned long arg4)
|
||||
{
|
||||
const char *model, *mmu_type;
|
||||
const char *model;
|
||||
void *fdt = (void *)arg1;
|
||||
u32 hartid, hart_count = 0;
|
||||
int rc, root_offset, cpus_offset, cpu_offset, len;
|
||||
@@ -101,10 +102,6 @@ unsigned long fw_platform_init(unsigned long arg0, unsigned long arg1,
|
||||
if (SBI_HARTMASK_MAX_BITS <= hartid)
|
||||
continue;
|
||||
|
||||
mmu_type = fdt_getprop(fdt, cpu_offset, "mmu-type", &len);
|
||||
if (!mmu_type || !len)
|
||||
hartid = -1U;
|
||||
|
||||
generic_hart_index2id[hart_count++] = hartid;
|
||||
}
|
||||
|
||||
@@ -152,6 +149,7 @@ static int generic_final_init(bool cold_boot)
|
||||
|
||||
fdt_cpu_fixup(fdt);
|
||||
fdt_fixups(fdt);
|
||||
fdt_domain_fixup(fdt);
|
||||
|
||||
if (generic_plat && generic_plat->fdt_fixup) {
|
||||
rc = generic_plat->fdt_fixup(fdt, generic_plat_match);
|
||||
@@ -174,6 +172,11 @@ static void generic_final_exit(void)
|
||||
generic_plat->final_exit(generic_plat_match);
|
||||
}
|
||||
|
||||
static int generic_domains_init(void)
|
||||
{
|
||||
return fdt_domains_populate(sbi_scratch_thishart_arg1_ptr());
|
||||
}
|
||||
|
||||
static u64 generic_tlbr_flush_limit(void)
|
||||
{
|
||||
if (generic_plat && generic_plat->tlbr_flush_limit)
|
||||
@@ -181,12 +184,24 @@ static u64 generic_tlbr_flush_limit(void)
|
||||
return SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT;
|
||||
}
|
||||
|
||||
static int generic_system_reset(u32 reset_type)
|
||||
static int generic_system_reset_check(u32 reset_type, u32 reset_reason)
|
||||
{
|
||||
if (generic_plat && generic_plat->system_reset)
|
||||
return generic_plat->system_reset(reset_type,
|
||||
generic_plat_match);
|
||||
return fdt_system_reset(reset_type);
|
||||
if (generic_plat && generic_plat->system_reset_check)
|
||||
return generic_plat->system_reset_check(reset_type,
|
||||
reset_reason,
|
||||
generic_plat_match);
|
||||
return fdt_system_reset_check(reset_type, reset_reason);
|
||||
}
|
||||
|
||||
static void generic_system_reset(u32 reset_type, u32 reset_reason)
|
||||
{
|
||||
if (generic_plat && generic_plat->system_reset) {
|
||||
generic_plat->system_reset(reset_type, reset_reason,
|
||||
generic_plat_match);
|
||||
return;
|
||||
}
|
||||
|
||||
fdt_system_reset(reset_type, reset_reason);
|
||||
}
|
||||
|
||||
const struct sbi_platform_operations platform_ops = {
|
||||
@@ -194,6 +209,7 @@ const struct sbi_platform_operations platform_ops = {
|
||||
.final_init = generic_final_init,
|
||||
.early_exit = generic_early_exit,
|
||||
.final_exit = generic_final_exit,
|
||||
.domains_init = generic_domains_init,
|
||||
.console_putc = fdt_serial_putc,
|
||||
.console_getc = fdt_serial_getc,
|
||||
.console_init = fdt_serial_init,
|
||||
@@ -209,6 +225,7 @@ const struct sbi_platform_operations platform_ops = {
|
||||
.timer_event_start = fdt_timer_event_start,
|
||||
.timer_init = fdt_timer_init,
|
||||
.timer_exit = fdt_timer_exit,
|
||||
.system_reset_check = generic_system_reset_check,
|
||||
.system_reset = generic_system_reset,
|
||||
};
|
||||
|
||||
|
@@ -11,3 +11,4 @@ platform-objs-y += platform.o
|
||||
|
||||
platform-objs-y += k210.o
|
||||
platform-varprefix-k210.o = dt_k210
|
||||
platform-padding-k210.o = 2048
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_const.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi_utils/fdt/fdt_fixup.h>
|
||||
#include <sbi_utils/irqchip/plic.h>
|
||||
#include <sbi_utils/serial/sifive-uart.h>
|
||||
#include <sbi_utils/sys/clint.h>
|
||||
@@ -67,6 +68,21 @@ static u32 k210_get_clk_freq(void)
|
||||
return pll0_freq / div;
|
||||
}
|
||||
|
||||
static int k210_final_init(bool cold_boot)
|
||||
{
|
||||
void *fdt;
|
||||
|
||||
if (!cold_boot)
|
||||
return 0;
|
||||
|
||||
fdt = sbi_scratch_thishart_arg1_ptr();
|
||||
|
||||
fdt_cpu_fixup(fdt);
|
||||
fdt_fixups(fdt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int k210_console_init(void)
|
||||
{
|
||||
return sifive_uart_init(K210_UART_BASE_ADDR, k210_get_clk_freq(),
|
||||
@@ -113,15 +129,9 @@ static int k210_timer_init(bool cold_boot)
|
||||
return clint_warm_timer_init();
|
||||
}
|
||||
|
||||
static int k210_system_reset(u32 type)
|
||||
{
|
||||
/* For now nothing to do. */
|
||||
sbi_printf("System reset\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct sbi_platform_operations platform_ops = {
|
||||
.final_init = k210_final_init,
|
||||
|
||||
.console_init = k210_console_init,
|
||||
.console_putc = sifive_uart_putc,
|
||||
.console_getc = sifive_uart_getc,
|
||||
@@ -136,8 +146,6 @@ const struct sbi_platform_operations platform_ops = {
|
||||
.timer_value = clint_timer_value,
|
||||
.timer_event_stop = clint_timer_event_stop,
|
||||
.timer_event_start = clint_timer_event_start,
|
||||
|
||||
.system_reset = k210_system_reset
|
||||
};
|
||||
|
||||
const struct sbi_platform platform = {
|
||||
|
@@ -186,13 +186,17 @@ static int ux600_timer_init(bool cold_boot)
|
||||
return clint_warm_timer_init();
|
||||
}
|
||||
|
||||
static int ux600_system_reset(u32 type)
|
||||
static int ux600_system_reset_check(u32 type, u32 reason)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void ux600_system_reset(u32 type, u32 reason)
|
||||
{
|
||||
/* Reset system using MSFTRST register in Nuclei Timer. */
|
||||
writel(UX600_NUCLEI_TIMER_MSFTRST_KEY, (void *)(UX600_NUCLEI_TIMER_ADDR
|
||||
+ UX600_NUCLEI_TIMER_MSFTRST_OFS));
|
||||
while(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct sbi_platform_operations platform_ops = {
|
||||
@@ -209,6 +213,7 @@ const struct sbi_platform_operations platform_ops = {
|
||||
.timer_event_stop = clint_timer_event_stop,
|
||||
.timer_event_start = clint_timer_event_start,
|
||||
.timer_init = ux600_timer_init,
|
||||
.system_reset_check = ux600_system_reset_check,
|
||||
.system_reset = ux600_system_reset
|
||||
};
|
||||
|
||||
|
@@ -15,7 +15,7 @@ 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
|
||||
-nographic -bios $(build_dir)/platform/sifive/fu540/firmware/fw_payload.elf
|
||||
|
||||
# Blobs to build
|
||||
FW_TEXT_START=0x80000000
|
||||
|
@@ -154,12 +154,6 @@ static u32 fu540_hart_index2id[FU540_HART_COUNT - 1] = {
|
||||
[3] = 4,
|
||||
};
|
||||
|
||||
static int fu540_system_reset(u32 type)
|
||||
{
|
||||
/* For now nothing to do. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct sbi_platform_operations platform_ops = {
|
||||
.final_init = fu540_final_init,
|
||||
.console_putc = sifive_uart_putc,
|
||||
@@ -174,7 +168,6 @@ const struct sbi_platform_operations platform_ops = {
|
||||
.timer_event_stop = clint_timer_event_stop,
|
||||
.timer_event_start = clint_timer_event_start,
|
||||
.timer_init = fu540_timer_init,
|
||||
.system_reset = fu540_system_reset
|
||||
};
|
||||
|
||||
const struct sbi_platform platform = {
|
||||
|
@@ -34,6 +34,9 @@ platform-ldflags-y =
|
||||
# Firmware load address configuration. This is mandatory.
|
||||
FW_TEXT_START=0x80000000
|
||||
|
||||
# Optional parameter for path to external FDT
|
||||
# FW_FDT_PATH="path to platform flattened device tree file"
|
||||
|
||||
#
|
||||
# Dynamic firmware configuration.
|
||||
# Optional parameters are commented out. Uncomment and define these parameters
|
||||
@@ -71,5 +74,4 @@ FW_PAYLOAD_OFFSET=0x200000
|
||||
endif
|
||||
# FW_PAYLOAD_ALIGN=0x1000
|
||||
# FW_PAYLOAD_PATH="path to next boot stage binary image file"
|
||||
# FW_PAYLOAD_FDT_PATH="path to platform flattened device tree file"
|
||||
# FW_PAYLOAD_FDT_ADDR=0x82200000
|
||||
|
@@ -107,7 +107,7 @@ static int platform_ipi_init(bool cold_boot)
|
||||
|
||||
/* Example if the generic CLINT driver is used */
|
||||
if (cold_boot) {
|
||||
ret = clint_cold_ipi_init(&clint, NULL);
|
||||
ret = clint_cold_ipi_init(&clint);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@@ -142,7 +142,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(&clint);
|
||||
ret = clint_cold_timer_init(&clint, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@@ -178,13 +178,20 @@ static void platform_timer_event_stop(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the platform.
|
||||
* Check reset type and reason supported by the platform.
|
||||
*/
|
||||
static int platform_system_reset(u32 type)
|
||||
static int platform_system_reset_check(u32 type, u32 reason)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the platform.
|
||||
*/
|
||||
static void platform_system_reset(u32 type, u32 reason)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Platform descriptor.
|
||||
*/
|
||||
@@ -202,6 +209,7 @@ 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_reset_check = platform_system_reset_check,
|
||||
.system_reset = platform_system_reset
|
||||
};
|
||||
const struct sbi_platform platform = {
|
||||
|
@@ -108,10 +108,14 @@ static int c910_timer_init(bool cold_boot)
|
||||
return clint_warm_timer_init();
|
||||
}
|
||||
|
||||
static int c910_system_reset(u32 type)
|
||||
static int c910_system_reset_check(u32 type, u32 reason)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void c910_system_reset(u32 type, u32 reason)
|
||||
{
|
||||
asm volatile ("ebreak");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int c910_hart_start(u32 hartid, ulong saddr)
|
||||
@@ -135,6 +139,7 @@ const struct sbi_platform_operations platform_ops = {
|
||||
.timer_init = c910_timer_init,
|
||||
.timer_event_start = clint_timer_event_start,
|
||||
|
||||
.system_reset_check = c910_system_reset_check,
|
||||
.system_reset = c910_system_reset,
|
||||
|
||||
.hart_start = c910_hart_start,
|
||||
|
@@ -9,6 +9,7 @@ function usage()
|
||||
echo " -i <input_file_path> Input binary file path"
|
||||
echo " -a <c_align> Output C array alignment"
|
||||
echo " -p <c_prefix> Output C array name prefix"
|
||||
echo " -t <num_zero_bytes> Output padding zero bytes"
|
||||
exit 1;
|
||||
}
|
||||
|
||||
@@ -16,8 +17,9 @@ function usage()
|
||||
INPUT_PATH=""
|
||||
OUTPUT_C_ALIGN=""
|
||||
OUTPUT_C_PREFIX=""
|
||||
NUM_ZERO_BYTES=0
|
||||
|
||||
while getopts "hi:a:p:o:" o; do
|
||||
while getopts "hi:a:p:t:" o; do
|
||||
case "${o}" in
|
||||
h)
|
||||
usage
|
||||
@@ -31,6 +33,9 @@ while getopts "hi:a:p:o:" o; do
|
||||
p)
|
||||
OUTPUT_C_PREFIX=${OPTARG}
|
||||
;;
|
||||
t)
|
||||
NUM_ZERO_BYTES=${OPTARG}
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
@@ -62,6 +67,8 @@ printf "const char __attribute__((aligned(%s))) %s_start[] = {\n" "${OUTPUT_C_AL
|
||||
|
||||
od -v -t x1 -An ${INPUT_PATH} | awk '{for (i=1; i<=NF; i++) printf " 0x%s,", $i; printf "\n"; }'
|
||||
|
||||
echo __dummy__ | awk "{for (i=1; i<=${NUM_ZERO_BYTES}; i++) { printf \" 0x00,\"; if (i % 16 == 0) printf \"\n\"; } }"
|
||||
|
||||
printf "};\n"
|
||||
|
||||
printf "const unsigned long %s_size = sizeof(%s_start);\n" "${OUTPUT_C_PREFIX}" "${OUTPUT_C_PREFIX}"
|
||||
|
Reference in New Issue
Block a user