aboutsummaryrefslogtreecommitdiffstats
path: root/roms/opensbi
diff options
context:
space:
mode:
Diffstat (limited to 'roms/opensbi')
-rw-r--r--roms/opensbi/.clang-format16
-rw-r--r--roms/opensbi/.gitignore11
-rw-r--r--roms/opensbi/CONTRIBUTORS.md27
-rw-r--r--roms/opensbi/COPYING.BSD25
-rw-r--r--roms/opensbi/Makefile493
-rw-r--r--roms/opensbi/README.md286
-rw-r--r--roms/opensbi/ThirdPartyNotices.md18
-rw-r--r--roms/opensbi/docs/contributing.md84
-rw-r--r--roms/opensbi/docs/domain_support.md314
-rw-r--r--roms/opensbi/docs/doxygen.cfg2462
-rw-r--r--roms/opensbi/docs/external/coreboot.md32
-rw-r--r--roms/opensbi/docs/firmware/fw.md111
-rw-r--r--roms/opensbi/docs/firmware/fw_dynamic.md35
-rw-r--r--roms/opensbi/docs/firmware/fw_jump.md51
-rw-r--r--roms/opensbi/docs/firmware/fw_payload.md72
-rw-r--r--roms/opensbi/docs/firmware/payload_linux.md9
-rw-r--r--roms/opensbi/docs/firmware/payload_uboot.md15
-rw-r--r--roms/opensbi/docs/library_usage.md89
-rw-r--r--roms/opensbi/docs/platform/andes-ae350.md30
-rw-r--r--roms/opensbi/docs/platform/fpga-ariane.md38
-rw-r--r--roms/opensbi/docs/platform/fpga-openpiton.md33
-rw-r--r--roms/opensbi/docs/platform/generic.md54
-rw-r--r--roms/opensbi/docs/platform/nuclei_ux600.md22
-rw-r--r--roms/opensbi/docs/platform/platform.md59
-rw-r--r--roms/opensbi/docs/platform/qemu_virt.md149
-rw-r--r--roms/opensbi/docs/platform/shakti_cclass.md33
-rw-r--r--roms/opensbi/docs/platform/sifive_fu540.md195
-rw-r--r--roms/opensbi/docs/platform/spike.md89
-rw-r--r--roms/opensbi/docs/platform/thead-c910.md34
-rw-r--r--roms/opensbi/docs/platform_guide.md42
-rw-r--r--roms/opensbi/docs/platform_requirements.md44
-rw-r--r--roms/opensbi/firmware/external_deps.mk14
-rw-r--r--roms/opensbi/firmware/fw_base.S769
-rw-r--r--roms/opensbi/firmware/fw_base.ldS81
-rw-r--r--roms/opensbi/firmware/fw_dynamic.S151
-rw-r--r--roms/opensbi/firmware/fw_dynamic.elf.ldS18
-rw-r--r--roms/opensbi/firmware/fw_jump.S96
-rw-r--r--roms/opensbi/firmware/fw_jump.elf.ldS18
-rw-r--r--roms/opensbi/firmware/fw_payload.S97
-rw-r--r--roms/opensbi/firmware/fw_payload.elf.ldS32
-rw-r--r--roms/opensbi/firmware/objects.mk57
-rw-r--r--roms/opensbi/firmware/payloads/objects.mk19
-rw-r--r--roms/opensbi/firmware/payloads/test.elf.ldS87
-rw-r--r--roms/opensbi/firmware/payloads/test_head.S88
-rw-r--r--roms/opensbi/firmware/payloads/test_main.c48
-rw-r--r--roms/opensbi/include/sbi/fw_dynamic.h79
-rw-r--r--roms/opensbi/include/sbi/riscv_asm.h187
-rw-r--r--roms/opensbi/include/sbi/riscv_atomic.h70
-rw-r--r--roms/opensbi/include/sbi/riscv_barrier.h57
-rw-r--r--roms/opensbi/include/sbi/riscv_encoding.h699
-rw-r--r--roms/opensbi/include/sbi/riscv_fp.h94
-rw-r--r--roms/opensbi/include/sbi/riscv_io.h114
-rw-r--r--roms/opensbi/include/sbi/riscv_locks.h34
-rw-r--r--roms/opensbi/include/sbi/sbi_bitmap.h128
-rw-r--r--roms/opensbi/include/sbi/sbi_bitops.h320
-rw-r--r--roms/opensbi/include/sbi/sbi_console.h39
-rw-r--r--roms/opensbi/include/sbi/sbi_const.h48
-rw-r--r--roms/opensbi/include/sbi/sbi_csr_detect.h50
-rw-r--r--roms/opensbi/include/sbi/sbi_domain.h165
-rw-r--r--roms/opensbi/include/sbi/sbi_ecall.h61
-rw-r--r--roms/opensbi/include/sbi/sbi_ecall_interface.h98
-rw-r--r--roms/opensbi/include/sbi/sbi_emulate_csr.h23
-rw-r--r--roms/opensbi/include/sbi/sbi_error.h38
-rw-r--r--roms/opensbi/include/sbi/sbi_fifo.h42
-rw-r--r--roms/opensbi/include/sbi/sbi_hart.h56
-rw-r--r--roms/opensbi/include/sbi/sbi_hartmask.h141
-rw-r--r--roms/opensbi/include/sbi/sbi_hfence.h38
-rw-r--r--roms/opensbi/include/sbi/sbi_hsm.h38
-rw-r--r--roms/opensbi/include/sbi/sbi_illegal_insn.h19
-rw-r--r--roms/opensbi/include/sbi/sbi_init.h23
-rw-r--r--roms/opensbi/include/sbi/sbi_ipi.h70
-rw-r--r--roms/opensbi/include/sbi/sbi_list.h152
-rw-r--r--roms/opensbi/include/sbi/sbi_math.h15
-rw-r--r--roms/opensbi/include/sbi/sbi_misaligned_ldst.h23
-rw-r--r--roms/opensbi/include/sbi/sbi_platform.h757
-rw-r--r--roms/opensbi/include/sbi/sbi_scratch.h128
-rw-r--r--roms/opensbi/include/sbi/sbi_string.h46
-rw-r--r--roms/opensbi/include/sbi/sbi_system.h19
-rw-r--r--roms/opensbi/include/sbi/sbi_timer.h44
-rw-r--r--roms/opensbi/include/sbi/sbi_tlb.h60
-rw-r--r--roms/opensbi/include/sbi/sbi_trap.h214
-rw-r--r--roms/opensbi/include/sbi/sbi_types.h109
-rw-r--r--roms/opensbi/include/sbi/sbi_unpriv.h41
-rw-r--r--roms/opensbi/include/sbi/sbi_version.h24
-rw-r--r--roms/opensbi/include/sbi_utils/fdt/fdt_domain.h73
-rw-r--r--roms/opensbi/include/sbi_utils/fdt/fdt_fixup.h78
-rw-r--r--roms/opensbi/include/sbi_utils/fdt/fdt_helper.h68
-rw-r--r--roms/opensbi/include/sbi_utils/ipi/fdt_ipi.h32
-rw-r--r--roms/opensbi/include/sbi_utils/irqchip/fdt_irqchip.h26
-rw-r--r--roms/opensbi/include/sbi_utils/irqchip/plic.h29
-rw-r--r--roms/opensbi/include/sbi_utils/reset/fdt_reset.h28
-rw-r--r--roms/opensbi/include/sbi_utils/serial/fdt_serial.h28
-rw-r--r--roms/opensbi/include/sbi_utils/serial/shakti-uart.h18
-rw-r--r--roms/opensbi/include/sbi_utils/serial/sifive-uart.h21
-rw-r--r--roms/opensbi/include/sbi_utils/serial/uart8250.h22
-rw-r--r--roms/opensbi/include/sbi_utils/sys/clint.h51
-rw-r--r--roms/opensbi/include/sbi_utils/sys/htif.h21
-rw-r--r--roms/opensbi/include/sbi_utils/sys/sifive_test.h21
-rw-r--r--roms/opensbi/include/sbi_utils/timer/fdt_timer.h35
-rw-r--r--roms/opensbi/lib/sbi/objects.mk43
-rw-r--r--roms/opensbi/lib/sbi/riscv_asm.c295
-rw-r--r--roms/opensbi/lib/sbi/riscv_atomic.c255
-rw-r--r--roms/opensbi/lib/sbi/riscv_hardfp.S171
-rw-r--r--roms/opensbi/lib/sbi/riscv_locks.c45
-rw-r--r--roms/opensbi/lib/sbi/sbi_bitmap.c40
-rw-r--r--roms/opensbi/lib/sbi/sbi_bitops.c200
-rw-r--r--roms/opensbi/lib/sbi/sbi_console.c398
-rw-r--r--roms/opensbi/lib/sbi/sbi_domain.c539
-rw-r--r--roms/opensbi/lib/sbi/sbi_ecall.c175
-rw-r--r--roms/opensbi/lib/sbi/sbi_ecall_base.c79
-rw-r--r--roms/opensbi/lib/sbi/sbi_ecall_hsm.c59
-rw-r--r--roms/opensbi/lib/sbi/sbi_ecall_legacy.c124
-rw-r--r--roms/opensbi/lib/sbi/sbi_ecall_replace.c196
-rw-r--r--roms/opensbi/lib/sbi/sbi_ecall_vendor.c40
-rw-r--r--roms/opensbi/lib/sbi/sbi_emulate_csr.c188
-rw-r--r--roms/opensbi/lib/sbi/sbi_expected_trap.S56
-rw-r--r--roms/opensbi/lib/sbi/sbi_fifo.c192
-rw-r--r--roms/opensbi/lib/sbi/sbi_hart.c536
-rw-r--r--roms/opensbi/lib/sbi/sbi_hfence.S135
-rw-r--r--roms/opensbi/lib/sbi/sbi_hsm.c291
-rw-r--r--roms/opensbi/lib/sbi/sbi_illegal_insn.c143
-rw-r--r--roms/opensbi/lib/sbi/sbi_init.c475
-rw-r--r--roms/opensbi/lib/sbi/sbi_ipi.c254
-rw-r--r--roms/opensbi/lib/sbi/sbi_math.c23
-rw-r--r--roms/opensbi/lib/sbi/sbi_misaligned_ldst.c243
-rw-r--r--roms/opensbi/lib/sbi/sbi_platform.c90
-rw-r--r--roms/opensbi/lib/sbi/sbi_scratch.c99
-rw-r--r--roms/opensbi/lib/sbi/sbi_string.c188
-rw-r--r--roms/opensbi/lib/sbi/sbi_system.c56
-rw-r--r--roms/opensbi/lib/sbi/sbi_timer.c136
-rw-r--r--roms/opensbi/lib/sbi/sbi_tlb.c429
-rw-r--r--roms/opensbi/lib/sbi/sbi_trap.c293
-rw-r--r--roms/opensbi/lib/sbi/sbi_unpriv.c165
-rw-r--r--roms/opensbi/lib/utils/fdt/fdt_domain.c455
-rw-r--r--roms/opensbi/lib/utils/fdt/fdt_fixup.c265
-rw-r--r--roms/opensbi/lib/utils/fdt/fdt_helper.c465
-rw-r--r--roms/opensbi/lib/utils/fdt/objects.mk9
-rw-r--r--roms/opensbi/lib/utils/ipi/fdt_ipi.c101
-rw-r--r--roms/opensbi/lib/utils/ipi/fdt_ipi_clint.c49
-rw-r--r--roms/opensbi/lib/utils/ipi/objects.mk11
-rw-r--r--roms/opensbi/lib/utils/irqchip/fdt_irqchip.c74
-rw-r--r--roms/opensbi/lib/utils/irqchip/fdt_irqchip_plic.c120
-rw-r--r--roms/opensbi/lib/utils/irqchip/objects.mk12
-rw-r--r--roms/opensbi/lib/utils/irqchip/plic.c100
-rw-r--r--roms/opensbi/lib/utils/libfdt/.clang-format1
-rw-r--r--roms/opensbi/lib/utils/libfdt/Makefile.libfdt18
-rw-r--r--roms/opensbi/lib/utils/libfdt/TODO3
-rw-r--r--roms/opensbi/lib/utils/libfdt/fdt.c316
-rw-r--r--roms/opensbi/lib/utils/libfdt/fdt.h66
-rw-r--r--roms/opensbi/lib/utils/libfdt/fdt_addresses.c101
-rw-r--r--roms/opensbi/lib/utils/libfdt/fdt_check.c74
-rw-r--r--roms/opensbi/lib/utils/libfdt/fdt_empty_tree.c38
-rw-r--r--roms/opensbi/lib/utils/libfdt/fdt_overlay.c881
-rw-r--r--roms/opensbi/lib/utils/libfdt/fdt_ro.c857
-rw-r--r--roms/opensbi/lib/utils/libfdt/fdt_rw.c491
-rw-r--r--roms/opensbi/lib/utils/libfdt/fdt_strerror.c59
-rw-r--r--roms/opensbi/lib/utils/libfdt/fdt_sw.c381
-rw-r--r--roms/opensbi/lib/utils/libfdt/fdt_wip.c94
-rw-r--r--roms/opensbi/lib/utils/libfdt/libfdt.h2072
-rw-r--r--roms/opensbi/lib/utils/libfdt/libfdt_env.h110
-rw-r--r--roms/opensbi/lib/utils/libfdt/libfdt_internal.h173
-rw-r--r--roms/opensbi/lib/utils/libfdt/objects.mk16
-rw-r--r--roms/opensbi/lib/utils/libfdt/version.lds82
-rw-r--r--roms/opensbi/lib/utils/reset/fdt_reset.c62
-rw-r--r--roms/opensbi/lib/utils/reset/fdt_reset_htif.c23
-rw-r--r--roms/opensbi/lib/utils/reset/fdt_reset_sifive.c38
-rw-r--r--roms/opensbi/lib/utils/reset/objects.mk12
-rw-r--r--roms/opensbi/lib/utils/serial/fdt_serial.c111
-rw-r--r--roms/opensbi/lib/utils/serial/fdt_serial_htif.c24
-rw-r--r--roms/opensbi/lib/utils/serial/fdt_serial_shakti.c35
-rw-r--r--roms/opensbi/lib/utils/serial/fdt_serial_sifive.c38
-rw-r--r--roms/opensbi/lib/utils/serial/fdt_serial_uart8250.c39
-rw-r--r--roms/opensbi/lib/utils/serial/objects.mk17
-rw-r--r--roms/opensbi/lib/utils/serial/shakti-uart.c48
-rw-r--r--roms/opensbi/lib/utils/serial/sifive-uart.c102
-rw-r--r--roms/opensbi/lib/utils/serial/uart8250.c125
-rw-r--r--roms/opensbi/lib/utils/sys/clint.c203
-rw-r--r--roms/opensbi/lib/utils/sys/htif.c154
-rw-r--r--roms/opensbi/lib/utils/sys/objects.mk12
-rw-r--r--roms/opensbi/lib/utils/sys/sifive_test.c57
-rw-r--r--roms/opensbi/lib/utils/timer/fdt_timer.c112
-rw-r--r--roms/opensbi/lib/utils/timer/fdt_timer_clint.c52
-rw-r--r--roms/opensbi/lib/utils/timer/objects.mk11
-rw-r--r--roms/opensbi/platform/andes/ae350/cache.c89
-rw-r--r--roms/opensbi/platform/andes/ae350/cache.h17
-rw-r--r--roms/opensbi/platform/andes/ae350/config.mk36
-rw-r--r--roms/opensbi/platform/andes/ae350/objects.mk11
-rw-r--r--roms/opensbi/platform/andes/ae350/platform.c192
-rw-r--r--roms/opensbi/platform/andes/ae350/platform.h125
-rw-r--r--roms/opensbi/platform/andes/ae350/plicsw.c145
-rw-r--r--roms/opensbi/platform/andes/ae350/plicsw.h46
-rw-r--r--roms/opensbi/platform/andes/ae350/plmt.c97
-rw-r--r--roms/opensbi/platform/andes/ae350/plmt.h23
-rw-r--r--roms/opensbi/platform/fpga/ariane/config.mk36
-rw-r--r--roms/opensbi/platform/fpga/ariane/objects.mk8
-rw-r--r--roms/opensbi/platform/fpga/ariane/platform.c177
-rw-r--r--roms/opensbi/platform/fpga/openpiton/config.mk35
-rw-r--r--roms/opensbi/platform/fpga/openpiton/objects.mk7
-rw-r--r--roms/opensbi/platform/fpga/openpiton/platform.c203
-rw-r--r--roms/opensbi/platform/generic/config.mk40
-rw-r--r--roms/opensbi/platform/generic/include/platform_override.h30
-rw-r--r--roms/opensbi/platform/generic/objects.mk11
-rw-r--r--roms/opensbi/platform/generic/platform.c241
-rw-r--r--roms/opensbi/platform/generic/sifive_fu540.c47
-rw-r--r--roms/opensbi/platform/kendryte/k210/config.mk19
-rw-r--r--roms/opensbi/platform/kendryte/k210/k210.dts70
-rw-r--r--roms/opensbi/platform/kendryte/k210/objects.mk14
-rw-r--r--roms/opensbi/platform/kendryte/k210/platform.c159
-rw-r--r--roms/opensbi/platform/kendryte/k210/platform.h36
-rw-r--r--roms/opensbi/platform/nuclei/ux600/config.mk30
-rw-r--r--roms/opensbi/platform/nuclei/ux600/objects.mk11
-rw-r--r--roms/opensbi/platform/nuclei/ux600/platform.c228
-rw-r--r--roms/opensbi/platform/sifive/fu540/config.mk40
-rw-r--r--roms/opensbi/platform/sifive/fu540/objects.mk10
-rw-r--r--roms/opensbi/platform/sifive/fu540/platform.c182
-rw-r--r--roms/opensbi/platform/template/config.mk77
-rw-r--r--roms/opensbi/platform/template/objects.mk15
-rw-r--r--roms/opensbi/platform/template/platform.c223
-rw-r--r--roms/opensbi/platform/thead/c910/config.mk14
-rw-r--r--roms/opensbi/platform/thead/c910/objects.mk5
-rw-r--r--roms/opensbi/platform/thead/c910/platform.c156
-rw-r--r--roms/opensbi/platform/thead/c910/platform.h46
-rwxr-xr-xroms/opensbi/scripts/create-binary-archive.sh168
-rwxr-xr-xroms/opensbi/scripts/d2c.sh74
224 files changed, 30074 insertions, 0 deletions
diff --git a/roms/opensbi/.clang-format b/roms/opensbi/.clang-format
new file mode 100644
index 000000000..c80c0aa98
--- /dev/null
+++ b/roms/opensbi/.clang-format
@@ -0,0 +1,16 @@
+AlignConsecutiveAssignments: true
+AlignEscapedNewlines: Left
+AlignTrailingComments: true
+AllowShortFunctionsOnASingleLine: None
+BraceWrapping:
+ AfterFunction: true
+BreakBeforeBraces: Custom
+BreakStringLiterals: false
+ContinuationIndentWidth: 8
+Cpp11BracedListStyle: false
+IndentWidth: 8
+ReflowComments: false
+SortIncludes: false
+SpacesInContainerLiterals: false
+TabWidth: 8
+UseTab: Always
diff --git a/roms/opensbi/.gitignore b/roms/opensbi/.gitignore
new file mode 100644
index 000000000..534ad6477
--- /dev/null
+++ b/roms/opensbi/.gitignore
@@ -0,0 +1,11 @@
+# Object files
+*.o
+*.a
+*.dep
+
+#Build & install directories
+build/
+install/
+
+# Development friendly files
+tags
diff --git a/roms/opensbi/CONTRIBUTORS.md b/roms/opensbi/CONTRIBUTORS.md
new file mode 100644
index 000000000..afae1251d
--- /dev/null
+++ b/roms/opensbi/CONTRIBUTORS.md
@@ -0,0 +1,27 @@
+
+List of OpenSBI Contributors (Alphabetically sorted)
+====================================================
+
+* **[Western Digital Corporation](https://www.wdc.com/)**
+ * Project initiator and maintainer
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates
+
+* Alistair Francis <alistair@alistair23.me>
+
+* Andreas Schwab <schwab@suse.de>
+
+* Anup Patel <anup.patel@wdc.com>
+
+* Atish Patra <atish.patra@wdc.com>
+
+* Bin Meng <bmeng.cn@gmail.com>
+
+* Damien Le Moal <damien.lemoal@wdc.com>
+
+* Karsten Merker <merker@debian.org>
+
+* Nick Kossifidis <mickflemm@gmail.com>
+
+* Shawn Chang <citypw@gmail.com>
+
+* Xiang Wang <wxjstz@126.com>
diff --git a/roms/opensbi/COPYING.BSD b/roms/opensbi/COPYING.BSD
new file mode 100644
index 000000000..26972c8a4
--- /dev/null
+++ b/roms/opensbi/COPYING.BSD
@@ -0,0 +1,25 @@
+The 2-Clause BSD License
+SPDX short identifier: BSD-2-Clause
+
+Copyright (c) 2019 Western Digital Corporation or its affiliates and other
+contributors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/roms/opensbi/Makefile b/roms/opensbi/Makefile
new file mode 100644
index 000000000..d6f097d30
--- /dev/null
+++ b/roms/opensbi/Makefile
@@ -0,0 +1,493 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2019 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+
+# Select Make Options:
+# o Do not use make's built-in rules
+# o Do not print "Entering directory ...";
+MAKEFLAGS += -r --no-print-directory
+
+# Readlink -f requires GNU readlink
+ifeq ($(shell uname -s),Darwin)
+READLINK ?= greadlink
+else
+READLINK ?= readlink
+endif
+
+# Find out source, build, and install directories
+src_dir=$(CURDIR)
+ifdef O
+ build_dir=$(shell $(READLINK) -f $(O))
+else
+ build_dir=$(CURDIR)/build
+endif
+ifeq ($(build_dir),$(CURDIR))
+$(error Build directory is same as source directory.)
+endif
+install_root_dir_default=$(CURDIR)/install
+ifdef I
+ install_root_dir=$(shell $(READLINK) -f $(I))
+else
+ install_root_dir=$(install_root_dir_default)/usr
+endif
+ifeq ($(install_root_dir),$(CURDIR))
+$(error Install root directory is same as source directory.)
+endif
+ifeq ($(install_root_dir),$(build_dir))
+$(error Install root directory is same as build directory.)
+endif
+ifdef PLATFORM_DIR
+ platform_dir_path=$(shell $(READLINK) -f $(PLATFORM_DIR))
+ ifdef PLATFORM
+ platform_parent_dir=$(platform_dir_path)
+ else
+ PLATFORM=$(shell basename $(platform_dir_path))
+ platform_parent_dir=$(subst $(PLATFORM),,$(platform_dir_path))
+ endif
+else
+ platform_parent_dir=$(src_dir)/platform
+endif
+
+# Check if verbosity is ON for build process
+CMD_PREFIX_DEFAULT := @
+ifeq ($(V), 1)
+ CMD_PREFIX :=
+else
+ CMD_PREFIX := $(CMD_PREFIX_DEFAULT)
+endif
+
+# Setup path of directories
+export platform_subdir=$(PLATFORM)
+export platform_src_dir=$(platform_parent_dir)/$(platform_subdir)
+export platform_build_dir=$(build_dir)/platform/$(platform_subdir)
+export include_dir=$(CURDIR)/include
+export libsbi_dir=$(CURDIR)/lib/sbi
+export libsbiutils_dir=$(CURDIR)/lib/utils
+export firmware_dir=$(CURDIR)/firmware
+
+# Find library version
+OPENSBI_VERSION_MAJOR=`grep "define OPENSBI_VERSION_MAJOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MAJOR.*\([0-9][0-9]*\)/\1/'`
+OPENSBI_VERSION_MINOR=`grep "define OPENSBI_VERSION_MINOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MINOR.*\([0-9][0-9]*\)/\1/'`
+OPENSBI_VERSION_GIT=$(shell if [ -d $(src_dir)/.git ]; then git describe 2> /dev/null; fi)
+
+# Setup compilation commands
+ifdef CROSS_COMPILE
+CC = $(CROSS_COMPILE)gcc
+CPP = $(CROSS_COMPILE)cpp
+AR = $(CROSS_COMPILE)ar
+LD = $(CROSS_COMPILE)ld
+OBJCOPY = $(CROSS_COMPILE)objcopy
+else
+CC ?= gcc
+CPP ?= cpp
+AR ?= ar
+LD ?= ld
+OBJCOPY ?= objcopy
+endif
+AS = $(CC)
+DTC = dtc
+
+# Guess the compillers xlen
+OPENSBI_CC_XLEN := $(shell TMP=`$(CC) -dumpmachine | sed 's/riscv\([0-9][0-9]\).*/\1/'`; echo $${TMP})
+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
+ ifeq ($(OPENSBI_CC_XLEN), 32)
+ PLATFORM_RISCV_XLEN = 32
+ else
+ PLATFORM_RISCV_XLEN = 64
+ endif
+endif
+
+# Setup list of objects.mk files
+ifdef PLATFORM
+platform-object-mks=$(shell if [ -d $(platform_src_dir)/ ]; then find $(platform_src_dir) -iname "objects.mk" | sort -r; fi)
+endif
+libsbi-object-mks=$(shell if [ -d $(libsbi_dir) ]; then find $(libsbi_dir) -iname "objects.mk" | sort -r; fi)
+libsbiutils-object-mks=$(shell if [ -d $(libsbiutils_dir) ]; then find $(libsbiutils_dir) -iname "objects.mk" | sort -r; fi)
+firmware-object-mks=$(shell if [ -d $(firmware_dir) ]; then find $(firmware_dir) -iname "objects.mk" | sort -r; fi)
+
+# Include platform specifig config.mk
+ifdef PLATFORM
+include $(platform_src_dir)/config.mk
+endif
+
+# Include all object.mk files
+ifdef PLATFORM
+include $(platform-object-mks)
+endif
+include $(libsbi-object-mks)
+include $(libsbiutils-object-mks)
+include $(firmware-object-mks)
+
+# Setup list of objects
+libsbi-objs-path-y=$(foreach obj,$(libsbi-objs-y),$(build_dir)/lib/sbi/$(obj))
+libsbiutils-objs-path-y=$(foreach obj,$(libsbiutils-objs-y),$(build_dir)/lib/utils/$(obj))
+ifdef PLATFORM
+platform-objs-path-y=$(foreach obj,$(platform-objs-y),$(platform_build_dir)/$(obj))
+firmware-bins-path-y=$(foreach bin,$(firmware-bins-y),$(platform_build_dir)/firmware/$(bin))
+endif
+firmware-elfs-path-y=$(firmware-bins-path-y:.bin=.elf)
+firmware-objs-path-y=$(firmware-bins-path-y:.bin=.o)
+
+# Setup list of deps files for objects
+deps-y=$(platform-objs-path-y:.o=.dep)
+deps-y+=$(libsbi-objs-path-y:.o=.dep)
+deps-y+=$(libsbiutils-objs-path-y:.o=.dep)
+deps-y+=$(firmware-objs-path-y:.o=.dep)
+
+# Setup platform ABI, ISA and Code Model
+ifndef PLATFORM_RISCV_ABI
+ 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 = $(OPENSBI_CC_ABI)
+ endif
+endif
+ifndef PLATFORM_RISCV_ISA
+ 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
+endif
+
+# Setup install directories
+ifdef INSTALL_INCLUDE_PATH
+ install_include_path=$(INSTALL_INCLUDE_PATH)
+else
+ install_include_path=include
+endif
+ifdef INSTALL_LIB_PATH
+ install_lib_path=$(INSTALL_LIB_PATH)
+else
+ ifneq ($(origin INSTALL_LIB_SUBDIR), undefined)
+ install_lib_subdir=$(INSTALL_LIB_SUBDIR)
+ else
+ install_lib_subdir=$(PLATFORM_RISCV_ABI)
+ endif
+ install_lib_path=lib$(subst 32,,$(PLATFORM_RISCV_XLEN))/$(install_lib_subdir)
+endif
+ifdef INSTALL_FIRMWARE_PATH
+ install_firmware_path=$(INSTALL_FIRMWARE_PATH)
+else
+ install_firmware_path=share/opensbi/$(PLATFORM_RISCV_ABI)
+endif
+ifdef INSTALL_DOCS_PATH
+ install_docs_path=$(INSTALL_DOCS_PATH)
+else
+ install_docs_path=share/opensbi/docs
+endif
+
+# Setup compilation commands flags
+GENFLAGS = -I$(platform_src_dir)/include
+GENFLAGS += -I$(include_dir)
+ifneq ($(OPENSBI_VERSION_GIT),)
+GENFLAGS += -DOPENSBI_VERSION_GIT="\"$(OPENSBI_VERSION_GIT)\""
+endif
+GENFLAGS += $(libsbiutils-genflags-y)
+GENFLAGS += $(platform-genflags-y)
+GENFLAGS += $(firmware-genflags-y)
+
+CFLAGS = -g -Wall -Werror -ffreestanding -nostdlib -fno-strict-aliasing -O2
+CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
+CFLAGS += -mno-save-restore -mstrict-align
+CFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
+CFLAGS += -mcmodel=$(PLATFORM_RISCV_CODE_MODEL)
+CFLAGS += $(GENFLAGS)
+CFLAGS += $(platform-cflags-y)
+CFLAGS += $(firmware-cflags-y)
+CFLAGS += -fno-pie -no-pie
+
+CPPFLAGS += $(GENFLAGS)
+CPPFLAGS += $(platform-cppflags-y)
+CPPFLAGS += $(firmware-cppflags-y)
+
+ASFLAGS = -g -Wall -nostdlib -D__ASSEMBLY__
+ASFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
+ASFLAGS += -mno-save-restore -mstrict-align
+ASFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
+ASFLAGS += -mcmodel=$(PLATFORM_RISCV_CODE_MODEL)
+ASFLAGS += $(GENFLAGS)
+ASFLAGS += $(platform-asflags-y)
+ASFLAGS += $(firmware-asflags-y)
+
+ARFLAGS = rcs
+
+ELFFLAGS += -Wl,--build-id=none -N -static-libgcc -lgcc
+ELFFLAGS += $(platform-ldflags-y)
+ELFFLAGS += $(firmware-ldflags-y)
+
+MERGEFLAGS += -r
+MERGEFLAGS += -b elf$(PLATFORM_RISCV_XLEN)-littleriscv
+MERGEFLAGS += -m elf$(PLATFORM_RISCV_XLEN)lriscv
+
+DTSCPPFLAGS = $(CPPFLAGS) -nostdinc -nostdlib -fno-builtin -D__DTS__ -x assembler-with-cpp
+
+# Setup functions for compilation
+define dynamic_flags
+-I$(shell dirname $(2)) -D__OBJNAME__=$(subst -,_,$(shell basename $(1) .o))
+endef
+merge_objs = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
+ echo " MERGE $(subst $(build_dir)/,,$(1))"; \
+ $(LD) $(MERGEFLAGS) $(2) -o $(1)
+merge_deps = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
+ echo " MERGE-DEP $(subst $(build_dir)/,,$(1))"; \
+ cat $(2) > $(1)
+copy_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
+ echo " COPY $(subst $(build_dir)/,,$(1))"; \
+ cp -f $(2) $(1)
+inst_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
+ echo " INSTALL $(subst $(install_root_dir)/,,$(1))"; \
+ cp -f $(2) $(1)
+inst_file_list = $(CMD_PREFIX)if [ ! -z "$(4)" ]; then \
+ mkdir -p $(1)/$(3); \
+ for file in $(4) ; do \
+ rel_file=`echo $$file | sed -e 's@$(2)/$(subst $(install_firmware_path),platform,$(3))@@'`; \
+ dest_file=$(1)"/"$(3)"/"`echo $$rel_file`; \
+ dest_dir=`dirname $$dest_file`; \
+ echo " INSTALL "$(3)"/"`echo $$rel_file`; \
+ mkdir -p $$dest_dir; \
+ cp -f $$file $$dest_file; \
+ done \
+ fi
+inst_header_dir = $(CMD_PREFIX)mkdir -p $(1); \
+ echo " INSTALL $(subst $(install_root_dir)/,,$(1))"; \
+ cp -rf $(2) $(1)
+compile_cpp = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
+ echo " CPP $(subst $(build_dir)/,,$(1))"; \
+ $(CPP) $(CPPFLAGS) -x c $(2) | grep -v "\#" > $(1)
+compile_cc_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
+ echo " CC-DEP $(subst $(build_dir)/,,$(1))"; \
+ printf %s `dirname $(1)`/ > $(1) && \
+ $(CC) $(CFLAGS) $(call dynamic_flags,$(1),$(2)) \
+ -MM $(2) >> $(1) || rm -f $(1)
+compile_cc = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
+ echo " CC $(subst $(build_dir)/,,$(1))"; \
+ $(CC) $(CFLAGS) $(call dynamic_flags,$(1),$(2)) -c $(2) -o $(1)
+compile_as_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
+ echo " AS-DEP $(subst $(build_dir)/,,$(1))"; \
+ printf %s `dirname $(1)`/ > $(1) && \
+ $(AS) $(ASFLAGS) $(call dynamic_flags,$(1),$(2)) \
+ -MM $(2) >> $(1) || rm -f $(1)
+compile_as = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
+ echo " AS $(subst $(build_dir)/,,$(1))"; \
+ $(AS) $(ASFLAGS) $(call dynamic_flags,$(1),$(2)) -c $(2) -o $(1)
+compile_elf = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
+ echo " ELF $(subst $(build_dir)/,,$(1))"; \
+ $(CC) $(CFLAGS) $(3) $(ELFFLAGS) -Wl,-T$(2) -o $(1)
+compile_ar = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
+ echo " AR $(subst $(build_dir)/,,$(1))"; \
+ $(AR) $(ARFLAGS) $(1) $(2)
+compile_objcopy = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
+ echo " OBJCOPY $(subst $(build_dir)/,,$(1))"; \
+ $(OBJCOPY) -S -O binary $(2) $(1)
+compile_dts = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
+ echo " DTC $(subst $(build_dir)/,,$(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))"; \
+ $(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)
+
+targets-y = $(build_dir)/lib/libsbi.a
+targets-y += $(build_dir)/lib/libsbiutils.a
+ifdef PLATFORM
+targets-y += $(platform_build_dir)/lib/libplatsbi.a
+endif
+targets-y += $(firmware-bins-path-y)
+
+# Default rule "make" should always be first rule
+.PHONY: all
+all: $(targets-y)
+
+# Preserve all intermediate files
+.SECONDARY:
+
+$(build_dir)/lib/libsbi.a: $(libsbi-objs-path-y)
+ $(call compile_ar,$@,$^)
+
+$(build_dir)/lib/libsbiutils.a: $(libsbi-objs-path-y) $(libsbiutils-objs-path-y)
+ $(call compile_ar,$@,$^)
+
+$(platform_build_dir)/lib/libplatsbi.a: $(libsbi-objs-path-y) $(libsbiutils-objs-path-y) $(platform-objs-path-y)
+ $(call compile_ar,$@,$^)
+
+$(build_dir)/%.dep: $(src_dir)/%.c
+ $(call compile_cc_dep,$@,$<)
+
+$(build_dir)/%.o: $(src_dir)/%.c
+ $(call compile_cc,$@,$<)
+
+$(build_dir)/%.dep: $(src_dir)/%.S
+ $(call compile_as_dep,$@,$<)
+
+$(build_dir)/%.o: $(src_dir)/%.S
+ $(call compile_as,$@,$<)
+
+$(platform_build_dir)/%.bin: $(platform_build_dir)/%.elf
+ $(call compile_objcopy,$@,$<)
+
+$(platform_build_dir)/%.elf: $(platform_build_dir)/%.o $(platform_build_dir)/%.elf.ld $(platform_build_dir)/lib/libplatsbi.a
+ $(call compile_elf,$@,$@.ld,$< $(platform_build_dir)/lib/libplatsbi.a)
+
+$(platform_build_dir)/%.ld: $(src_dir)/%.ldS
+ $(call compile_cpp,$@,$<)
+
+$(platform_build_dir)/%.dep: $(platform_src_dir)/%.c
+ $(call compile_cc_dep,$@,$<)
+
+$(platform_build_dir)/%.o: $(platform_src_dir)/%.c
+ $(call compile_cc,$@,$<)
+
+$(platform_build_dir)/%.o: $(platform_build_dir)/%.c
+ $(call compile_cc,$@,$<)
+
+$(platform_build_dir)/%.dep: $(platform_src_dir)/%.S
+ $(call compile_as_dep,$@,$<)
+
+$(platform_build_dir)/%.o: $(platform_src_dir)/%.S
+ $(call compile_as,$@,$<)
+
+$(platform_build_dir)/%.dep: $(platform_src_dir)/%.dts
+ $(call compile_gen_dep,$@,.dtb,$<)
+ $(call compile_gen_dep,$@,.c,$(@:.dep=.dtb))
+ $(call compile_gen_dep,$@,.o,$(@:.dep=.c))
+
+$(platform_build_dir)/%.c: $(platform_build_dir)/%.dtb
+ $(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,$@,$<)
+
+$(platform_build_dir)/%.dep: $(src_dir)/%.c
+ $(call compile_cc_dep,$@,$<)
+
+$(platform_build_dir)/%.o: $(src_dir)/%.c
+ $(call compile_cc,$@,$<)
+
+$(platform_build_dir)/%.dep: $(src_dir)/%.S
+ $(call compile_as_dep,$@,$<)
+
+$(platform_build_dir)/%.o: $(src_dir)/%.S
+ $(call compile_as,$@,$<)
+
+# Rule for "make docs"
+$(build_dir)/docs/latex/refman.pdf: $(build_dir)/docs/latex/refman.tex
+ $(CMD_PREFIX)mkdir -p $(build_dir)/docs
+ $(CMD_PREFIX)$(MAKE) -C $(build_dir)/docs/latex
+$(build_dir)/docs/latex/refman.tex: $(build_dir)/docs/doxygen.cfg
+ $(CMD_PREFIX)mkdir -p $(build_dir)/docs
+ $(CMD_PREFIX)doxygen $(build_dir)/docs/doxygen.cfg
+$(build_dir)/docs/doxygen.cfg: $(src_dir)/docs/doxygen.cfg
+ $(CMD_PREFIX)mkdir -p $(build_dir)/docs
+ $(CMD_PREFIX)cat docs/doxygen.cfg | sed -e "s#@@SRC_DIR@@#$(src_dir)#" -e "s#@@BUILD_DIR@@#$(build_dir)#" -e "s#@@OPENSBI_MAJOR@@#$(OPENSBI_VERSION_MAJOR)#" -e "s#@@OPENSBI_MINOR@@#$(OPENSBI_VERSION_MINOR)#" > $(build_dir)/docs/doxygen.cfg
+.PHONY: docs
+docs: $(build_dir)/docs/latex/refman.pdf
+
+# Dependency files should only be included after default Makefile rules
+# They should not be included for any "xxxconfig" or "xxxclean" rule
+all-deps-1 = $(if $(findstring config,$(MAKECMDGOALS)),,$(deps-y))
+all-deps-2 = $(if $(findstring clean,$(MAKECMDGOALS)),,$(all-deps-1))
+-include $(all-deps-2)
+
+# Include external dependency of firmwares after default Makefile rules
+include $(src_dir)/firmware/external_deps.mk
+
+# Convenient "make run" command for emulated platforms
+.PHONY: run
+run: all
+ifneq ($(platform-runcmd),)
+ $(platform-runcmd) $(RUN_ARGS)
+else
+ifdef PLATFORM
+ @echo "Platform $(PLATFORM) doesn't specify a run command"
+ @false
+else
+ @echo Run command only available when targeting a platform
+ @false
+endif
+endif
+
+install_targets-y = install_libsbi
+install_targets-y += install_libsbiutils
+ifdef PLATFORM
+install_targets-y += install_libplatsbi
+install_targets-y += install_firmwares
+endif
+
+# Rule for "make install"
+.PHONY: install
+install: $(install_targets-y)
+
+.PHONY: install_libsbi
+install_libsbi: $(build_dir)/lib/libsbi.a
+ $(call inst_header_dir,$(install_root_dir)/$(install_include_path),$(include_dir)/sbi)
+ $(call inst_file,$(install_root_dir)/$(install_lib_path)/libsbi.a,$(build_dir)/lib/libsbi.a)
+
+.PHONY: install_libsbiutils
+install_libsbiutils: $(build_dir)/lib/libsbiutils.a
+ $(call inst_header_dir,$(install_root_dir)/$(install_include_path),$(include_dir)/sbi_utils)
+ $(call inst_file,$(install_root_dir)/$(install_lib_path)/libsbiutils.a,$(build_dir)/lib/libsbiutils.a)
+
+.PHONY: install_libplatsbi
+install_libplatsbi: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(build_dir)/lib/libsbiutils.a
+ $(call inst_file,$(install_root_dir)/$(install_lib_path)/opensbi/$(platform_subdir)/lib/libplatsbi.a,$(platform_build_dir)/lib/libplatsbi.a)
+
+.PHONY: install_firmwares
+install_firmwares: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(build_dir)/lib/libsbiutils.a $(firmware-bins-path-y)
+ $(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-elfs-path-y))
+ $(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-bins-path-y))
+
+.PHONY: install_docs
+install_docs: $(build_dir)/docs/latex/refman.pdf
+ $(call inst_file,$(install_root_dir)/$(install_docs_path)/refman.pdf,$(build_dir)/docs/latex/refman.pdf)
+
+# Rule for "make clean"
+.PHONY: clean
+clean:
+ $(CMD_PREFIX)mkdir -p $(build_dir)
+ $(if $(V), @echo " RM $(build_dir)/*.o")
+ $(CMD_PREFIX)find $(build_dir) -type f -name "*.o" -exec rm -rf {} +
+ $(if $(V), @echo " RM $(build_dir)/*.a")
+ $(CMD_PREFIX)find $(build_dir) -type f -name "*.a" -exec rm -rf {} +
+ $(if $(V), @echo " RM $(build_dir)/*.elf")
+ $(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
+distclean: clean
+ $(CMD_PREFIX)mkdir -p $(build_dir)
+ $(if $(V), @echo " RM $(build_dir)/*.dep")
+ $(CMD_PREFIX)find $(build_dir) -type f -name "*.dep" -exec rm -rf {} +
+ifeq ($(build_dir),$(CURDIR)/build)
+ $(if $(V), @echo " RM $(build_dir)")
+ $(CMD_PREFIX)rm -rf $(build_dir)
+endif
+ifeq ($(install_root_dir),$(install_root_dir_default)/usr)
+ $(if $(V), @echo " RM $(install_root_dir_default)")
+ $(CMD_PREFIX)rm -rf $(install_root_dir_default)
+endif
diff --git a/roms/opensbi/README.md b/roms/opensbi/README.md
new file mode 100644
index 000000000..03c02fb1c
--- /dev/null
+++ b/roms/opensbi/README.md
@@ -0,0 +1,286 @@
+RISC-V Open Source Supervisor Binary Interface (OpenSBI)
+========================================================
+
+Copyright and License
+---------------------
+
+The OpenSBI project is copyright (c) 2019 Western Digital Corporation
+or its affiliates and other contributors.
+
+It is distributed under the terms of the BSD 2-clause license
+("Simplified BSD License" or "FreeBSD License", SPDX: *BSD-2-Clause*).
+A copy of this license with OpenSBI copyright can be found in the file
+[COPYING.BSD].
+
+All source files in OpenSBI contain the 2-Clause BSD license SPDX short
+identifier in place of the full license text.
+
+```
+SPDX-License-Identifier: BSD-2-Clause
+```
+
+This enables machine processing of license information based on the SPDX
+License Identifiers that are available on the [SPDX] web site.
+
+OpenSBI source code also contains code reused from other projects as listed
+below. The original license text of these projects is included in the source
+files where the reused code is present.
+
+* The libfdt source code is disjunctively dual licensed
+ (GPL-2.0+ OR BSD-2-Clause). Some of this project code is used in OpenSBI
+ under the terms of the BSD 2-Clause license. Any contributions to this
+ code must be made under the terms of both licenses.
+
+See also the [third party notices] file for more information.
+
+Introduction
+------------
+
+The **RISC-V Supervisor Binary Interface (SBI)** is the recommended interface
+between:
+
+1. A platform-specific firmware running in M-mode and a bootloader, a
+ hypervisor or a general-purpose OS executing in S-mode or HS-mode.
+2. A hypervisor running in HS-mode and a bootloader or a general-purpose OS
+ executing in VS-mode.
+
+The *RISC-V SBI specification* is maintained as an independent project by the
+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
+executing in M-mode (case 1 mentioned above). An OpenSBI implementation can be
+easily extended by RISC-V platform and system-on-chip vendors to fit a
+particular hardware configuration.
+
+The main component of OpenSBI is provided in the form of a platform-independent
+static library **libsbi.a** implementing the SBI interface. A firmware or
+bootloader implementation can link against this library to ensure conformance
+with the SBI interface specifications. *libsbi.a* also defines an interface for
+integrating with platform-specific operations provided by the platform firmware
+implementation (e.g. console access functions, inter-processor interrupt
+control, etc).
+
+To illustrate the use of the *libsbi.a* library, OpenSBI also provides a set of
+platform-specific support examples. For each example, a platform-specific
+static library *libplatsbi.a* can be compiled. This library implements
+SBI call processing by integrating *libsbi.a* with the necessary
+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].
+
+Supported SBI version
+---------------------
+Currently, OpenSBI fully supports SBI specification *v0.2*. OpenSBI also
+supports Hart State Management (HSM) SBI extension starting from OpenSBI v0.7.
+HSM extension allows S-mode software to boot all the harts a defined order
+rather than legacy method of random booting of harts. As a result, many
+required features such as CPU hotplug, kexec/kdump can also be supported easily
+in S-mode. HSM extension in OpenSBI is implemented in a non-backward compatible
+manner to reduce the maintenance burden and avoid confusion. That's why, any
+S-mode software using OpenSBI will not be able to boot more than 1 hart if HSM
+extension is not supported in S-mode.
+
+Linux kernel already supports SBI v0.2 and HSM SBI extension starting from
+**v5.7-rc1**. If you are using an Linux kernel older than **5.7-rc1** or any
+other S-mode software without HSM SBI extension, you should stick to OpenSBI
+v0.6 to boot all the harts. For a UMP systems, it doesn't matter.
+
+N.B. Any S-mode boot loader (i.e. U-Boot) doesn't need to support HSM extension,
+as it doesn't need to boot all the harts. The operating system should be
+capable enough to bring up all other non-booting harts using HSM extension.
+
+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].
+
+Please note that only a 64-bit version of the toolchain is available in
+the Bootlin toolchain repository for now.
+
+Building and Installing the OpenSBI Platform-Independent Library
+----------------------------------------------------------------
+
+The OpenSBI platform-independent static library *libsbi.a* can be compiled
+natively or it can be cross-compiled on a host with a different base
+architecture than RISC-V.
+
+For cross-compiling, the environment variable *CROSS_COMPILE* must be defined
+to specify the name prefix of the RISC-V compiler toolchain executables, e.g.
+*riscv64-unknown-elf-* if the gcc executable used is *riscv64-unknown-elf-gcc*.
+
+To build *libsbi.a* simply execute:
+```
+make
+```
+
+All compiled binaries as well as the resulting *libsbi.a* static library file
+will be placed in the *build/lib* directory. To specify an alternate build root
+directory path, run:
+```
+make O=<build_directory>
+```
+
+To generate files to be installed for using *libsbi.a* in other projects, run:
+```
+make install
+```
+
+This will create the *install* directory with all necessary include files
+copied under the *install/include* directory and the library file copied into
+the *install/lib* directory. To specify an alternate installation root
+directory path, run:
+```
+make I=<install_directory> install
+```
+
+Building and Installing a Reference Platform Static Library and Firmware
+------------------------------------------------------------------------
+
+When the *PLATFORM=<platform_subdir>* argument is specified on the make command
+line, the platform-specific static library *libplatsbi.a* and firmware examples
+are built for the platform *<platform_subdir>* present in the directory
+*platform* in the OpenSBI top directory. For example, to compile the platform
+library and the firmware examples for the QEMU RISC-V *virt* machine,
+*<platform_subdir>* should be *generic*.
+
+To build *libsbi.a*, *libplatsbi.a* and the firmware for one of the supported
+platforms, run:
+```
+make PLATFORM=<platform_subdir>
+```
+
+An alternate build directory path can also be specified:
+```
+make PLATFORM=<platform_subdir> O=<build_directory>
+```
+
+The platform-specific library *libplatsbi.a* will be generated in the
+*build/platform/<platform_subdir>/lib* directory. The platform firmware files
+will be under the *build/platform/<platform_subdir>/firmware* directory.
+The compiled firmwares will be available in two different formats: an ELF file
+and an expanded image file.
+
+To install *libsbi.a*, *libplatsbi.a*, and the compiled firmwares, run:
+```
+make PLATFORM=<platform_subdir> install
+```
+
+This will copy the compiled platform-specific libraries and firmware files
+under the *install/platform/<platform_subdir>/* directory. An alternate
+install root directory path can be specified as follows:
+```
+make PLATFORM=<platform_subdir> I=<install_directory> install
+```
+
+In addition, platform-specific configuration options can be specified with the
+top-level make command line. These options, such as *PLATFORM_<xyz>* or
+*FW_<abc>*, are platform-specific and described in more details in the
+*docs/platform/<platform_name>.md* files and
+*docs/firmware/<firmware_name>.md* files.
+
+Building 32-bit / 64-bit OpenSBI Images
+---------------------------------------
+By default, building OpenSBI generates 32-bit or 64-bit images based on the
+supplied RISC-V cross-compile toolchain. For example if *CROSS_COMPILE* is set
+to *riscv64-unknown-elf-*, 64-bit OpenSBI images will be generated. If building
+32-bit OpenSBI images, *CROSS_COMPILE* should be set to a toolchain that is
+pre-configured to generate 32-bit RISC-V codes, like *riscv32-unknown-elf-*.
+
+However it's possible to explicitly specify the image bits we want to build with
+a given RISC-V toolchain. This can be done by setting the environment variable
+*PLATFORM_RISCV_XLEN* to the desired width, for example:
+
+```
+export CROSS_COMPILE=riscv64-unknown-elf-
+export PLATFORM_RISCV_XLEN=32
+```
+
+will generate 32-bit OpenSBI images. And vice vesa.
+
+Contributing to OpenSBI
+-----------------------
+
+The OpenSBI project encourages and welcomes contributions. Contributions should
+follow the rules described in the OpenSBI [Contribution Guideline] document.
+In particular, all patches sent should contain a Signed-off-by tag.
+
+The [Contributors List] document provides a list of individuals and
+organizations actively contributing to the OpenSBI project.
+
+Documentation
+-------------
+
+Detailed documentation of various aspects of OpenSBI can be found under the
+*docs* directory. The documentation covers the following topics.
+
+* [Contribution Guideline]: Guideline for contributing code to OpenSBI project
+* [Library Usage]: API documentation of OpenSBI static library *libsbi.a*
+* [Platform Requirements]: Requirements for using OpenSBI on a platform
+* [Platform Support Guide]: Guideline for implementing support for new platforms
+* [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
+format.
+
+Doxygen can be installed on Linux distributions using *.deb* packages using
+the following command.
+```
+sudo apt-get install doxygen doxygen-latex doxygen-doc doxygen-gui graphviz
+```
+
+For *.rpm* based Linux distributions, the following commands can be used.
+```
+sudo yum install doxygen doxygen-latex doxywizard graphviz
+```
+or
+```
+sudo yum install doxygen doxygen-latex doxywizard graphviz
+```
+
+To build a consolidated *refman.pdf* of all documentation, run:
+```
+make docs
+```
+or
+```
+make O=<build_directory> docs
+```
+
+the resulting *refman.pdf* will be available under the directory
+*<build_directory>/docs/latex*. To install this file, run:
+```
+make install_docs
+```
+or
+```
+make I=<install_directory> install_docs
+```
+
+*refman.pdf* will be installed under *<install_directory>/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
+[Contributors List]: CONTRIBUTORS.md
+[Library Usage]: docs/library_usage.md
+[Platform Requirements]: docs/platform_requirements.md
+[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
diff --git a/roms/opensbi/ThirdPartyNotices.md b/roms/opensbi/ThirdPartyNotices.md
new file mode 100644
index 000000000..1162d4361
--- /dev/null
+++ b/roms/opensbi/ThirdPartyNotices.md
@@ -0,0 +1,18 @@
+Copyright (c) 2019 Western Digital Corporation or its affiliates.
+
+Third Party Notices
+===================
+
+This project includes or partly uses code from the following open source
+software subject to the following open source licenses.
+
+libfdt
+------
+
+Copyright (C) 2016 Free Electrons
+Copyright (C) 2016 NextThing Co.
+
+The libfdt source code is disjunctively dual licensed (GPL-2.0+ or
+BSD-2-Clause). Some of this project code is used in OpenSBI under the terms of
+the BSD 2-Clause license. The full text of this license can be found in the
+file [COPYING.BSD](COPYING.BSD).
diff --git a/roms/opensbi/docs/contributing.md b/roms/opensbi/docs/contributing.md
new file mode 100644
index 000000000..9c2b3ba2c
--- /dev/null
+++ b/roms/opensbi/docs/contributing.md
@@ -0,0 +1,84 @@
+OpenSBI Contribution Guideline
+==============================
+
+All contributions to OpenSBI can be sent in the following ways:
+1. Email patches to the OpenSBI mailing list at `opensbi@lists.infradead.org`
+2. GitHub Pull Requests (PRs) to the [OpenSBI main repository]
+
+To join the OpenSBI mailing list, please visit the [OpenSBI infradead page].
+
+The OpenSBI maintainers prefer patches via the OpenSBI mailing list
+(option 1 above) so that they are visible to a wider audience. All
+accepted patches on the OpenSBI mailing list will be taken by any of
+the OpenSBI maintainers and merged into the [OpenSBI main repository]
+using GitHub PRs.
+
+All contributed work must follow the following rules:
+1. OpenSBI code should be written in accordance to the [Linux coding style].
+2. This project embraces the [Developer Certificate of Origin (DCO)] for
+contributions. This means that you must agree to the following prior to
+submitting patches: if you agree with this developer certificate you
+acknowledge this by adding a Signed-off-by tag to your patch commit log.
+Every submitted patch must have this tag.
+3. A commit message must have a subject line, followed by a blank line,
+followed by a description of the patch content. A blank line and the author
+Signed-off-by tag must follow this description.
+4. A commit subject line must start with a prefix followed by a ":". Common
+prefixes are for example "lib:", "platform:", "firmware:", "docs:", "utils:"
+and "top:".
+5. Maintainers should use "Rebase and Merge" when using GitHub to merge pull
+requests to avoid creating unnecessary merge commits.
+6. Maintainers should avoid creating branches directly in the main
+riscv/opensbi repository. Instead prefer using a fork of the riscv/opensbi main
+repository and branches within that fork to create pull requests.
+7. A maintainer cannot merge his own pull requests in the riscv/opensbi main
+repository.
+8. A pull request must get at least one review from a maintainer.
+9. A pull request must spend at least 24 hours in review to allow for other
+developers to review.
+
+-----------------------------------------------------------------------
+
+Developer Certificate of Origin
+Version 1.1
+
+Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
+660 York Street, Suite 102,
+San Francisco, CA 94110 USA
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+
+
+Developer's Certificate of Origin 1.1
+
+By making a contribution to this project, I certify that:
+
+(a) The contribution was created in whole or in part by me and I
+ have the right to submit it under the open source license
+ indicated in the file; or
+
+(b) The contribution is based upon previous work that, to the best
+ of my knowledge, is covered under an appropriate open source
+ license and I have the right under that license to submit that
+ work with modifications, whether created in whole or in part
+ by me, under the same open source license (unless I am
+ permitted to submit under a different license), as indicated
+ in the file; or
+
+(c) The contribution was provided directly to me by some other
+ person who certified (a), (b) or (c) and I have not modified
+ it.
+
+(d) I understand and agree that this project and the contribution
+ are public and that a record of the contribution (including all
+ personal information I submit with it, including my sign-off) is
+ maintained indefinitely and may be redistributed consistent with
+ this project or the open source license(s) involved.
+
+-----------------------------------------------------------------------
+
+[OpenSBI main repository]: https://github.com/riscv/opensbi
+[OpenSBI infradead page]: http://lists.infradead.org/mailman/listinfo/opensbi
+[Linux coding style]: https://www.kernel.org/doc/html/v4.10/process/coding-style.html
+[Developer Certificate of Origin (DCO)]: http://developercertificate.org/
diff --git a/roms/opensbi/docs/domain_support.md b/roms/opensbi/docs/domain_support.md
new file mode 100644
index 000000000..73931f1da
--- /dev/null
+++ b/roms/opensbi/docs/domain_support.md
@@ -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 {
+ ...
+ };
+```
diff --git a/roms/opensbi/docs/doxygen.cfg b/roms/opensbi/docs/doxygen.cfg
new file mode 100644
index 000000000..82f31a7ae
--- /dev/null
+++ b/roms/opensbi/docs/doxygen.cfg
@@ -0,0 +1,2462 @@
+# Doxyfile 1.8.13
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "RISC-V OpenSBI"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER = "v@@OPENSBI_MAJOR@@.@@OPENSBI_MINOR@@"
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = "Open source implemenation of the supervisor binary interface"
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = @@BUILD_DIR@@/docs
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 0.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS = 0
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = YES
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = @@SRC_DIR@@/README.md \
+ @@SRC_DIR@@/docs/contributing.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 \
+ @@SRC_DIR@@/lib
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
+
+FILE_PATTERNS = *.c \
+ *.h \
+ *.md
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE = README.md
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse-libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = NO
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = NO
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = NO
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = YES
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = YES
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/roms/opensbi/docs/external/coreboot.md b/roms/opensbi/docs/external/coreboot.md
new file mode 100644
index 000000000..de32e902c
--- /dev/null
+++ b/roms/opensbi/docs/external/coreboot.md
@@ -0,0 +1,32 @@
+OpenSBI as coreboot payload
+===========================
+
+[coreboot] is a free/libre and open source firmware platform support multiple
+hardware architectures(x86, ARMv7, arm64, PowerPC64, MIPS and RISC-V) and
+diverse hardware models. In RISC-V world, coreboot currently support HiFive
+Unleashed with OpenSBI as a payload to boot GNU/Linux:
+
+```
+SiFive HiFive unleashed's original firmware boot process:
+ +-----------+
++------+ +------+ +------+ | BBL |
+| MSEL |--->| ZSBL |--->| FSBL |--->| +-------+
++------+ +------+ +------+ | | linux |
+ +---+-------+
+
+coreboot boot process:
+ +---------------------------------------------------------------------+
+ | coreboot |
++------+ +------+ | +-----------+ +----------+ +----------+ +-----------------------+
+| MSEL |-->| ZSBL |-->| | bootblock |->| romstage |->| ramstage |->| payload ( OpenSBI) |
++------+ +------+ | +-----------+ +----------+ +----------+ | +-------+ |
+ | | | linux | |
+ +---------------------------------------------+-------------+-------+-+
+```
+
+The upstreaming work is still in progress. There's a [documentation] about how
+to build [out-of-tree code] to load OpenSBI.
+
+[coreboot]: https://www.coreboot.org/
+[documentation]: https://github.com/hardenedlinux/embedded-iot_profile/blob/master/docs/riscv/hifiveunleashed_coreboot_notes-en.md
+[out-of-tree code]: https://github.com/hardenedlinux/coreboot-HiFiveUnleashed
diff --git a/roms/opensbi/docs/firmware/fw.md b/roms/opensbi/docs/firmware/fw.md
new file mode 100644
index 000000000..cc0cc9e56
--- /dev/null
+++ b/roms/opensbi/docs/firmware/fw.md
@@ -0,0 +1,111 @@
+OpenSBI Platform Firmwares
+==========================
+
+OpenSBI provides firmware builds for specific platforms. Different types of
+firmwares are supported to deal with the differences between different platforms
+early boot stage. All firmwares will execute the same initialization procedure
+of the platform hardware according to the platform specific code as well as
+OpenSBI generic library code. The supported firmwares type will differ in how
+the arguments passed by the platform early boot stage are handled, as well as
+how the boot stage following the firmware will be handled and executed.
+
+OpenSBI currently supports three different types of firmwares.
+
+Firmware with Dynamic Information (*FW_DYNAMIC*)
+------------------------------------------------
+
+The *FW_DYNAMIC* firmware gets information about the next booting stage entry,
+e.g. a bootloader or an OS kernel, from previous booting stage at runtime.
+
+A *FW_DYNAMIC* firmware is particularly useful when the booting stage executed
+prior to OpenSBI firmware is capable of loading both the OpenSBI firmware
+and the booting stage binary to follow OpenSBI firmware.
+
+Firmware with Jump Address (*FW_JUMP*)
+--------------------------------------
+
+The *FW_JUMP* firmware assumes a fixed address of the next booting stage
+entry, e.g. a bootloader or an OS kernel, without directly including the
+binary code for this next stage.
+
+A *FW_JUMP* firmware is particularly useful when the booting stage executed
+prior to OpenSBI firmware is capable of loading both the OpenSBI firmware
+and the booting stage binary to follow OpenSBI firmware.
+
+Firmware with Payload (*FW_PAYLOAD*)
+------------------------------------
+
+The *FW_PAYLOAD* firmware directly includes the binary code for the booting
+stage to follow OpenSBI firmware execution. Typically, this payload will be a
+bootloader or an OS kernel.
+
+A *FW_PAYLOAD* firmware is particularly useful when the booting stage executed
+prior to OpenSBI firmware is not capable of loading both OpenSBI firmware and
+the booting stage to follow OpenSBI firmware.
+
+A *FW_PAYLOAD* firmware is also useful for cases where the booting stage prior
+to OpenSBI firmware does not pass a *flattened device tree (FDT file)*. In such
+case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree in the
+.text section of the final firmware.
+
+Firmware Configuration and Compilation
+--------------------------------------
+
+All firmware types support the following common compile time configuration
+parameters:
+
+* **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
+following documents.
+
+* *[FW_DYNAMIC]*: The *Firmware with Dynamic Information (FW_DYNAMIC)* is
+ described in more details in the file *fw_dynamic.md*.
+* *[FW_JUMP]*: The *Firmware with Jump Address (FW_JUMP)* is described in more
+ details in the file *fw_jump.md*.
+* *[FW_PAYLOAD]*: The *Firmware with Payload (FW_PAYLOAD)* is described in more
+ details in the file *fw_payload.md*.
+
+[FW_DYNAMIC]: fw_dynamic.md
+[FW_JUMP]: fw_jump.md
+[FW_PAYLOAD]: fw_payload.md
+
+Providing different payloads to OpenSBI Firmware
+------------------------------------------------
+OpenSBI firmware can accept various payloads using a compile time option.
+Typically, these payloads refer to the next stage boot loader (e.g. U-Boot)
+or operating system kernel images (e.g. Linux). By default, OpenSBI
+automatically provides a test payload if no specific payload is specified
+at compile time.
+
+To specify a payload at compile time, the make variable _FW_PAYLOAD_PATH_ is
+used.
+```
+make PLATFORM=<platform_subdir> FW_PAYLOAD_PATH=<payload path>
+```
+The instructions to build each payload is different and the details can
+be found in the
+*docs/firmware/payload_<payload_name>.md* files.
+
+Options for OpenSBI Firmware behaviors
+--------------------------------------
+An optional compile time flag FW_OPTIONS can be used to control the OpenSBI
+firmware run-time behaviors.
+
+```
+make PLATFORM=<platform_subdir> FW_OPTIONS=<options>
+```
+
+FW_OPTIONS is a bitwise or'ed value of various options, eg: *FW_OPTIONS=0x1*
+stands for disabling boot prints from the OpenSBI library.
+
+For all supported options, please check "enum sbi_scratch_options" in the
+*include/sbi/sbi_scratch.h* header file.
diff --git a/roms/opensbi/docs/firmware/fw_dynamic.md b/roms/opensbi/docs/firmware/fw_dynamic.md
new file mode 100644
index 000000000..01f43f9f4
--- /dev/null
+++ b/roms/opensbi/docs/firmware/fw_dynamic.md
@@ -0,0 +1,35 @@
+OpenSBI Firmware with Dynamic Information (FW_DYNAMIC)
+======================================================
+
+OpenSBI **firmware with dynamic info (FW_DYNAMIC)** is a firmware which gets
+information about next booting stage (e.g. a bootloader or an OS) and runtime
+OpenSBI library options from previous booting stage.
+
+The previous booting stage will pass information to *FW_DYNAMIC* by creating
+*struct fw_dynamic_info* in memory and passing it's address to *FW_DYNAMIC*
+via *a2* register of RISC-V CPU.
+
+A *FW_DYNAMIC* firmware is particularly useful when the booting stage executed
+prior to OpenSBI firmware is capable of loading both the OpenSBI firmware and
+the booting stage binary to follow OpenSBI firmware.
+
+*FW_DYNAMIC* Compilation
+------------------------
+
+A platform can enable *FW_DYNAMIC* firmware using any of the following methods.
+
+1. Specifying `FW_DYNAMIC=y` on the top level `make` command line.
+2. Specifying `FW_DYNAMIC=y` in the target platform *config.mk* configuration
+file.
+
+The compiled *FW_DYNAMIC* firmware ELF file is named *fw_dynamic.elf*. It's
+expanded image file is *fw_dynamic.bin*. Both files are created in the platform
+specific build directory under the *build/platform/<platform_subdir>/firmware*
+directory.
+
+*FW_DYNAMIC* Firmware Configuration Options
+-------------------------------------------
+
+The *FW_DYNAMIC* firmware does not requires any platform specific configuration
+parameters because all required information is passed by previous booting stage
+at runtime via *struct fw_dynamic_info*.
diff --git a/roms/opensbi/docs/firmware/fw_jump.md b/roms/opensbi/docs/firmware/fw_jump.md
new file mode 100644
index 000000000..eea301387
--- /dev/null
+++ b/roms/opensbi/docs/firmware/fw_jump.md
@@ -0,0 +1,51 @@
+OpenSBI Firmware with Jump Address (FW_JUMP)
+============================================
+
+OpenSBI **firmware with Jump Address (FW_JUMP)** is a firmware which only
+handles the address of the next booting stage entry, e.g. a bootloader or an OS
+kernel, without directly including the binary code for this next stage.
+
+A *FW_JUMP* firmware is particularly useful when the booting stage executed
+prior to the OpenSBI firmware is capable of loading both the OpenSBI firmware
+and the booting stage binary to follow the OpenSBI firmware.
+
+*FW_JUMP* Compilation
+---------------------
+
+A platform *FW_JUMP* firmware can be enabled by any of the following methods:
+
+1. Specifying `FW_JUMP=y` on the top level `make` command line.
+2. Specifying `FW_JUMP=y` in the target platform *config.mk* configuration file.
+
+The compiled *FW_JUMP* firmware ELF file is named *fw_jump.elf*. Its expanded
+image file is *fw_jump.bin*. Both files are created in the platform-specific
+build directory under the *build/platform/<platform_subdir>/firmware* directory.
+
+*FW_JUMP* Firmware Configuration Options
+----------------------------------------
+
+To operate correctly, a *FW_JUMP* firmware requires some configuration
+parameters to be defined using either the top level `make` command line or the
+target platform *config.mk* configuration file. The possible parameters are as
+follows:
+
+* **FW_JUMP_ADDR** - Address of the entry point of the booting stage to be
+ executed following OpenSBI firmware. This address generally corresponds
+ exactly to the address where this next booting stage was loaded. This is a
+ mandatory parameter. Compilation errors will result from not defining this
+ address.
+
+* **FW_JUMP_FDT_ADDR** - Address where the *flattened device tree (FDT file)*
+ passed by the prior booting stage will be placed in memory before executing
+ the booting stage following the OpenSBI firmware. If this option is not
+ provided, then the OpenSBI firmware will pass the FDT address passed by the
+ previous booting stage to the next booting stage.
+
+*FW_JUMP* Example
+-----------------
+
+The *[qemu/virt]* platform illustrates how to configure and use a *FW_JUMP*
+firmware. Detailed information regarding these platforms can be found in the
+platform documentation files.
+
+[qemu/virt]: ../platform/qemu_virt.md
diff --git a/roms/opensbi/docs/firmware/fw_payload.md b/roms/opensbi/docs/firmware/fw_payload.md
new file mode 100644
index 000000000..094744806
--- /dev/null
+++ b/roms/opensbi/docs/firmware/fw_payload.md
@@ -0,0 +1,72 @@
+OpenSBI Firmware with Payload (FW_PAYLOAD)
+==========================================
+
+OpenSBI **firmware with Payload (FW_PAYLOAD)** is a firmware which directly
+includes the binary for the booting stage to follow the OpenSBI firmware
+execution. Typically, this payload will be a bootloader or an OS kernel.
+
+A *FW_PAYLOAD* firmware is particularly useful when the booting stage executed
+prior to the OpenSBI firmware is not capable of loading both the OpenSBI
+firmware and the booting stage to follow OpenSBI firmware.
+
+A *FW_PAYLOAD* firmware is also useful for cases where the booting stage prior
+to the OpenSBI firmware does not pass a *flattened device tree (FDT file)*. In
+such a case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree
+in the .text section of the final firmware.
+
+Enabling *FW_PAYLOAD* compilation
+---------------------------------
+
+The *FW_PAYLOAD* firmware can be enabled by any of the following methods:
+
+1. Specifying `FW_PAYLOAD=y` on the top level `make` command line.
+2. Specifying `FW_PAYLOAD=y` in the target platform *config.mk* configuration
+ file.
+
+The compiled *FW_PAYLOAD* firmware ELF file is named *fw_jump.elf*. Its
+expanded image file is *fw_payload.bin*. Both files are created in the
+platform-specific build directory under the
+*build/platform/<platform_subdir>/firmware* directory.
+
+Configuration Options
+---------------------
+
+A *FW_PAYLOAD* firmware is built according to configuration parameters and
+options. These configuration parameters can be defined using either the top
+level `make` command line or the target platform *config.mk* configuration
+file. The parameters currently defined are as follows:
+
+* **FW_PAYLOAD_OFFSET** - Offset from *FW_TEXT_BASE* where the payload binary
+ will be linked in the final *FW_PAYLOAD* firmware binary image. This
+ configuration parameter is mandatory if *FW_PAYLOAD_ALIGN* is not defined.
+ Compilation errors will result from an incorrect definition of
+ *FW_PAYLOAD_OFFSET* or of *FW_PAYLOAD_ALIGN*, or if neither of these
+ parameters are defined.
+
+* **FW_PAYLOAD_ALIGN** - Address alignment constraint where the payload binary
+ will be linked after the end of the base firmware binary in the final
+ *FW_PAYLOAD* firmware binary image. This configuration parameter is mandatory
+ if *FW_PAYLOAD_OFFSET* is not defined. If both *FW_PAYLOAD_OFFSET* and
+ *FW_PAYLOAD_ALIGN* are defined, *FW_PAYLOAD_OFFSET* is used and
+ *FW_PAYLOAD_ALIGN* is ignored.
+
+* **FW_PAYLOAD_PATH** - Path to the image file of the next booting stage
+ binary. If this option is not provided then a simple test payload is
+ 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_ADDR** - Address where the FDT passed by the prior booting
+ 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.
+
+*FW_PAYLOAD* Example
+--------------------
+
+The *[qemu/virt]* platforms illustrate how to configure and use a *FW_PAYLOAD*
+firmware. Detailed information regarding these platforms can be found in the
+platform documentation files.
+
+[qemu/virt]: ../platform/qemu_virt.md
diff --git a/roms/opensbi/docs/firmware/payload_linux.md b/roms/opensbi/docs/firmware/payload_linux.md
new file mode 100644
index 000000000..e896567ab
--- /dev/null
+++ b/roms/opensbi/docs/firmware/payload_linux.md
@@ -0,0 +1,9 @@
+Linux as a direct payload to OpenSBI
+====================================
+
+OpenSBI has the capability to load a Linux kernel image directly in supervisor
+mode. The flattened image generated by the Linux kernel build process can be
+provided as a payload to OpenSBI.
+
+Detailed examples can be found in both the [QEMU](../platform/qemu_virt.md)
+and the [HiFive Unleashed](../platform/sifive_fu540.md) platform guides.
diff --git a/roms/opensbi/docs/firmware/payload_uboot.md b/roms/opensbi/docs/firmware/payload_uboot.md
new file mode 100644
index 000000000..b8f0803e2
--- /dev/null
+++ b/roms/opensbi/docs/firmware/payload_uboot.md
@@ -0,0 +1,15 @@
+U-Boot as a payload to OpenSBI
+==============================
+
+[U-Boot](https://www.denx.de/wiki/U-Boot) is an open-source primary boot loader.
+It can be used as first and/or second stage boot loader in an embedded
+environment. In the context of OpenSBI, U-Boot can be specified as a payload to
+the OpenSBI firmware, becoming the boot stage following the OpenSBI firmware
+execution.
+
+Building and Generating U-Boot images
+=====================================
+Please refer to the U-Boot build documentation for detailed instructions on
+how to build U-Boot image and boot high level operating systems from U-Boot
+prompt.
+
diff --git a/roms/opensbi/docs/library_usage.md b/roms/opensbi/docs/library_usage.md
new file mode 100644
index 000000000..ff99801fc
--- /dev/null
+++ b/roms/opensbi/docs/library_usage.md
@@ -0,0 +1,89 @@
+OpenSBI Library Usage
+=====================
+
+OpenSBI provides two types of static libraries:
+
+1. *libsbi.a* - A platform-independent generic static library implementing the
+ interface defined by the SBI specifications. Platform-specific processing
+ hooks for the execution of this interface must be provided by the firmware or
+ bootloader linking with this library. This library is installed as
+ *<install_directory>/lib/libsbi.a*
+2. *libsbiutils.a* - A static library that will contain all common code required
+ by any platform supported in OpenSBI. It will be built by default and included
+ in libplatsbi.a. This library is installed as
+ *<install_directory>/lib/libsbiutils.a*.
+3. *libplatsbi.a* - An example platform-specific static library integrating
+ *libsbi.a* with platform-specific hooks. This library is available only for
+ the platforms supported by OpenSBI. This library is installed as
+ *<install_directory>/platform/<platform_subdir>/lib/libplatsbi.a*
+
+Implementations may choose either *libsbi.a* or *libplatsbi.a* to link with
+their firmware or bootloader. In the case of *libsbi.a*, platform-specific
+hooks in the form of a *struct sbi_platform* instance need to be provided.
+
+The platform-specific example firmwares provided by OpenSBI are not mandatory.
+An implementation may choose to link the OpenSBI generic static library together
+with an M-mode firmware or bootloader providing the hardware-specific hooks.
+Since OpenSBI is a statically linked library, users must ensure that the
+license of these external components is compatible with the OpenSBI license.
+
+Constraints on OpenSBI usage from external firmware
+---------------------------------------------------
+
+Users have to ensure that an external firmware or bootloader linking against
+OpenSBI static libraries (*libsbi.a* or *libplatsbi.a*) is compiled with the
+same GCC target options *-mabi*, *-march*, and *-mcmodel*.
+
+There are only two constraints on calling any OpenSBI library function from an
+external M-mode firmware or bootloader:
+
+1. The RISC-V *MSCRATCH* CSR must point to a valid OpenSBI scratch space
+ (i.e. a *struct sbi_scratch* instance).
+2. The RISC-V *SP* register (i.e. the stack pointer) must be set per-HART
+ pointing to distinct non-overlapping stacks.
+
+The most important functions from an external firmware or bootloader
+perspective are *sbi_init()* and *sbi_trap_handler()*.
+
+In addition to the above constraints, the external firmware or bootloader must
+ensure that interrupts are disabled in the *MSTATUS* and *MIE* CSRs when calling
+the functions *sbi_init()* and *sbi_trap_handler()*.
+
+The *sbi_init()* function should be called by the external firmware or
+bootloader for each HART that is powered-up at boot-time or in response to a
+CPU hotplug event.
+
+The *sbi_trap_handler()* function should be called by the external firmware or
+bootloader to service the following interrupts and traps:
+
+1. M-mode timer interrupt
+2. M-mode software interrupt
+3. Illegal instruction trap
+4. Misaligned load trap
+5. Misaligned store trap
+6. Supervisor ecall trap
+7. Hypervisor ecall trap
+
+**Note:** external firmwares or bootloaders can be more conservative by
+forwarding all traps and interrupts to *sbi_trap_handler()*.
+
+Definitions of OpenSBI Data Types for the External Firmware
+-----------------------------------------------------------
+
+OpenSBI can be built as library using external firmware build system such as EDK2
+code base (The open source of UEFI firmware implementation) and linked with external
+firmware drivers based on the external firmware architecture.
+
+**OPENSBI_EXTERNAL_SBI_TYPES** identifier is introduced to *sbi_types.h* for selecting
+external header file during the build preprocess in order to define OpensSBI data types
+based on external firmware data type binding.
+For example, *bool* is declared as *int* in sbi_types.h. However in EDK2 build system,
+*bool* is declared as *BOOLEAN* which is defined as *unsigned char* data type.
+
+External firmware can define **OPENSBI_EXTERNAL_SBI_TYPES** in CFLAGS and specify it to the
+header file maintained in its code tree. However, the external build system has to address
+the additional include directory for the external header file based on its own build system.
+For example,
+*-D***OPENSBI_EXTERNAL_SBI_TYPES***=OpensbiTypes.h*
+Above tells *sbi_types.h* to refer to *OpensbiTypes.h* instead of using original definitions of
+data types.
diff --git a/roms/opensbi/docs/platform/andes-ae350.md b/roms/opensbi/docs/platform/andes-ae350.md
new file mode 100644
index 000000000..46889a1f1
--- /dev/null
+++ b/roms/opensbi/docs/platform/andes-ae350.md
@@ -0,0 +1,30 @@
+Andes AE350 SoC Platform
+========================
+The AE350 AXI/AHB-based platform N25(F)/NX25(F)/D25F/A25/AX25 CPU with level-one
+memories,interrupt controller, debug module, AXI and AHB Bus Matrix Controller,
+AXI-to-AHB Bridge and a collection of fundamentalAHB/APB bus IP components
+pre-integrated together as a system design.The high-quality and configurable
+AHB/APB IPs suites a majority embedded systems, and the verified platform serves
+as a starting point to jump start SoC designs.
+
+To build platform specific library and firmwares, provide the
+*PLATFORM=andes/ae350* parameter to the top level make command.
+
+Platform Options
+----------------
+
+The Andes AE350 platform does not have any platform-specific options.
+
+Building Andes AE350 Platform
+-----------------------------
+
+To use Linux v5.2 should be used to build Andes AE350 OpenSBI binaries by using
+the compile time option FW_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_FDT_PATH=<ae350.dtb path>
+```
diff --git a/roms/opensbi/docs/platform/fpga-ariane.md b/roms/opensbi/docs/platform/fpga-ariane.md
new file mode 100644
index 000000000..f95001fb3
--- /dev/null
+++ b/roms/opensbi/docs/platform/fpga-ariane.md
@@ -0,0 +1,38 @@
+Ariane FPGA SoC Platform
+========================
+Ariane is a 6-stage, single issue, in-order CPU which implements the 64-bit
+RISC-V instruction set. The Ariane FPGA development platform is based on FPGA
+SoC (which currently supports only Genesys 2 board) and is capable of running
+Linux.
+
+The FPGA SoC currently contains the following peripherals:
+- DDR3 memory controller
+- SPI controller to conncet to an SDCard
+- Ethernet controller
+- JTAG port (see debugging section below)
+- Bootrom containing zero stage bootloader and device tree.
+
+To build platform specific library and firmwares, provide the
+*PLATFORM=fpga/ariane* parameter to the top level `make` command.
+
+Platform Options
+----------------
+
+The *Ariane FPGA* platform does not have any platform-specific options.
+
+Building Ariane FPGA Platform
+-----------------------------
+
+**Linux Kernel Payload**
+
+```
+make PLATFORM=fpga/ariane FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
+```
+
+Booting Ariane FPGA Platform
+----------------------------
+
+**Linux Kernel Payload**
+
+As Linux kernel image is embedded in the OpenSBI firmware binary, Ariane will
+directly boot into Linux directly after powered on.
diff --git a/roms/opensbi/docs/platform/fpga-openpiton.md b/roms/opensbi/docs/platform/fpga-openpiton.md
new file mode 100644
index 000000000..7861a197c
--- /dev/null
+++ b/roms/opensbi/docs/platform/fpga-openpiton.md
@@ -0,0 +1,33 @@
+OpenPiton FPGA SoC Platform
+========================
+OpenPiton is the world's first open source, general purpose, multithreaded
+manycore processor. It is a tiled manycore framework scalable from one to
+1/2 billion cores. Currently, OpenPiton supports the 64bit Ariane RISC-V
+processor from ETH Zurich. To this end, Ariane has been equipped with a
+different L1 cache subsystem that follows a write-through protocol and that has
+support for cache invalidations and atomics.
+
+To build platform specific library and firmwares, provide the
+*PLATFORM=fpga/openpiton* parameter to the top level `make` command.
+
+Platform Options
+----------------
+
+The *OpenPiton* platform does not have any platform-specific options.
+
+Building Ariane FPGA Platform
+-----------------------------
+
+**Linux Kernel Payload**
+
+```
+make PLATFORM=fpga/openpiton FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
+```
+
+Booting Ariane FPGA Platform
+----------------------------
+
+**Linux Kernel Payload**
+
+As Linux kernel image is embedded in the OpenSBI firmware binary, Ariane will
+directly boot into Linux directly after powered on.
diff --git a/roms/opensbi/docs/platform/generic.md b/roms/opensbi/docs/platform/generic.md
new file mode 100644
index 000000000..f1f7f6424
--- /dev/null
+++ b/roms/opensbi/docs/platform/generic.md
@@ -0,0 +1,54 @@
+Generic Platform
+================
+
+The **Generic** platform is a flattened device tree (FDT) based platform
+where all platform specific functionality is provided based on FDT passed
+by previous booting stage. The **Generic** platform allows us to use same
+OpenSBI firmware binaries on various emulators, simulators, FPGAs, and
+boards.
+
+By default, the generic FDT platform makes following assumptions:
+
+1. platform FW_TEXT_START is 0x80000000
+2. platform features are default
+3. platform stack size is default
+4. platform has no quirks or work-arounds
+
+The above assumptions (except 1) can be overridden by adding special platform
+callbacks which will be called based on FDT root node compatible string.
+
+Users of the generic FDT platform will have to ensure that:
+
+1. Various FDT based drivers under lib/utils directory are upto date
+ based on their platform requirements
+2. The FDT passed by previous booting stage has DT compatible strings and
+ DT properties in sync with the FDT based drivers under lib/utils directory
+3. The FDT must have "stdout-path" DT property in the "/chosen" DT node when
+ a platform has multiple serial ports or consoles
+4. On multi-HART platform, the FDT must have a DT node for IPI device and
+ lib/utils/ipi directory must have corresponding FDT based IPI driver
+5. The FDT must have a DT node for timer device and lib/utils/timer directory
+ must have corresponding FDT based timer driver
+
+To build the platform-specific library and firmware images, provide the
+*PLATFORM=generic* parameter to the top level `make` command.
+
+For custom FW_TEXT_START, we can build the platform-specific library and
+firmware images by passing *PLATFORM=generic FW_TEXT_START=<custom_text_start>*
+parameter to the top level `make` command.
+
+Platform Options
+----------------
+
+The *Generic* platform does not have any platform-specific options.
+
+RISC-V Platforms Using Generic Platform
+---------------------------------------
+
+* **QEMU RISC-V Virt Machine** (*[qemu_virt.md]*)
+* **Spike** (*[spike.md]*)
+* **Shakti C-class SoC Platform** (*[shakti_cclass.md]*)
+
+[qemu_virt.md]: qemu_virt.md
+[spike.md]: spike.md
+[shakti_cclass.md]: shakti_cclass.md
diff --git a/roms/opensbi/docs/platform/nuclei_ux600.md b/roms/opensbi/docs/platform/nuclei_ux600.md
new file mode 100644
index 000000000..273b6b438
--- /dev/null
+++ b/roms/opensbi/docs/platform/nuclei_ux600.md
@@ -0,0 +1,22 @@
+
+Nuclei UX600 Platform
+=====================
+
+The **Nuclei UX600** is a 64-bit RISC-V Core which is capable of running Linux.
+
+> Nuclei UX600: single core, pipeline as single-issue and 6~9 variable stages, in-order dispatch and out-of-order write-back, running up to >1.2GHz
+
+To build the platform-specific library and firmware images, provide the
+*PLATFORM=nuclei/ux600* parameter to the top level `make` command.
+
+Platform Options
+----------------
+
+The *Nuclei UX600* platform does not have any platform-specific options.
+
+Building Nuclei UX600 Platform
+------------------------------
+
+```
+make PLATFORM=nuclei/ux600 clean all
+```
diff --git a/roms/opensbi/docs/platform/platform.md b/roms/opensbi/docs/platform/platform.md
new file mode 100644
index 000000000..7f4706813
--- /dev/null
+++ b/roms/opensbi/docs/platform/platform.md
@@ -0,0 +1,59 @@
+OpenSBI Supported Platforms
+===========================
+
+OpenSBI currently supports the following virtual and hardware platforms:
+
+* **Generic**: Flattened device tree (FDT) based platform where platform
+ specific functionality is provided based on the FDT passed by previous
+ booting stage. More details on this platform can be found in the file
+ *[generic.md]*.
+
+* **QEMU RISC-V Virt Machine**: Platform support for the QEMU *virt* virtual
+ RISC-V machine. This virtual machine is intended for RISC-V software
+ development and tests. More details on this platform can be found in the
+ file *[qemu_virt.md]*.
+
+* **SiFive FU540 SoC**: Platform support for SiFive FU540 SoC used on the
+ HiFive Unleashed board, as well as the *sifive_u* QEMU virtual RISC-V
+ machine. More details on this platform can be found in the file
+ *[sifive_fu540.md]*.
+
+* **Kendryte K210 SoC**: Platform support for the Kendryte K210 SoC used on
+ boards such as the Kendryte KD233 or the Sipeed MAIX Dock.
+
+* **Ariane FPGA SoC**: Platform support for the Ariane FPGA SoC used on
+ Genesys 2 board. More details on this platform can be found in the file
+ *[fpga-ariane.md]*.
+
+* **Andes AE350 SoC**: Platform support for the Andes's SoC (AE350). More
+ details on this platform can be found in the file *[andes-ae350.md]*.
+
+* **T-HEAD C910**: Platform support for the T-HEAD C910 Processor. More
+ details on this platform can be found in the file *[thead-c910.md]*.
+
+* **Spike**: Platform support for the Spike emulator. More
+ details on this platform can be found in the file *[spike.md]*.
+
+* **OpenPiton FPGA SoC**: Platform support OpenPiton research platform based
+ on ariane core. More details on this platform can be found in the file
+ *[fpga_openpiton.md]*.
+
+* **Shakti C-class SoC Platform**: Platform support for Shakti C-class
+ processor based SOCs. More details on this platform can be found in the
+ file *[shakti_cclass.md]*.
+
+The code for these supported platforms can be used as example to implement
+support for other platforms. The *platform/template* directory also provides
+template files for implementing support for a new platform. The *object.mk*,
+*config.mk* and *platform.c* template files provides enough comments to
+facilitate the implementation.
+
+[generic.md]: generic.md
+[qemu_virt.md]: qemu_virt.md
+[sifive_fu540.md]: sifive_fu540.md
+[fpga-ariane.md]: fpga-ariane.md
+[andes-ae350.md]: andes-ae350.md
+[thead-c910.md]: thead-c910.md
+[spike.md]: spike.md
+[fpga_openpiton.md]: fpga_openpiton.md
+[shakti_cclass.md]: shakti_cclass.md
diff --git a/roms/opensbi/docs/platform/qemu_virt.md b/roms/opensbi/docs/platform/qemu_virt.md
new file mode 100644
index 000000000..27771485c
--- /dev/null
+++ b/roms/opensbi/docs/platform/qemu_virt.md
@@ -0,0 +1,149 @@
+QEMU RISC-V Virt Machine Platform
+=================================
+
+The **QEMU RISC-V Virt Machine** is a virtual platform created for RISC-V
+software development and testing. It is also referred to as
+*QEMU RISC-V VirtIO machine* because it uses VirtIO devices for network,
+storage, and other types of IO.
+
+To build the platform-specific library and firmware images, provide the
+*PLATFORM=generic* parameter to the top level `make` command.
+
+Platform Options
+----------------
+
+The *QEMU RISC-V Virt Machine* platform does not have any platform-specific
+options.
+
+Execution on QEMU RISC-V 64-bit
+-------------------------------
+
+**No Payload Case**
+
+Build:
+```
+make PLATFORM=generic
+```
+
+Run:
+```
+qemu-system-riscv64 -M virt -m 256M -nographic \
+ -bios build/platform/generic/firmware/fw_payload.bin
+```
+
+**U-Boot Payload**
+
+Note: the command line examples here assume that U-Boot was compiled using
+the `qemu-riscv64_smode_defconfig` configuration.
+
+Build:
+```
+make PLATFORM=generic FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
+```
+
+Run:
+```
+qemu-system-riscv64 -M virt -m 256M -nographic \
+ -bios build/platform/generic/firmware/fw_payload.elf
+```
+or
+```
+qemu-system-riscv64 -M virt -m 256M -nographic \
+ -bios build/platform/generic/firmware/fw_jump.bin \
+ -kernel <uboot_build_directory>/u-boot.bin
+```
+
+**Linux Kernel Payload**
+
+Note: We assume that the Linux kernel is compiled using
+*arch/riscv/configs/defconfig*.
+
+Build:
+```
+make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
+```
+
+Run:
+```
+qemu-system-riscv64 -M virt -m 256M -nographic \
+ -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"
+```
+or
+```
+qemu-system-riscv64 -M virt -m 256M -nographic \
+ -bios build/platform/generic/firmware/fw_jump.bin \
+ -kernel <linux_build_directory>/arch/riscv/boot/Image \
+ -drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
+ -device virtio-blk-device,drive=hd0 \
+ -append "root=/dev/vda rw console=ttyS0"
+```
+
+
+Execution on QEMU RISC-V 32-bit
+-------------------------------
+
+**No Payload Case**
+
+Build:
+```
+make PLATFORM=generic PLATFORM_RISCV_XLEN=32
+```
+
+Run:
+```
+qemu-system-riscv32 -M virt -m 256M -nographic \
+ -bios build/platform/generic/firmware/fw_payload.bin
+```
+
+**U-Boot Payload**
+
+Note: the command line examples here assume that U-Boot was compiled using
+the `qemu-riscv32_smode_defconfig` configuration.
+
+Build:
+```
+make PLATFORM=generic PLATFORM_RISCV_XLEN=32 FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
+```
+
+Run:
+```
+qemu-system-riscv32 -M virt -m 256M -nographic \
+ -bios build/platform/generic/firmware/fw_payload.elf
+```
+or
+```
+qemu-system-riscv32 -M virt -m 256M -nographic \
+ -bios build/platform/generic/firmware/fw_jump.bin \
+ -kernel <uboot_build_directory>/u-boot.bin
+```
+
+**Linux Kernel Payload**
+
+Note: We assume that the Linux kernel is compiled using
+*arch/riscv/configs/rv32_defconfig*.
+
+Build:
+```
+make PLATFORM=generic PLATFORM_RISCV_XLEN=32 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
+```
+
+Run:
+```
+qemu-system-riscv32 -M virt -m 256M -nographic \
+ -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"
+```
+or
+```
+qemu-system-riscv32 -M virt -m 256M -nographic \
+ -bios build/platform/generic/firmware/fw_jump.bin \
+ -kernel <linux_build_directory>/arch/riscv/boot/Image \
+ -drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
+ -device virtio-blk-device,drive=hd0 \
+ -append "root=/dev/vda rw console=ttyS0"
+```
diff --git a/roms/opensbi/docs/platform/shakti_cclass.md b/roms/opensbi/docs/platform/shakti_cclass.md
new file mode 100644
index 000000000..05c9b3a4c
--- /dev/null
+++ b/roms/opensbi/docs/platform/shakti_cclass.md
@@ -0,0 +1,33 @@
+Shakti C-class SoC Platform
+===========================
+C-Class is a member of the SHAKTI family of processors from
+Indian Institute of Technology - Madras (IIT-M).
+
+It is an extremely configurable and commercial-grade 5-stage
+in-order core supporting the standard RV64GCSUN ISA extensions.
+
+For more details, refer:
+* https://gitlab.com/shaktiproject/cores/c-class/blob/master/README.md
+* https://c-class.readthedocs.io/en/latest
+* https://shakti.org.in
+
+Platform Options
+----------------
+
+The *Shakti C-class SoC* platform does not have any platform-specific
+options.
+
+Building Shakti C-class Platform
+--------------------------------
+
+**Linux Kernel Payload**
+
+```
+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_FDT_PATH=<shakti.dtb path>
+```
diff --git a/roms/opensbi/docs/platform/sifive_fu540.md b/roms/opensbi/docs/platform/sifive_fu540.md
new file mode 100644
index 000000000..b4d3c6051
--- /dev/null
+++ b/roms/opensbi/docs/platform/sifive_fu540.md
@@ -0,0 +1,195 @@
+SiFive FU540 SoC Platform
+=========================
+The FU540-C000 is the world’s first 4+1 64-bit RISC-V SoC from SiFive.
+The HiFive Unleashed development platform is based on FU540-C000 and capable
+of running Linux.
+
+With QEMU v4.2 or above release, the 'sifive_u' machine can be used to test
+OpenSBI image built for the real hardware as well.
+
+To build platform specific library and firmwares, provide the
+*PLATFORM=sifive/fu540* parameter to the top level `make` command.
+
+Platform Options
+----------------
+
+The *SiFive FU540 SoC* platform does not have any platform-specific
+options.
+
+Building SiFive Fu540 Platform
+------------------------------
+
+In order to boot SMP Linux in U-Boot, Linux v5.1 (or higher) and latest
+U-Boot v2020.01 (or higher) should be used.
+
+**Linux Kernel Payload**
+
+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
+(or higher) should be used to build SiFive FU540 OpenSBI binaries by using
+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_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, 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:
+------------------------------------------------------
+The first stage boot loader ([FSBL]) expects the storage media to have a GPT
+partition table. It tries to look for a partition with following GUID to load
+the next stage boot loader (OpenSBI in this case).
+
+```
+2E54B353-1271-4842-806F-E436D6AF6985
+```
+
+That's why the generated firmware binary in above steps should be copied to
+the partition of the sdcard with above GUID.
+
+```
+dd if=build/platform/sifive/fu540/firmware/fw_payload.bin of=/dev/disk2s1 bs=1024
+```
+
+In my case, it is the first partition is **disk2s1** that has been formatted
+with the above specified GUID.
+
+In case of a brand new sdcard, it should be formatted with below partition
+tables as described here.
+
+```
+sgdisk --clear \
+ --new=1:2048:67583 --change-name=1:bootloader --typecode=1:2E54B353-1271-4842-806F-E436D6AF6985 \
+ --new=2:264192: --change-name=2:root --typecode=2:0FC63DAF-8483-4772-8E79-3D69D8477DE4 \
+ ${DISK}
+```
+
+Booting SiFive Fu540 Platform
+-----------------------------
+
+**Linux Kernel Payload**
+
+As Linux kernel image is embedded in the OpenSBI firmware binary, HiFive
+Unleashed will directly boot into Linux directly after powered on.
+
+**U-Boot Payload**
+
+As U-Boot image is used as payload, HiFive Unleashed will boot into a U-Boot
+prompt. U-Boot tftp boot method can be used to load kernel image in U-Boot
+prompt. Here are the steps do a tftpboot.
+
+1. Set the ip address of the board.
+```
+setenv ipaddr <ipaddr of the board>
+```
+2. Set the tftpboot server IP.
+```
+setenv serverip <ipaddr of the tftp server>
+```
+3. Set the network gateway address.
+```
+setenv gatewayip <ipaddress of the network gateway>
+```
+4. Load the Linux kernel image from the tftp server.
+```
+tftpboot ${kernel_addr_r} <Image path in tftpboot directory>
+```
+5. Load the ramdisk image from the tftp server. This is only required if
+ramdisk is loaded from tftp server. This step is optional, if rootfs is
+already part of the kernel or loaded from an external storage by kernel.
+```
+tftpboot ${ramdisk_addr_r} <ramdisk path in tftpboot directory>
+```
+6. Load the pre-compiled device tree via tftpboot.
+```
+tftpboot ${fdt_addr_r} <hifive-unleashed-a00.dtb path in tftpboot directory>
+```
+7. Set the boot command-line arguments.
+```
+setenv bootargs "root=<root partition> rw console=ttySIF0 earlycon=sbi"
+```
+(Note: root partition should point to
+** /dev/ram ** - If a ramdisk is used
+** root=/dev/mmcblk0pX ** - If a rootfs is already on some other partition
+of sdcard)
+8. Now boot into Linux.
+```
+booti ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}
+or
+(If ramdisk is not loaded from network)
+booti ${kernel_addr_r} - ${fdt_addr_r}
+```
+
+**U-Boot & Linux Kernel as a single payload**
+
+At U-Boot prompt execute the following boot command to boot Linux.
+
+```
+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_FDT_PATH.
+
+This is because QEMU generates a device tree blob on the fly based on the
+command line parameters and it's compatible with the one used in the upstream
+Linux kernel.
+
+When U-Boot v2020.01 (or higher) is used as the payload, as the SiFive FU540
+DTB for the real hardware is embedded in U-Boot binary itself, due to the same
+reason above, we need to switch the U-Boot sifive_fu540_defconfig configuration
+from **CONFIG_OF_SEPARATE** to **CONFIG_OF_PRIOR_STAGE** so that U-Boot uses the
+DTB generated by QEMU, and u-boot.bin should be used as the payload image, like:
+
+```
+make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin
+```
+
+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.
+
+[U-Boot]: https://gitlab.denx.de/u-boot/u-boot/blob/master/doc/board/sifive/fu540.rst
+[FSBL]: https://github.com/sifive/freedom-u540-c000-bootloader
diff --git a/roms/opensbi/docs/platform/spike.md b/roms/opensbi/docs/platform/spike.md
new file mode 100644
index 000000000..79e2eb2b0
--- /dev/null
+++ b/roms/opensbi/docs/platform/spike.md
@@ -0,0 +1,89 @@
+Spike Simulator Platform
+========================
+
+The **Spike** is a RISC-V ISA simulator which implements a functional model
+of one or more RISC-V harts. The **Spike** compatible virtual platform is
+also available on QEMU. In fact, we can use same OpenSBI firmware binaries
+on **Spike** simulator and QEMU Spike machine.
+
+For more details, refer [Spike on GitHub](https://github.com/riscv/riscv-isa-sim)
+
+To build the platform-specific library and firmware images, provide the
+*PLATFORM=generic* parameter to the top level `make` command.
+
+Platform Options
+----------------
+
+The *Spike* platform does not have any platform-specific options.
+
+Execution on Spike Simulator
+----------------------------
+
+**No Payload Case**
+
+Build:
+```
+make PLATFORM=generic
+```
+
+Run:
+```
+spike build/platform/generic/firmware/fw_payload.elf
+```
+
+**Linux Kernel Payload**
+
+Note: We assume that the Linux kernel is compiled using
+*arch/riscv/configs/defconfig*.
+
+Build:
+```
+make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
+```
+
+Run:
+```
+spike --initrd <path_to_cpio_ramdisk> build/platform/generic/firmware/fw_payload.elf
+```
+
+Execution on QEMU RISC-V 64-bit
+-------------------------------
+
+**No Payload Case**
+
+Build:
+```
+make PLATFORM=generic
+```
+
+Run:
+```
+qemu-system-riscv64 -M spike -m 256M -nographic \
+ -bios build/platform/generic/firmware/fw_payload.elf
+```
+
+**Linux Kernel Payload**
+
+Note: We assume that the Linux kernel is compiled using
+*arch/riscv/configs/defconfig*.
+
+Build:
+```
+make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
+```
+
+Run:
+```
+qemu-system-riscv64 -M spike -m 256M -nographic \
+ -bios build/platform/generic/firmware/fw_payload.elf \
+ -initrd <path_to_cpio_ramdisk> \
+ -append "root=/dev/ram rw console=hvc0 earlycon=sbi"
+```
+or
+```
+qemu-system-riscv64 -M spike -m 256M -nographic \
+ -bios build/platform/generic/firmware/fw_jump.elf \
+ -kernel <linux_build_directory>/arch/riscv/boot/Image \
+ -initrd <path_to_cpio_ramdisk> \
+ -append "root=/dev/ram rw console=hvc0 earlycon=sbi"
+```
diff --git a/roms/opensbi/docs/platform/thead-c910.md b/roms/opensbi/docs/platform/thead-c910.md
new file mode 100644
index 000000000..786b47d03
--- /dev/null
+++ b/roms/opensbi/docs/platform/thead-c910.md
@@ -0,0 +1,34 @@
+T-HEAD C910 Processor
+=====================
+C910 is a 12-stage, 3 issues, 8 executions, out-of-order 64-bit RISC-V CPU which
+supports 16 cores, runs with 2.5GHz, and is capable of running Linux.
+
+To build platform specific library and firmwares, provide the
+*PLATFORM=thead/c910* parameter to the top level make command.
+
+Platform Options
+----------------
+
+The *T-HEAD C910* platform does not have any platform-specific options.
+
+Building T-HEAD C910 Platform
+-----------------------------
+
+```
+make PLATFORM=thead/c910
+```
+
+Booting T-HEAD C910 Platform
+----------------------------
+
+**No Payload**
+
+As there's no payload, you may download vmlinux or u-boot to FW_JUMP_ADDR which
+specified in config.mk or compile commands with GDB. And the execution flow will
+turn to vmlinux or u-boot when opensbi ends.
+
+**Linux Kernel Payload**
+
+You can also choose to use Linux kernel as payload by enabling FW_PAYLOAD=y
+along with specifying FW_PAYLOAD_OFFSET. The kernel image will be embedded in
+the OPENSBI firmware binary, T-head will directly boot into Linux after OpenSBI.
diff --git a/roms/opensbi/docs/platform_guide.md b/roms/opensbi/docs/platform_guide.md
new file mode 100644
index 000000000..7920fac2a
--- /dev/null
+++ b/roms/opensbi/docs/platform_guide.md
@@ -0,0 +1,42 @@
+OpenSBI Platform Support Guideline
+==================================
+
+The OpenSBI platform support allows an implementation to define a set of
+platform-specific hooks (hardware manipulation functions) in the form of a
+*struct sbi_platform* data structure instance. This instance is required by
+the platform-independent *libsbi.a* to execute platform-specific operations.
+
+Each of the reference platform supports provided by OpenSBI defines an instance
+of the *struct sbi_platform* data structure. For each supported platform,
+*libplatsbi.a* integrates this instance with *libsbi.a* to create a
+platform-specific OpenSBI static library. This library is installed
+in *<install_directory>/platform/<platform_subdir>/lib/libplatsbi.a*
+
+OpenSBI also provides implementation examples of bootable runtime firmwares for
+the supported platforms. These firmwares are linked against *libplatsbi.a*.
+Firmware binaries are installed in
+*<install_directory>/platform/<platform_subdir>/bin*. These firmwares can be
+used as executable runtime firmwares on the supported platforms as a replacement
+for the legacy *riskv-pk* boot loader (BBL).
+
+A complete doxygen-style documentation of *struct sbi_platform* and related
+APIs is available in the file *include/sbi/sbi_platform.h*.
+
+Adding support for a new platform
+---------------------------------
+
+Support for a new platform named *<xyz>* can be added as follows:
+
+1. Create a directory named *<xyz>* under the *platform/* directory.
+2. Create a platform configuration file named *config.mk* under the
+ *platform/<xyz>/* directory. This configuration file will provide
+ compiler flags, and select firmware options.
+3. Create a *platform/<xyz>/objects.mk* file for listing the
+ platform-specific object files to be compiled.
+4. Create a *platform/<xyz>/platform.c* file providing a *struct sbi_platform*
+ instance.
+
+A platform support code template is available under the *platform/template*
+directory. Copying this directory and its content as a new directory named
+*<xyz>* under the *platform/* directory will create all the files mentioned
+above.
diff --git a/roms/opensbi/docs/platform_requirements.md b/roms/opensbi/docs/platform_requirements.md
new file mode 100644
index 000000000..68dc3935a
--- /dev/null
+++ b/roms/opensbi/docs/platform_requirements.md
@@ -0,0 +1,44 @@
+OpenSBI Platform Requirements
+=============================
+
+The RISC-V platform requirements for OpenSBI can change over time
+with advances in RISC-V specifications and ecosystem.
+
+To handle this, we have two types of RISC-V platform requirements:
+
+1. **Base platform requirements** which apply to all OpenSBI releases
+2. **Release specific platform requirements** which apply to a OpenSBI
+ release and later releases
+
+Currently, we don't have any **Release specific platform requirements**
+but such platform requirements will be added in future.
+
+Base Platform Requirements
+--------------------------
+
+The base RISC-V platform requirements for OpenSBI are as follows:
+
+1. At least rv32ima or rv64ima required on all HARTs
+2. At least one HART should have S-mode support because:
+
+ * SBI calls are meant for RISC-V S-mode (Supervisor mode)
+ * OpenSBI implements SBI calls for S-mode software
+
+3. The MTVEC CSR on all HARTs must support direct mode
+4. The PMP CSRs are optional. If PMP CSRs are not implemented then
+ OpenSBI cannot protect M-mode firmware and secured memory regions
+5. The TIME CSR is optional. If TIME CSR is not implemented in
+ hardware then a 64-bit MMIO counter is required to track time
+ and emulate TIME CSR
+6. Hardware support for injecting M-mode software interrupts on
+ a multi-HART platform
+
+The RISC-V extensions not covered by rv32ima or rv64ima are optional
+for OpenSBI. Although, OpenSBI will detect and handle some of these
+optional RISC-V extensions at runtime.
+
+The optional RISC-V extensions handled by OpenSBI at runtime are:
+
+* D-extension: Double precision floating point
+* F-extension: Single precision floating point
+* H-extension: Hypervisor
diff --git a/roms/opensbi/firmware/external_deps.mk b/roms/opensbi/firmware/external_deps.mk
new file mode 100644
index 000000000..6264005bc
--- /dev/null
+++ b/roms/opensbi/firmware/external_deps.mk
@@ -0,0 +1,14 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2019 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# 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)
diff --git a/roms/opensbi/firmware/fw_base.S b/roms/opensbi/firmware/fw_base.S
new file mode 100644
index 000000000..ab33e1102
--- /dev/null
+++ b/roms/opensbi/firmware/fw_base.S
@@ -0,0 +1,769 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_scratch.h>
+#include <sbi/sbi_trap.h>
+
+#define BOOT_STATUS_RELOCATE_DONE 1
+#define BOOT_STATUS_BOOT_HART_DONE 2
+
+.macro MOV_3R __d0, __s0, __d1, __s1, __d2, __s2
+ add \__d0, \__s0, zero
+ add \__d1, \__s1, zero
+ add \__d2, \__s2, zero
+.endm
+
+.macro MOV_5R __d0, __s0, __d1, __s1, __d2, __s2, __d3, __s3, __d4, __s4
+ add \__d0, \__s0, zero
+ add \__d1, \__s1, zero
+ add \__d2, \__s2, zero
+ add \__d3, \__s3, zero
+ add \__d4, \__s4, zero
+.endm
+
+/*
+ * If __start_reg <= __check_reg and __check_reg < __end_reg then
+ * jump to __pass
+ */
+.macro BRANGE __start_reg, __end_reg, __check_reg, __jump_lable
+ blt \__check_reg, \__start_reg, 999f
+ bge \__check_reg, \__end_reg, 999f
+ j \__jump_lable
+999:
+.endm
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .globl _start
+ .globl _start_warm
+_start:
+ /* Find preferred boot HART id */
+ MOV_3R s0, a0, s1, a1, s2, a2
+ call fw_boot_hart
+ add a6, a0, zero
+ MOV_3R a0, s0, a1, s1, a2, s2
+ li a7, -1
+ beq a6, a7, _try_lottery
+ /* Jump to relocation wait loop if we are not boot hart */
+ bne a0, a6, _wait_relocate_copy_done
+_try_lottery:
+ /* Jump to relocation wait loop if we don't get relocation lottery */
+ la a6, _relocate_lottery
+ li a7, 1
+ amoadd.w a6, a7, (a6)
+ bnez a6, _wait_relocate_copy_done
+
+ /* Save load address */
+ la t0, _load_start
+ la t1, _start
+ REG_S t1, 0(t0)
+
+ /* Relocate if load address != link address */
+_relocate:
+ la t0, _link_start
+ REG_L t0, 0(t0)
+ la t1, _link_end
+ REG_L t1, 0(t1)
+ la t2, _load_start
+ REG_L t2, 0(t2)
+ sub t3, t1, t0
+ add t3, t3, t2
+ beq t0, t2, _relocate_done
+ la t4, _relocate_done
+ sub t4, t4, t2
+ add t4, t4, t0
+ blt t2, t0, _relocate_copy_to_upper
+_relocate_copy_to_lower:
+ ble t1, t2, _relocate_copy_to_lower_loop
+ la t3, _relocate_lottery
+ BRANGE t2, t1, t3, _start_hang
+ la t3, _boot_status
+ BRANGE t2, t1, t3, _start_hang
+ la t3, _relocate
+ la t5, _relocate_done
+ BRANGE t2, t1, t3, _start_hang
+ BRANGE t2, t1, t5, _start_hang
+ BRANGE t3, t5, t2, _start_hang
+_relocate_copy_to_lower_loop:
+ REG_L t3, 0(t2)
+ REG_S t3, 0(t0)
+ add t0, t0, __SIZEOF_POINTER__
+ add t2, t2, __SIZEOF_POINTER__
+ blt t0, t1, _relocate_copy_to_lower_loop
+ jr t4
+_relocate_copy_to_upper:
+ ble t3, t0, _relocate_copy_to_upper_loop
+ la t2, _relocate_lottery
+ BRANGE t0, t3, t2, _start_hang
+ la t2, _boot_status
+ BRANGE t0, t3, t2, _start_hang
+ la t2, _relocate
+ la t5, _relocate_done
+ BRANGE t0, t3, t2, _start_hang
+ BRANGE t0, t3, t5, _start_hang
+ BRANGE t2, t5, t0, _start_hang
+_relocate_copy_to_upper_loop:
+ add t3, t3, -__SIZEOF_POINTER__
+ add t1, t1, -__SIZEOF_POINTER__
+ REG_L t2, 0(t3)
+ REG_S t2, 0(t1)
+ blt t0, t1, _relocate_copy_to_upper_loop
+ jr t4
+_wait_relocate_copy_done:
+ la t0, _start
+ la t1, _link_start
+ REG_L t1, 0(t1)
+ beq t0, t1, _wait_for_boot_hart
+ la t2, _boot_status
+ la t3, _wait_for_boot_hart
+ sub t3, t3, t0
+ add t3, t3, t1
+1:
+ /* waitting for relocate copy done (_boot_status == 1) */
+ li t4, BOOT_STATUS_RELOCATE_DONE
+ REG_L t5, 0(t2)
+ /* Reduce the bus traffic so that boot hart may proceed faster */
+ nop
+ nop
+ nop
+ bgt t4, t5, 1b
+ jr t3
+_relocate_done:
+
+ /*
+ * Mark relocate copy done
+ * Use _boot_status copy relative to the load address
+ */
+ la t0, _boot_status
+ la t1, _link_start
+ REG_L t1, 0(t1)
+ la t2, _load_start
+ REG_L t2, 0(t2)
+ sub t0, t0, t1
+ add t0, t0, t2
+ li t1, BOOT_STATUS_RELOCATE_DONE
+ REG_S t1, 0(t0)
+ fence rw, rw
+
+ /* At this point we are running from link address */
+
+ /* Reset all registers for boot HART */
+ li ra, 0
+ call _reset_regs
+
+ /* Zero-out BSS */
+ la s4, _bss_start
+ la s5, _bss_end
+_bss_zero:
+ REG_S zero, (s4)
+ add s4, s4, __SIZEOF_POINTER__
+ blt s4, s5, _bss_zero
+
+ /* Setup temporary trap handler */
+ la s4, _start_hang
+ csrw CSR_MTVEC, s4
+
+ /* Setup temporary stack */
+ la s4, _fw_end
+ li s5, (SBI_SCRATCH_SIZE * 2)
+ add sp, s4, s5
+
+ /* Allow main firmware to save info */
+ MOV_5R s0, a0, s1, a1, s2, a2, s3, a3, s4, a4
+ call fw_save_info
+ MOV_5R a0, s0, a1, s1, a2, s2, a3, s3, a4, s4
+
+#ifdef FW_FDT_PATH
+ /* Override previous arg1 */
+ la a1, fw_fdt_bin
+#endif
+
+ /*
+ * Initialize platform
+ * Note: The a0 to a4 registers passed to the
+ * firmware are parameters to this function.
+ */
+ MOV_5R s0, a0, s1, a1, s2, a2, s3, a3, s4, a4
+ call fw_platform_init
+ add t0, a0, zero
+ MOV_5R a0, s0, a1, s1, a2, s2, a3, s3, a4, s4
+ add a1, t0, zero
+
+ /* Preload HART details
+ * s7 -> HART Count
+ * s8 -> HART Stack Size
+ */
+ la a4, platform
+#if __riscv_xlen == 64
+ lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
+ lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
+#else
+ lw s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
+ lw s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
+#endif
+
+ /* Setup scratch space for all the HARTs*/
+ la tp, _fw_end
+ mul a5, s7, s8
+ add tp, tp, a5
+ /* Keep a copy of tp */
+ add t3, tp, zero
+ /* Counter */
+ li t2, 1
+ /* hartid 0 is mandated by ISA */
+ li t1, 0
+_scratch_init:
+ add tp, t3, zero
+ mul a5, s8, t1
+ sub tp, tp, a5
+ li a5, SBI_SCRATCH_SIZE
+ sub tp, tp, a5
+
+ /* Initialize scratch space */
+ /* Store fw_start and fw_size in scratch space */
+ la a4, _fw_start
+ la a5, _fw_end
+ mul t0, s7, s8
+ add a5, a5, t0
+ sub a5, a5, a4
+ REG_S a4, SBI_SCRATCH_FW_START_OFFSET(tp)
+ REG_S a5, SBI_SCRATCH_FW_SIZE_OFFSET(tp)
+ /* Store next arg1 in scratch space */
+ MOV_3R s0, a0, s1, a1, s2, a2
+ call fw_next_arg1
+ REG_S a0, SBI_SCRATCH_NEXT_ARG1_OFFSET(tp)
+ MOV_3R a0, s0, a1, s1, a2, s2
+ /* Store next address in scratch space */
+ MOV_3R s0, a0, s1, a1, s2, a2
+ call fw_next_addr
+ REG_S a0, SBI_SCRATCH_NEXT_ADDR_OFFSET(tp)
+ MOV_3R a0, s0, a1, s1, a2, s2
+ /* Store next mode in scratch space */
+ MOV_3R s0, a0, s1, a1, s2, a2
+ call fw_next_mode
+ REG_S a0, SBI_SCRATCH_NEXT_MODE_OFFSET(tp)
+ MOV_3R a0, s0, a1, s1, a2, s2
+ /* Store warm_boot address in scratch space */
+ la a4, _start_warm
+ REG_S a4, SBI_SCRATCH_WARMBOOT_ADDR_OFFSET(tp)
+ /* Store platform address in scratch space */
+ la a4, platform
+ REG_S a4, SBI_SCRATCH_PLATFORM_ADDR_OFFSET(tp)
+ /* Store hartid-to-scratch function address in scratch space */
+ la a4, _hartid_to_scratch
+ 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 */
+ MOV_3R s0, a0, s1, a1, s2, a2
+#ifdef FW_OPTIONS
+ li a0, FW_OPTIONS
+#else
+ call fw_options
+#endif
+ REG_S a0, SBI_SCRATCH_OPTIONS_OFFSET(tp)
+ MOV_3R a0, s0, a1, s1, a2, s2
+ /* Move to next scratch space */
+ add t1, t1, t2
+ blt t1, s7, _scratch_init
+
+ /*
+ * Relocate Flatened Device Tree (FDT)
+ * source FDT address = previous arg1
+ * destination FDT address = next arg1
+ *
+ * Note: We will preserve a0 and a1 passed by
+ * previous booting stage.
+ */
+ beqz a1, _fdt_reloc_done
+ /* Mask values in a3 and a4 */
+ li a3, ~(__SIZEOF_POINTER__ - 1)
+ li a4, 0xff
+ /* t1 = destination FDT start address */
+ MOV_3R s0, a0, s1, a1, s2, a2
+ call fw_next_arg1
+ add t1, a0, zero
+ MOV_3R a0, s0, a1, s1, a2, s2
+ beqz t1, _fdt_reloc_done
+ beq t1, a1, _fdt_reloc_done
+ and t1, t1, a3
+ /* t0 = source FDT start address */
+ add t0, a1, zero
+ and t0, t0, a3
+ /* t2 = source FDT size in big-endian */
+#if __riscv_xlen == 64
+ lwu t2, 4(t0)
+#else
+ lw t2, 4(t0)
+#endif
+ /* t3 = bit[15:8] of FDT size */
+ add t3, t2, zero
+ srli t3, t3, 16
+ and t3, t3, a4
+ slli t3, t3, 8
+ /* t4 = bit[23:16] of FDT size */
+ add t4, t2, zero
+ srli t4, t4, 8
+ and t4, t4, a4
+ slli t4, t4, 16
+ /* t5 = bit[31:24] of FDT size */
+ add t5, t2, zero
+ and t5, t5, a4
+ slli t5, t5, 24
+ /* t2 = bit[7:0] of FDT size */
+ srli t2, t2, 24
+ and t2, t2, a4
+ /* t2 = FDT size in little-endian */
+ or t2, t2, t3
+ or t2, t2, t4
+ or t2, t2, t5
+ /* t2 = destination FDT end address */
+ add t2, t1, t2
+ /* FDT copy loop */
+ ble t2, t1, _fdt_reloc_done
+_fdt_reloc_again:
+ REG_L t3, 0(t0)
+ REG_S t3, 0(t1)
+ add t0, t0, __SIZEOF_POINTER__
+ add t1, t1, __SIZEOF_POINTER__
+ blt t1, t2, _fdt_reloc_again
+_fdt_reloc_done:
+
+ /* mark boot hart done */
+ li t0, BOOT_STATUS_BOOT_HART_DONE
+ la t1, _boot_status
+ REG_S t0, 0(t1)
+ fence rw, rw
+ j _start_warm
+
+ /* waiting for boot hart to be done (_boot_status == 2) */
+_wait_for_boot_hart:
+ li t0, BOOT_STATUS_BOOT_HART_DONE
+ la t1, _boot_status
+ REG_L t1, 0(t1)
+ /* Reduce the bus traffic so that boot hart may proceed faster */
+ nop
+ nop
+ nop
+ bne t0, t1, _wait_for_boot_hart
+
+_start_warm:
+ /* Reset all registers for non-boot HARTs */
+ li ra, 0
+ call _reset_regs
+
+ /* Disable and clear all interrupts */
+ csrw CSR_MIE, zero
+ csrw CSR_MIP, zero
+
+ /* Find HART count and HART stack size */
+ la a4, platform
+#if __riscv_xlen == 64
+ lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
+ lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
+#else
+ lw s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
+ lw s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
+#endif
+ REG_L s9, SBI_PLATFORM_HART_INDEX2ID_OFFSET(a4)
+
+ /* Find HART id */
+ csrr s6, CSR_MHARTID
+
+ /* Find HART index */
+ beqz s9, 3f
+ li a4, 0
+1:
+#if __riscv_xlen == 64
+ lwu a5, (s9)
+#else
+ lw a5, (s9)
+#endif
+ beq a5, s6, 2f
+ add s9, s9, 4
+ add a4, a4, 1
+ blt a4, s7, 1b
+ li a4, -1
+2: add s6, a4, zero
+3: bge s6, s7, _start_hang
+
+ /* Find the scratch space based on HART index */
+ la tp, _fw_end
+ mul a5, s7, s8
+ add tp, tp, a5
+ mul a5, s8, s6
+ sub tp, tp, a5
+ li a5, SBI_SCRATCH_SIZE
+ sub tp, tp, a5
+
+ /* update the mscratch */
+ csrw CSR_MSCRATCH, tp
+
+ /* Setup stack */
+ add sp, tp, zero
+
+ /* 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
+
+ /* We don't expect to reach here hence just hang */
+ j _start_hang
+
+ .align 3
+_relocate_lottery:
+ RISCV_PTR 0
+_boot_status:
+ RISCV_PTR 0
+_load_start:
+ RISCV_PTR _fw_start
+_link_start:
+ RISCV_PTR _fw_start
+_link_end:
+ RISCV_PTR _fw_reloc_end
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .globl _hartid_to_scratch
+_hartid_to_scratch:
+ /*
+ * a0 -> HART ID (passed by caller)
+ * a1 -> HART Index (passed by caller)
+ * t0 -> HART Stack Size
+ * t1 -> HART Stack End
+ * t2 -> Temporary
+ */
+ la t2, platform
+#if __riscv_xlen == 64
+ lwu t0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(t2)
+ lwu t2, SBI_PLATFORM_HART_COUNT_OFFSET(t2)
+#else
+ lw t0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(t2)
+ lw t2, SBI_PLATFORM_HART_COUNT_OFFSET(t2)
+#endif
+ sub t2, t2, a1
+ mul t2, t2, t0
+ la t1, _fw_end
+ add t1, t1, t2
+ li t2, SBI_SCRATCH_SIZE
+ sub a0, t1, t2
+ ret
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .globl _start_hang
+_start_hang:
+ wfi
+ j _start_hang
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .globl fw_platform_init
+ .weak fw_platform_init
+fw_platform_init:
+ add a0, a1, zero
+ ret
+
+.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)
+
+ /*
+ * 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
+ 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
+
+ /* Save original SP on exception stack */
+ REG_S sp, (SBI_TRAP_REGS_OFFSET(sp) - SBI_TRAP_REGS_SIZE)(t0)
+
+ /* 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)
+
+ /* Save T0 on stack */
+ REG_S t0, SBI_TRAP_REGS_OFFSET(t0)(sp)
+
+ /* 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)
+ .if \have_mstatush
+ csrr t0, CSR_MSTATUSH
+ REG_S t0, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
+ .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)
+ REG_S gp, SBI_TRAP_REGS_OFFSET(gp)(sp)
+ REG_S tp, SBI_TRAP_REGS_OFFSET(tp)(sp)
+ REG_S t1, SBI_TRAP_REGS_OFFSET(t1)(sp)
+ REG_S t2, SBI_TRAP_REGS_OFFSET(t2)(sp)
+ REG_S s0, SBI_TRAP_REGS_OFFSET(s0)(sp)
+ REG_S s1, SBI_TRAP_REGS_OFFSET(s1)(sp)
+ REG_S a0, SBI_TRAP_REGS_OFFSET(a0)(sp)
+ REG_S a1, SBI_TRAP_REGS_OFFSET(a1)(sp)
+ REG_S a2, SBI_TRAP_REGS_OFFSET(a2)(sp)
+ REG_S a3, SBI_TRAP_REGS_OFFSET(a3)(sp)
+ REG_S a4, SBI_TRAP_REGS_OFFSET(a4)(sp)
+ REG_S a5, SBI_TRAP_REGS_OFFSET(a5)(sp)
+ REG_S a6, SBI_TRAP_REGS_OFFSET(a6)(sp)
+ REG_S a7, SBI_TRAP_REGS_OFFSET(a7)(sp)
+ REG_S s2, SBI_TRAP_REGS_OFFSET(s2)(sp)
+ REG_S s3, SBI_TRAP_REGS_OFFSET(s3)(sp)
+ REG_S s4, SBI_TRAP_REGS_OFFSET(s4)(sp)
+ REG_S s5, SBI_TRAP_REGS_OFFSET(s5)(sp)
+ REG_S s6, SBI_TRAP_REGS_OFFSET(s6)(sp)
+ REG_S s7, SBI_TRAP_REGS_OFFSET(s7)(sp)
+ REG_S s8, SBI_TRAP_REGS_OFFSET(s8)(sp)
+ REG_S s9, SBI_TRAP_REGS_OFFSET(s9)(sp)
+ REG_S s10, SBI_TRAP_REGS_OFFSET(s10)(sp)
+ REG_S s11, SBI_TRAP_REGS_OFFSET(s11)(sp)
+ REG_S t3, SBI_TRAP_REGS_OFFSET(t3)(sp)
+ 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)
+ REG_L tp, SBI_TRAP_REGS_OFFSET(tp)(sp)
+ REG_L t1, SBI_TRAP_REGS_OFFSET(t1)(sp)
+ REG_L t2, SBI_TRAP_REGS_OFFSET(t2)(sp)
+ REG_L s0, SBI_TRAP_REGS_OFFSET(s0)(sp)
+ REG_L s1, SBI_TRAP_REGS_OFFSET(s1)(sp)
+ REG_L a0, SBI_TRAP_REGS_OFFSET(a0)(sp)
+ REG_L a1, SBI_TRAP_REGS_OFFSET(a1)(sp)
+ REG_L a2, SBI_TRAP_REGS_OFFSET(a2)(sp)
+ REG_L a3, SBI_TRAP_REGS_OFFSET(a3)(sp)
+ REG_L a4, SBI_TRAP_REGS_OFFSET(a4)(sp)
+ REG_L a5, SBI_TRAP_REGS_OFFSET(a5)(sp)
+ REG_L a6, SBI_TRAP_REGS_OFFSET(a6)(sp)
+ REG_L a7, SBI_TRAP_REGS_OFFSET(a7)(sp)
+ REG_L s2, SBI_TRAP_REGS_OFFSET(s2)(sp)
+ REG_L s3, SBI_TRAP_REGS_OFFSET(s3)(sp)
+ REG_L s4, SBI_TRAP_REGS_OFFSET(s4)(sp)
+ REG_L s5, SBI_TRAP_REGS_OFFSET(s5)(sp)
+ REG_L s6, SBI_TRAP_REGS_OFFSET(s6)(sp)
+ REG_L s7, SBI_TRAP_REGS_OFFSET(s7)(sp)
+ REG_L s8, SBI_TRAP_REGS_OFFSET(s8)(sp)
+ REG_L s9, SBI_TRAP_REGS_OFFSET(s9)(sp)
+ REG_L s10, SBI_TRAP_REGS_OFFSET(s10)(sp)
+ REG_L s11, SBI_TRAP_REGS_OFFSET(s11)(sp)
+ REG_L t3, SBI_TRAP_REGS_OFFSET(t3)(sp)
+ REG_L t4, SBI_TRAP_REGS_OFFSET(t4)(sp)
+ REG_L t5, SBI_TRAP_REGS_OFFSET(t5)(sp)
+ REG_L t6, SBI_TRAP_REGS_OFFSET(t6)(sp)
+.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 \have_mstatush
+ REG_L t0, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
+ csrw CSR_MSTATUSH, t0
+ .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
+_reset_regs:
+
+ /* flush the instruction cache */
+ fence.i
+ /* Reset all registers except ra, a0, a1 and a2 */
+ li sp, 0
+ li gp, 0
+ li tp, 0
+ li t0, 0
+ li t1, 0
+ li t2, 0
+ li s0, 0
+ li s1, 0
+ li a3, 0
+ li a4, 0
+ li a5, 0
+ li a6, 0
+ li a7, 0
+ li s2, 0
+ li s3, 0
+ li s4, 0
+ li s5, 0
+ li s6, 0
+ li s7, 0
+ li s8, 0
+ li s9, 0
+ li s10, 0
+ li s11, 0
+ li t3, 0
+ li t4, 0
+ li t5, 0
+ li t6, 0
+ 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
diff --git a/roms/opensbi/firmware/fw_base.ldS b/roms/opensbi/firmware/fw_base.ldS
new file mode 100644
index 000000000..0ac75f200
--- /dev/null
+++ b/roms/opensbi/firmware/fw_base.ldS
@@ -0,0 +1,81 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+ . = FW_TEXT_START;
+
+ PROVIDE(_fw_start = .);
+
+ . = ALIGN(0x1000); /* Need this to create proper sections */
+
+ /* Beginning of the code section */
+
+ .text :
+ {
+ PROVIDE(_text_start = .);
+ *(.entry)
+ *(.text)
+ . = ALIGN(8);
+ PROVIDE(_text_end = .);
+ }
+
+ . = ALIGN(0x1000); /* Ensure next section is page aligned */
+
+ /* End of the code sections */
+
+ /* Beginning of the read-only data sections */
+
+ . = ALIGN(0x1000); /* Ensure next section is page aligned */
+
+ .rodata :
+ {
+ PROVIDE(_rodata_start = .);
+ *(.rodata .rodata.*)
+ . = ALIGN(8);
+ PROVIDE(_rodata_end = .);
+ }
+
+ /* End of the read-only data sections */
+
+ /* Beginning of the read-write data sections */
+
+ . = ALIGN(0x1000); /* Ensure next section is page aligned */
+
+ .data :
+ {
+ PROVIDE(_data_start = .);
+
+ *(.sdata)
+ *(.sdata.*)
+ *(.data)
+ *(.data.*)
+ *(.readmostly.data)
+ *(*.data)
+ . = ALIGN(8);
+
+ PROVIDE(_data_end = .);
+ }
+
+ . = ALIGN(0x1000); /* Ensure next section is page aligned */
+
+ .bss :
+ {
+ PROVIDE(_bss_start = .);
+ *(.sbss)
+ *(.sbss.*)
+ *(.bss)
+ *(.bss.*)
+ . = ALIGN(8);
+ PROVIDE(_bss_end = .);
+ }
+
+ /* End of the read-write data sections */
+
+ . = ALIGN(0x1000); /* Need this to create proper sections */
+
+ PROVIDE(_fw_end = .);
diff --git a/roms/opensbi/firmware/fw_dynamic.S b/roms/opensbi/firmware/fw_dynamic.S
new file mode 100644
index 000000000..8b56947af
--- /dev/null
+++ b/roms/opensbi/firmware/fw_dynamic.S
@@ -0,0 +1,151 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/fw_dynamic.h>
+
+#include "fw_base.S"
+
+ .section .entry, "ax", %progbits
+ .align 3
+_bad_dynamic_info:
+ wfi
+ j _bad_dynamic_info
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .global fw_boot_hart
+ /*
+ * This function is called very early even before
+ * fw_save_info() is called.
+ * We can only use a0, a1, and a2 registers here.
+ * The boot HART id should be returned in 'a0'.
+ */
+fw_boot_hart:
+ /* Sanity checks */
+ li a1, FW_DYNAMIC_INFO_MAGIC_VALUE
+ REG_L a0, FW_DYNAMIC_INFO_MAGIC_OFFSET(a2)
+ bne a0, a1, _bad_dynamic_info
+ li a1, FW_DYNAMIC_INFO_VERSION_MAX
+ REG_L a0, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
+ bgt a0, a1, _bad_dynamic_info
+
+ /* Read boot HART id */
+ li a1, 0x2
+ blt a0, a1, 2f
+ REG_L a0, FW_DYNAMIC_INFO_BOOT_HART_OFFSET(a2)
+ ret
+2: li a0, -1
+ ret
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .global fw_save_info
+ /*
+ * We can only use a0, a1, a2, a3, and a4 registers here.
+ * The a0, a1, and a2 registers will be same as passed by
+ * previous booting stage.
+ * Nothing to be returned here.
+ */
+fw_save_info:
+ /* Save next arg1 in 'a1' */
+ la a4, _dynamic_next_arg1
+ REG_S a1, (a4)
+
+ /* Sanity checks */
+ li a4, FW_DYNAMIC_INFO_MAGIC_VALUE
+ REG_L a3, FW_DYNAMIC_INFO_MAGIC_OFFSET(a2)
+ bne a3, a4, _bad_dynamic_info
+ li a4, FW_DYNAMIC_INFO_VERSION_MAX
+ REG_L a3, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
+ bgt a3, a4, _bad_dynamic_info
+
+ /* Save version == 0x1 fields */
+ la a4, _dynamic_next_addr
+ REG_L a3, FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET(a2)
+ REG_S a3, (a4)
+ la a4, _dynamic_next_mode
+ REG_L a3, FW_DYNAMIC_INFO_NEXT_MODE_OFFSET(a2)
+ REG_S a3, (a4)
+ la a4, _dynamic_options
+ REG_L a3, FW_DYNAMIC_INFO_OPTIONS_OFFSET(a2)
+ REG_S a3, (a4)
+
+ /* Save version == 0x2 fields */
+ li a4, 0x2
+ REG_L a3, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
+ blt a3, a4, 2f
+ la a4, _dynamic_boot_hart
+ REG_L a3, FW_DYNAMIC_INFO_BOOT_HART_OFFSET(a2)
+ REG_S a3, (a4)
+2:
+ ret
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .global fw_next_arg1
+ /*
+ * We can only use a0, a1, and a2 registers here.
+ * The a0, a1, and a2 registers will be same as passed by
+ * previous booting stage.
+ * The next arg1 should be returned in 'a0'.
+ */
+fw_next_arg1:
+ la a0, _dynamic_next_arg1
+ REG_L a0, (a0)
+ ret
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .global fw_next_addr
+ /*
+ * We can only use a0, a1, and a2 registers here.
+ * The next address should be returned in 'a0'.
+ */
+fw_next_addr:
+ la a0, _dynamic_next_addr
+ REG_L a0, (a0)
+ ret
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .global fw_next_mode
+ /*
+ * We can only use a0, a1, and a2 registers here.
+ * The next address should be returned in 'a0'
+ */
+fw_next_mode:
+ la a0, _dynamic_next_mode
+ REG_L a0, (a0)
+ ret
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .global fw_options
+ /*
+ * We can only use a0, a1, and a2 registers here.
+ * The 'a4' register will have default options.
+ * The next address should be returned in 'a0'.
+ */
+fw_options:
+ la a0, _dynamic_options
+ REG_L a0, (a0)
+ ret
+
+ .section .entry, "ax", %progbits
+ .align 3
+_dynamic_next_arg1:
+ RISCV_PTR 0x0
+_dynamic_next_addr:
+ RISCV_PTR 0x0
+_dynamic_next_mode:
+ RISCV_PTR PRV_S
+_dynamic_options:
+ RISCV_PTR 0x0
+_dynamic_boot_hart:
+ RISCV_PTR -1
diff --git a/roms/opensbi/firmware/fw_dynamic.elf.ldS b/roms/opensbi/firmware/fw_dynamic.elf.ldS
new file mode 100644
index 000000000..d1e2ea89e
--- /dev/null
+++ b/roms/opensbi/firmware/fw_dynamic.elf.ldS
@@ -0,0 +1,18 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+OUTPUT_ARCH(riscv)
+ENTRY(_start)
+
+SECTIONS
+{
+ #include "fw_base.ldS"
+
+ PROVIDE(_fw_reloc_end = .);
+}
diff --git a/roms/opensbi/firmware/fw_jump.S b/roms/opensbi/firmware/fw_jump.S
new file mode 100644
index 000000000..8553f8c7f
--- /dev/null
+++ b/roms/opensbi/firmware/fw_jump.S
@@ -0,0 +1,96 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include "fw_base.S"
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .global fw_boot_hart
+ /*
+ * This function is called very early even before
+ * fw_save_info() is called.
+ * We can only use a0, a1, and a2 registers here.
+ * The boot HART id should be returned in 'a0'.
+ */
+fw_boot_hart:
+ li a0, -1
+ ret
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .global fw_save_info
+ /*
+ * We can only use a0, a1, a2, a3, and a4 registers here.
+ * The a0, a1, and a2 registers will be same as passed by
+ * previous booting stage.
+ * Nothing to be returned here.
+ */
+fw_save_info:
+ ret
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .global fw_next_arg1
+ /*
+ * We can only use a0, a1, and a2 registers here.
+ * The a0, a1, and a2 registers will be same as passed by
+ * previous booting stage.
+ * The next arg1 should be returned in 'a0'.
+ */
+fw_next_arg1:
+#ifdef FW_JUMP_FDT_ADDR
+ li a0, FW_JUMP_FDT_ADDR
+#else
+ add a0, a1, zero
+#endif
+ ret
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .global fw_next_addr
+ /*
+ * We can only use a0, a1, and a2 registers here.
+ * The next address should be returned in 'a0'.
+ */
+fw_next_addr:
+ la a0, _jump_addr
+ REG_L a0, (a0)
+ ret
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .global fw_next_mode
+ /*
+ * We can only use a0, a1, and a2 registers here.
+ * The next address should be returned in 'a0'
+ */
+fw_next_mode:
+ li a0, PRV_S
+ ret
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .global fw_options
+ /*
+ * We can only use a0, a1, and a2 registers here.
+ * The 'a4' register will have default options.
+ * The next address should be returned in 'a0'.
+ */
+fw_options:
+ add a0, zero, zero
+ ret
+
+#ifndef FW_JUMP_ADDR
+#error "Must define FW_JUMP_ADDR"
+#endif
+
+ .section .entry, "ax", %progbits
+ .align 3
+_jump_addr:
+ RISCV_PTR FW_JUMP_ADDR
diff --git a/roms/opensbi/firmware/fw_jump.elf.ldS b/roms/opensbi/firmware/fw_jump.elf.ldS
new file mode 100644
index 000000000..d1e2ea89e
--- /dev/null
+++ b/roms/opensbi/firmware/fw_jump.elf.ldS
@@ -0,0 +1,18 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+OUTPUT_ARCH(riscv)
+ENTRY(_start)
+
+SECTIONS
+{
+ #include "fw_base.ldS"
+
+ PROVIDE(_fw_reloc_end = .);
+}
diff --git a/roms/opensbi/firmware/fw_payload.S b/roms/opensbi/firmware/fw_payload.S
new file mode 100644
index 000000000..1ef121e28
--- /dev/null
+++ b/roms/opensbi/firmware/fw_payload.S
@@ -0,0 +1,97 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include "fw_base.S"
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .global fw_boot_hart
+ /*
+ * This function is called very early even before
+ * fw_save_info() is called.
+ * We can only use a0, a1, and a2 registers here.
+ * The boot HART id should be returned in 'a0'.
+ */
+fw_boot_hart:
+ li a0, -1
+ ret
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .global fw_save_info
+ /*
+ * We can only use a0, a1, a2, a3, and a4 registers here.
+ * The a0, a1, and a2 registers will be same as passed by
+ * previous booting stage.
+ * Nothing to be returned here.
+ */
+fw_save_info:
+ ret
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .global fw_next_arg1
+ /*
+ * We can only use a0, a1, and a2 registers here.
+ * The a0, a1, and a2 registers will be same as passed by
+ * previous booting stage.
+ * The next arg1 should be returned in 'a0'.
+ */
+fw_next_arg1:
+#ifdef FW_PAYLOAD_FDT_ADDR
+ li a0, FW_PAYLOAD_FDT_ADDR
+#else
+ add a0, a1, zero
+#endif
+ ret
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .global fw_next_addr
+ /*
+ * We can only use a0, a1, and a2 registers here.
+ * The next address should be returned in 'a0'.
+ */
+fw_next_addr:
+ la a0, payload_bin
+ ret
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .global fw_next_mode
+ /*
+ * We can only use a0, a1, and a2 registers here.
+ * The next address should be returned in 'a0'.
+ */
+fw_next_mode:
+ li a0, PRV_S
+ ret
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .global fw_options
+ /*
+ * We can only use a0, a1, and a2 registers here.
+ * The 'a4' register will have default options.
+ * The next address should be returned in 'a0'.
+ */
+fw_options:
+ add a0, zero, zero
+ ret
+
+ .section .payload, "ax", %progbits
+ .align 4
+ .globl payload_bin
+payload_bin:
+#ifndef FW_PAYLOAD_PATH
+ wfi
+ j payload_bin
+#else
+ .incbin FW_PAYLOAD_PATH
+#endif
diff --git a/roms/opensbi/firmware/fw_payload.elf.ldS b/roms/opensbi/firmware/fw_payload.elf.ldS
new file mode 100644
index 000000000..f1a544b80
--- /dev/null
+++ b/roms/opensbi/firmware/fw_payload.elf.ldS
@@ -0,0 +1,32 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+OUTPUT_ARCH(riscv)
+ENTRY(_start)
+
+SECTIONS
+{
+ #include "fw_base.ldS"
+
+#ifdef FW_PAYLOAD_OFFSET
+ . = FW_TEXT_START + FW_PAYLOAD_OFFSET;
+#else
+ . = ALIGN(FW_PAYLOAD_ALIGN);
+#endif
+
+ .payload :
+ {
+ PROVIDE(_payload_start = .);
+ *(.payload)
+ . = ALIGN(8);
+ PROVIDE(_payload_end = .);
+ }
+
+ PROVIDE(_fw_reloc_end = .);
+}
diff --git a/roms/opensbi/firmware/objects.mk b/roms/opensbi/firmware/objects.mk
new file mode 100644
index 000000000..b2ace7512
--- /dev/null
+++ b/roms/opensbi/firmware/objects.mk
@@ -0,0 +1,57 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2019 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+
+firmware-genflags-y =
+firmware-cppflags-y +=
+firmware-cflags-y +=
+firmware-asflags-y +=
+firmware-ldflags-y +=
+
+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
+ifdef FW_JUMP_ADDR
+firmware-genflags-$(FW_JUMP) += -DFW_JUMP_ADDR=$(FW_JUMP_ADDR)
+endif
+ifdef FW_JUMP_FDT_ADDR
+firmware-genflags-$(FW_JUMP) += -DFW_JUMP_FDT_ADDR=$(FW_JUMP_FDT_ADDR)
+endif
+
+firmware-bins-$(FW_PAYLOAD) += fw_payload.bin
+ifdef FW_PAYLOAD_PATH
+FW_PAYLOAD_PATH_FINAL=$(FW_PAYLOAD_PATH)
+else
+FW_PAYLOAD_PATH_FINAL=$(platform_build_dir)/firmware/payloads/test.bin
+endif
+firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_PATH=\"$(FW_PAYLOAD_PATH_FINAL)\"
+ifdef FW_PAYLOAD_OFFSET
+firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_OFFSET=$(FW_PAYLOAD_OFFSET)
+endif
+ifdef FW_PAYLOAD_ALIGN
+firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_ALIGN=$(FW_PAYLOAD_ALIGN)
+endif
+
+ifdef FW_PAYLOAD_FDT_ADDR
+firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_FDT_ADDR=$(FW_PAYLOAD_FDT_ADDR)
+endif
+
+ifdef FW_OPTIONS
+firmware-genflags-y += -DFW_OPTIONS=$(FW_OPTIONS)
+endif
diff --git a/roms/opensbi/firmware/payloads/objects.mk b/roms/opensbi/firmware/payloads/objects.mk
new file mode 100644
index 000000000..21e0185a8
--- /dev/null
+++ b/roms/opensbi/firmware/payloads/objects.mk
@@ -0,0 +1,19 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2019 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+
+firmware-bins-$(FW_PAYLOAD) += payloads/test.bin
+
+test-y += test_head.o
+test-y += test_main.o
+
+%/test.o: $(foreach obj,$(test-y),%/$(obj))
+ $(call merge_objs,$@,$^)
+
+%/test.dep: $(foreach dep,$(test-y:.o=.dep),%/$(dep))
+ $(call merge_deps,$@,$^)
diff --git a/roms/opensbi/firmware/payloads/test.elf.ldS b/roms/opensbi/firmware/payloads/test.elf.ldS
new file mode 100644
index 000000000..f3f3242ab
--- /dev/null
+++ b/roms/opensbi/firmware/payloads/test.elf.ldS
@@ -0,0 +1,87 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+OUTPUT_ARCH(riscv)
+ENTRY(_start)
+
+SECTIONS
+{
+#ifdef FW_PAYLOAD_OFFSET
+ . = FW_TEXT_START + FW_PAYLOAD_OFFSET;
+#else
+ . = ALIGN(FW_PAYLOAD_ALIGN);
+#endif
+
+ PROVIDE(_payload_start = .);
+
+ . = ALIGN(0x1000); /* Need this to create proper sections */
+
+ /* Beginning of the code section */
+
+ .text :
+ {
+ PROVIDE(_text_start = .);
+ *(.entry)
+ *(.text)
+ . = ALIGN(8);
+ PROVIDE(_text_end = .);
+ }
+
+ . = ALIGN(0x1000); /* Ensure next section is page aligned */
+
+ /* End of the code sections */
+
+ /* Beginning of the read-only data sections */
+
+ . = ALIGN(0x1000); /* Ensure next section is page aligned */
+
+ .rodata :
+ {
+ PROVIDE(_rodata_start = .);
+ *(.rodata .rodata.*)
+ . = ALIGN(8);
+ PROVIDE(_rodata_end = .);
+ }
+
+ /* End of the read-only data sections */
+
+ /* Beginning of the read-write data sections */
+
+ . = ALIGN(0x1000); /* Ensure next section is page aligned */
+
+ .data :
+ {
+ PROVIDE(_data_start = .);
+
+ *(.data)
+ *(.data.*)
+ *(.readmostly.data)
+ *(*.data)
+ . = ALIGN(8);
+
+ PROVIDE(_data_end = .);
+ }
+
+ . = ALIGN(0x1000); /* Ensure next section is page aligned */
+
+ .bss :
+ {
+ PROVIDE(_bss_start = .);
+ *(.bss)
+ *(.bss.*)
+ . = ALIGN(8);
+ PROVIDE(_bss_end = .);
+ }
+
+ /* End of the read-write data sections */
+
+ . = ALIGN(0x1000); /* Need this to create proper sections */
+
+ PROVIDE(_payload_end = .);
+}
diff --git a/roms/opensbi/firmware/payloads/test_head.S b/roms/opensbi/firmware/payloads/test_head.S
new file mode 100644
index 000000000..840013e4e
--- /dev/null
+++ b/roms/opensbi/firmware/payloads/test_head.S
@@ -0,0 +1,88 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/riscv_encoding.h>
+#define __ASM_STR(x) x
+
+#if __riscv_xlen == 64
+#define __REG_SEL(a, b) __ASM_STR(a)
+#define RISCV_PTR .dword
+#elif __riscv_xlen == 32
+#define __REG_SEL(a, b) __ASM_STR(b)
+#define RISCV_PTR .word
+#else
+#error "Unexpected __riscv_xlen"
+#endif
+
+#define REG_L __REG_SEL(ld, lw)
+#define REG_S __REG_SEL(sd, sw)
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .globl _start
+_start:
+ /* Pick one hart to run the main boot sequence */
+ la a3, _hart_lottery
+ li a2, 1
+ amoadd.w a3, a2, (a3)
+ bnez a3, _start_hang
+
+ /* Save a0 and a1 */
+ la a3, _boot_a0
+ REG_S a0, 0(a3)
+ la a3, _boot_a1
+ REG_S a1, 0(a3)
+
+ /* Zero-out BSS */
+ la a4, _bss_start
+ la a5, _bss_end
+_bss_zero:
+ REG_S zero, (a4)
+ add a4, a4, __SIZEOF_POINTER__
+ blt a4, a5, _bss_zero
+
+_start_warm:
+ /* Disable and clear all interrupts */
+ csrw CSR_SIE, zero
+ csrw CSR_SIP, zero
+
+ /* Setup exception vectors */
+ la a3, _start_hang
+ csrw CSR_STVEC, a3
+
+ /* Setup stack */
+ la a3, _payload_end
+ li a4, 0x2000
+ add sp, a3, a4
+
+ /* Jump to C main */
+ la a3, _boot_a0
+ REG_L a0, 0(a3)
+ la a3, _boot_a1
+ REG_L a1, 0(a3)
+ call test_main
+
+ /* We don't expect to reach here hence just hang */
+ j _start_hang
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .globl _start_hang
+_start_hang:
+ wfi
+ j _start_hang
+
+ .section .entry, "ax", %progbits
+ .align 3
+_hart_lottery:
+ RISCV_PTR 0
+_boot_a0:
+ RISCV_PTR 0
+_boot_a1:
+ RISCV_PTR 0
diff --git a/roms/opensbi/firmware/payloads/test_main.c b/roms/opensbi/firmware/payloads/test_main.c
new file mode 100644
index 000000000..0d6593023
--- /dev/null
+++ b/roms/opensbi/firmware/payloads/test_main.c
@@ -0,0 +1,48 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/sbi_ecall_interface.h>
+
+#define SBI_ECALL(__num, __a0, __a1, __a2) \
+ ({ \
+ register unsigned long a0 asm("a0") = (unsigned long)(__a0); \
+ register unsigned long a1 asm("a1") = (unsigned long)(__a1); \
+ register unsigned long a2 asm("a2") = (unsigned long)(__a2); \
+ register unsigned long a7 asm("a7") = (unsigned long)(__num); \
+ asm volatile("ecall" \
+ : "+r"(a0) \
+ : "r"(a1), "r"(a2), "r"(a7) \
+ : "memory"); \
+ a0; \
+ })
+
+#define SBI_ECALL_0(__num) SBI_ECALL(__num, 0, 0, 0)
+#define SBI_ECALL_1(__num, __a0) SBI_ECALL(__num, __a0, 0, 0)
+#define SBI_ECALL_2(__num, __a0, __a1) SBI_ECALL(__num, __a0, __a1, 0)
+
+#define sbi_ecall_console_putc(c) SBI_ECALL_1(SBI_EXT_0_1_CONSOLE_PUTCHAR, (c))
+
+static inline void sbi_ecall_console_puts(const char *str)
+{
+ while (str && *str)
+ sbi_ecall_console_putc(*str++);
+}
+
+#define wfi() \
+ do { \
+ __asm__ __volatile__("wfi" ::: "memory"); \
+ } while (0)
+
+void test_main(unsigned long a0, unsigned long a1)
+{
+ sbi_ecall_console_puts("\nTest payload running\n");
+
+ while (1)
+ wfi();
+}
diff --git a/roms/opensbi/include/sbi/fw_dynamic.h b/roms/opensbi/include/sbi/fw_dynamic.h
new file mode 100644
index 000000000..3c088311f
--- /dev/null
+++ b/roms/opensbi/include/sbi/fw_dynamic.h
@@ -0,0 +1,79 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __FW_DYNAMIC_H__
+#define __FW_DYNAMIC_H__
+
+#include <sbi/riscv_asm.h>
+
+/* clang-format off */
+
+/** Offset of magic member in fw_dynamic_info */
+#define FW_DYNAMIC_INFO_MAGIC_OFFSET (0 * __SIZEOF_POINTER__)
+/** Offset of version member in fw_dynamic_info */
+#define FW_DYNAMIC_INFO_VERSION_OFFSET (1 * __SIZEOF_POINTER__)
+/** Offset of next_addr member in fw_dynamic_info (version >= 1) */
+#define FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET (2 * __SIZEOF_POINTER__)
+/** Offset of next_mode member in fw_dynamic_info (version >= 1) */
+#define FW_DYNAMIC_INFO_NEXT_MODE_OFFSET (3 * __SIZEOF_POINTER__)
+/** Offset of options member in fw_dynamic_info (version >= 1) */
+#define FW_DYNAMIC_INFO_OPTIONS_OFFSET (4 * __SIZEOF_POINTER__)
+/** Offset of boot_hart member in fw_dynamic_info (version >= 2) */
+#define FW_DYNAMIC_INFO_BOOT_HART_OFFSET (5 * __SIZEOF_POINTER__)
+
+/** Expected value of info magic ('OSBI' ascii string in hex) */
+#define FW_DYNAMIC_INFO_MAGIC_VALUE 0x4942534f
+
+/** Maximum supported info version */
+#define FW_DYNAMIC_INFO_VERSION_MAX 0x2
+
+/** Possible next mode values */
+#define FW_DYNAMIC_INFO_NEXT_MODE_U 0x0
+#define FW_DYNAMIC_INFO_NEXT_MODE_S 0x1
+#define FW_DYNAMIC_INFO_NEXT_MODE_M 0x3
+
+/* clang-format on */
+
+#ifndef __ASSEMBLY__
+
+#include <sbi/sbi_types.h>
+
+/** Representation dynamic info passed by previous booting stage */
+struct fw_dynamic_info {
+ /** Info magic */
+ unsigned long magic;
+ /** Info version */
+ unsigned long version;
+ /** Next booting stage address */
+ unsigned long next_addr;
+ /** Next booting stage mode */
+ unsigned long next_mode;
+ /** Options for OpenSBI library */
+ unsigned long options;
+ /**
+ * Preferred boot HART id
+ *
+ * It is possible that the previous booting stage uses same link
+ * address as the FW_DYNAMIC firmware. In this case, the relocation
+ * lottery mechanism can potentially overwrite the previous booting
+ * stage while other HARTs are still running in the previous booting
+ * stage leading to boot-time crash. To avoid this boot-time crash,
+ * the previous booting stage can specify last HART that will jump
+ * to the FW_DYNAMIC firmware as the preferred boot HART.
+ *
+ * To avoid specifying a preferred boot HART, the previous booting
+ * stage can set it to -1UL which will force the FW_DYNAMIC firmware
+ * to use the relocation lottery mechanism.
+ */
+ unsigned long boot_hart;
+} __packed;
+
+#endif
+
+#endif
diff --git a/roms/opensbi/include/sbi/riscv_asm.h b/roms/opensbi/include/sbi/riscv_asm.h
new file mode 100644
index 000000000..10f31a7fc
--- /dev/null
+++ b/roms/opensbi/include/sbi/riscv_asm.h
@@ -0,0 +1,187 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __RISCV_ASM_H__
+#define __RISCV_ASM_H__
+
+#include <sbi/riscv_encoding.h>
+
+/* clang-format off */
+
+#ifdef __ASSEMBLY__
+#define __ASM_STR(x) x
+#else
+#define __ASM_STR(x) #x
+#endif
+
+#if __riscv_xlen == 64
+#define __REG_SEL(a, b) __ASM_STR(a)
+#elif __riscv_xlen == 32
+#define __REG_SEL(a, b) __ASM_STR(b)
+#else
+#error "Unexpected __riscv_xlen"
+#endif
+
+#define PAGE_SHIFT (12)
+#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
+#define PAGE_MASK (~(PAGE_SIZE - 1))
+
+#define REG_L __REG_SEL(ld, lw)
+#define REG_S __REG_SEL(sd, sw)
+#define SZREG __REG_SEL(8, 4)
+#define LGREG __REG_SEL(3, 2)
+
+#if __SIZEOF_POINTER__ == 8
+#ifdef __ASSEMBLY__
+#define RISCV_PTR .dword
+#define RISCV_SZPTR 8
+#define RISCV_LGPTR 3
+#else
+#define RISCV_PTR ".dword"
+#define RISCV_SZPTR "8"
+#define RISCV_LGPTR "3"
+#endif
+#elif __SIZEOF_POINTER__ == 4
+#ifdef __ASSEMBLY__
+#define RISCV_PTR .word
+#define RISCV_SZPTR 4
+#define RISCV_LGPTR 2
+#else
+#define RISCV_PTR ".word"
+#define RISCV_SZPTR "4"
+#define RISCV_LGPTR "2"
+#endif
+#else
+#error "Unexpected __SIZEOF_POINTER__"
+#endif
+
+#if (__SIZEOF_INT__ == 4)
+#define RISCV_INT __ASM_STR(.word)
+#define RISCV_SZINT __ASM_STR(4)
+#define RISCV_LGINT __ASM_STR(2)
+#else
+#error "Unexpected __SIZEOF_INT__"
+#endif
+
+#if (__SIZEOF_SHORT__ == 2)
+#define RISCV_SHORT __ASM_STR(.half)
+#define RISCV_SZSHORT __ASM_STR(2)
+#define RISCV_LGSHORT __ASM_STR(1)
+#else
+#error "Unexpected __SIZEOF_SHORT__"
+#endif
+
+/* clang-format on */
+
+#ifndef __ASSEMBLY__
+
+#define csr_swap(csr, val) \
+ ({ \
+ unsigned long __v = (unsigned long)(val); \
+ __asm__ __volatile__("csrrw %0, " __ASM_STR(csr) ", %1" \
+ : "=r"(__v) \
+ : "rK"(__v) \
+ : "memory"); \
+ __v; \
+ })
+
+#define csr_read(csr) \
+ ({ \
+ register unsigned long __v; \
+ __asm__ __volatile__("csrr %0, " __ASM_STR(csr) \
+ : "=r"(__v) \
+ : \
+ : "memory"); \
+ __v; \
+ })
+
+#define csr_write(csr, val) \
+ ({ \
+ unsigned long __v = (unsigned long)(val); \
+ __asm__ __volatile__("csrw " __ASM_STR(csr) ", %0" \
+ : \
+ : "rK"(__v) \
+ : "memory"); \
+ })
+
+#define csr_read_set(csr, val) \
+ ({ \
+ unsigned long __v = (unsigned long)(val); \
+ __asm__ __volatile__("csrrs %0, " __ASM_STR(csr) ", %1" \
+ : "=r"(__v) \
+ : "rK"(__v) \
+ : "memory"); \
+ __v; \
+ })
+
+#define csr_set(csr, val) \
+ ({ \
+ unsigned long __v = (unsigned long)(val); \
+ __asm__ __volatile__("csrs " __ASM_STR(csr) ", %0" \
+ : \
+ : "rK"(__v) \
+ : "memory"); \
+ })
+
+#define csr_read_clear(csr, val) \
+ ({ \
+ unsigned long __v = (unsigned long)(val); \
+ __asm__ __volatile__("csrrc %0, " __ASM_STR(csr) ", %1" \
+ : "=r"(__v) \
+ : "rK"(__v) \
+ : "memory"); \
+ __v; \
+ })
+
+#define csr_clear(csr, val) \
+ ({ \
+ unsigned long __v = (unsigned long)(val); \
+ __asm__ __volatile__("csrc " __ASM_STR(csr) ", %0" \
+ : \
+ : "rK"(__v) \
+ : "memory"); \
+ })
+
+unsigned long csr_read_num(int csr_num);
+
+void csr_write_num(int csr_num, unsigned long val);
+
+#define wfi() \
+ do { \
+ __asm__ __volatile__("wfi" ::: "memory"); \
+ } while (0)
+
+/* Get current HART id */
+#define current_hartid() ((unsigned int)csr_read(CSR_MHARTID))
+
+/* determine CPU extension, return non-zero support */
+int misa_extension_imp(char ext);
+
+#define misa_extension(c)\
+({\
+ _Static_assert(((c >= 'A') && (c <= 'Z')),\
+ "The parameter of misa_extension must be [A-Z]");\
+ misa_extension_imp(c);\
+})
+
+/* Get MXL field of misa, return -1 on error */
+int misa_xlen(void);
+
+/* Get RISC-V ISA string representation */
+void misa_string(int xlen, char *out, unsigned int out_sz);
+
+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 *log2len);
+
+#endif /* !__ASSEMBLY__ */
+
+#endif
diff --git a/roms/opensbi/include/sbi/riscv_atomic.h b/roms/opensbi/include/sbi/riscv_atomic.h
new file mode 100644
index 000000000..3972e0b72
--- /dev/null
+++ b/roms/opensbi/include/sbi/riscv_atomic.h
@@ -0,0 +1,70 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __RISCV_ATOMIC_H__
+#define __RISCV_ATOMIC_H__
+
+typedef struct {
+ volatile long counter;
+} atomic_t;
+
+#define ATOMIC_INIT(_lptr, val) (_lptr)->counter = (val)
+
+#define ATOMIC_INITIALIZER(val) \
+ { \
+ .counter = (val), \
+ }
+
+long atomic_read(atomic_t *atom);
+
+void atomic_write(atomic_t *atom, long value);
+
+long atomic_add_return(atomic_t *atom, long value);
+
+long atomic_sub_return(atomic_t *atom, long value);
+
+long atomic_cmpxchg(atomic_t *atom, long oldval, long newval);
+
+long atomic_xchg(atomic_t *atom, long newval);
+
+unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
+ unsigned int newval);
+
+unsigned long atomic_raw_xchg_ulong(volatile unsigned long *ptr,
+ unsigned long newval);
+/**
+ * Set a bit in an atomic variable and return the new value.
+ * @nr : Bit to set.
+ * @atom: atomic variable to modify
+ */
+int atomic_set_bit(int nr, atomic_t *atom);
+
+/**
+ * Clear a bit in an atomic variable and return the new value.
+ * @nr : Bit to set.
+ * @atom: atomic variable to modify
+ */
+
+int atomic_clear_bit(int nr, atomic_t *atom);
+
+/**
+ * Set a bit in any address and return the new value .
+ * @nr : Bit to set.
+ * @addr: Address to modify
+ */
+int atomic_raw_set_bit(int nr, volatile unsigned long *addr);
+
+/**
+ * Clear a bit in any address and return the new value .
+ * @nr : Bit to set.
+ * @addr: Address to modify
+ */
+int atomic_raw_clear_bit(int nr, volatile unsigned long *addr);
+
+#endif
diff --git a/roms/opensbi/include/sbi/riscv_barrier.h b/roms/opensbi/include/sbi/riscv_barrier.h
new file mode 100644
index 000000000..905ecb40f
--- /dev/null
+++ b/roms/opensbi/include/sbi/riscv_barrier.h
@@ -0,0 +1,57 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __RISCV_BARRIER_H__
+#define __RISCV_BARRIER_H__
+
+/* clang-format off */
+
+#define RISCV_ACQUIRE_BARRIER "\tfence r , rw\n"
+#define RISCV_RELEASE_BARRIER "\tfence rw, w\n"
+
+#define RISCV_FENCE(p, s) \
+ __asm__ __volatile__ ("fence " #p "," #s : : : "memory")
+
+/* Read & Write Memory barrier */
+#define mb() RISCV_FENCE(iorw,iorw)
+
+/* Read Memory barrier */
+#define rmb() RISCV_FENCE(ir,ir)
+
+/* Write Memory barrier */
+#define wmb() RISCV_FENCE(ow,ow)
+
+/* SMP Read & Write Memory barrier */
+#define smp_mb() RISCV_FENCE(rw,rw)
+
+/* SMP Read Memory barrier */
+#define smp_rmb() RISCV_FENCE(r,r)
+
+/* SMP Write Memory barrier */
+#define smp_wmb() RISCV_FENCE(w,w)
+
+/* CPU relax for busy loop */
+#define cpu_relax() asm volatile ("" : : : "memory")
+
+/* clang-format on */
+
+#define __smp_store_release(p, v) \
+ do { \
+ RISCV_FENCE(rw, w); \
+ *(p) = (v); \
+ } while (0)
+
+#define __smp_load_acquire(p) \
+ ({ \
+ typeof(*p) ___p1 = *(p); \
+ RISCV_FENCE(r, rw); \
+ ___p1; \
+ })
+
+#endif
diff --git a/roms/opensbi/include/sbi/riscv_encoding.h b/roms/opensbi/include/sbi/riscv_encoding.h
new file mode 100644
index 000000000..e1d0b463c
--- /dev/null
+++ b/roms/opensbi/include/sbi/riscv_encoding.h
@@ -0,0 +1,699 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __RISCV_ENCODING_H__
+#define __RISCV_ENCODING_H__
+
+#include <sbi/sbi_const.h>
+
+/* clang-format off */
+#define MSTATUS_SIE _UL(0x00000002)
+#define MSTATUS_MIE _UL(0x00000008)
+#define MSTATUS_SPIE_SHIFT 5
+#define MSTATUS_SPIE (_UL(1) << MSTATUS_SPIE_SHIFT)
+#define MSTATUS_UBE _UL(0x00000040)
+#define MSTATUS_MPIE _UL(0x00000080)
+#define MSTATUS_SPP_SHIFT 8
+#define MSTATUS_SPP (_UL(1) << MSTATUS_SPP_SHIFT)
+#define MSTATUS_MPP_SHIFT 11
+#define MSTATUS_MPP (_UL(3) << MSTATUS_MPP_SHIFT)
+#define MSTATUS_FS _UL(0x00006000)
+#define MSTATUS_XS _UL(0x00018000)
+#define MSTATUS_VS _UL(0x01800000)
+#define MSTATUS_MPRV _UL(0x00020000)
+#define MSTATUS_SUM _UL(0x00040000)
+#define MSTATUS_MXR _UL(0x00080000)
+#define MSTATUS_TVM _UL(0x00100000)
+#define MSTATUS_TW _UL(0x00200000)
+#define MSTATUS_TSR _UL(0x00400000)
+#define MSTATUS32_SD _UL(0x80000000)
+#if __riscv_xlen == 64
+#define MSTATUS_UXL _ULL(0x0000000300000000)
+#define MSTATUS_SXL _ULL(0x0000000C00000000)
+#define MSTATUS_SBE _ULL(0x0000001000000000)
+#define MSTATUS_MBE _ULL(0x0000002000000000)
+#define MSTATUS_MPV _ULL(0x0000008000000000)
+#else
+#define MSTATUSH_SBE _UL(0x00000010)
+#define MSTATUSH_MBE _UL(0x00000020)
+#define MSTATUSH_MPV _UL(0x00000080)
+#endif
+#define MSTATUS32_SD _UL(0x80000000)
+#define MSTATUS64_SD _ULL(0x8000000000000000)
+
+#define SSTATUS_SIE MSTATUS_SIE
+#define SSTATUS_SPIE_SHIFT MSTATUS_SPIE_SHIFT
+#define SSTATUS_SPIE MSTATUS_SPIE
+#define SSTATUS_SPP_SHIFT MSTATUS_SPP_SHIFT
+#define SSTATUS_SPP MSTATUS_SPP
+#define SSTATUS_FS MSTATUS_FS
+#define SSTATUS_XS MSTATUS_XS
+#define SSTATUS_VS MSTATUS_VS
+#define SSTATUS_SUM MSTATUS_SUM
+#define SSTATUS_MXR MSTATUS_MXR
+#define SSTATUS32_SD MSTATUS32_SD
+#define SSTATUS64_UXL MSTATUS_UXL
+#define SSTATUS64_SD MSTATUS64_SD
+
+#if __riscv_xlen == 64
+#define HSTATUS_VSXL _UL(0x300000000)
+#define HSTATUS_VSXL_SHIFT 32
+#endif
+#define HSTATUS_VTSR _UL(0x00400000)
+#define HSTATUS_VTW _UL(0x00200000)
+#define HSTATUS_VTVM _UL(0x00100000)
+#define HSTATUS_VGEIN _UL(0x0003f000)
+#define HSTATUS_VGEIN_SHIFT 12
+#define HSTATUS_HU _UL(0x00000200)
+#define HSTATUS_SPVP _UL(0x00000100)
+#define HSTATUS_SPV _UL(0x00000080)
+#define HSTATUS_GVA _UL(0x00000040)
+#define HSTATUS_VSBE _UL(0x00000020)
+
+#define IRQ_S_SOFT 1
+#define IRQ_VS_SOFT 2
+#define IRQ_M_SOFT 3
+#define IRQ_S_TIMER 5
+#define IRQ_VS_TIMER 6
+#define IRQ_M_TIMER 7
+#define IRQ_S_EXT 9
+#define IRQ_VS_EXT 10
+#define IRQ_M_EXT 11
+#define IRQ_S_GEXT 12
+
+#define MIP_SSIP (_UL(1) << IRQ_S_SOFT)
+#define MIP_VSSIP (_UL(1) << IRQ_VS_SOFT)
+#define MIP_MSIP (_UL(1) << IRQ_M_SOFT)
+#define MIP_STIP (_UL(1) << IRQ_S_TIMER)
+#define MIP_VSTIP (_UL(1) << IRQ_VS_TIMER)
+#define MIP_MTIP (_UL(1) << IRQ_M_TIMER)
+#define MIP_SEIP (_UL(1) << IRQ_S_EXT)
+#define MIP_VSEIP (_UL(1) << IRQ_VS_EXT)
+#define MIP_MEIP (_UL(1) << IRQ_M_EXT)
+#define MIP_SGEIP (_UL(1) << IRQ_S_GEXT)
+
+#define SIP_SSIP MIP_SSIP
+#define SIP_STIP MIP_STIP
+
+#define PRV_U _UL(0)
+#define PRV_S _UL(1)
+#define PRV_M _UL(3)
+
+#define SATP32_MODE _UL(0x80000000)
+#define SATP32_ASID _UL(0x7FC00000)
+#define SATP32_PPN _UL(0x003FFFFF)
+#define SATP64_MODE _ULL(0xF000000000000000)
+#define SATP64_ASID _ULL(0x0FFFF00000000000)
+#define SATP64_PPN _ULL(0x00000FFFFFFFFFFF)
+
+#define SATP_MODE_OFF _UL(0)
+#define SATP_MODE_SV32 _UL(1)
+#define SATP_MODE_SV39 _UL(8)
+#define SATP_MODE_SV48 _UL(9)
+#define SATP_MODE_SV57 _UL(10)
+#define SATP_MODE_SV64 _UL(11)
+
+#define HGATP_MODE_OFF _UL(0)
+#define HGATP_MODE_SV32X4 _UL(1)
+#define HGATP_MODE_SV39X4 _UL(8)
+#define HGATP_MODE_SV48X4 _UL(9)
+
+#define HGATP32_MODE_SHIFT 31
+#define HGATP32_VMID_SHIFT 22
+#define HGATP32_VMID_MASK _UL(0x1FC00000)
+#define HGATP32_PPN _UL(0x003FFFFF)
+
+#define HGATP64_MODE_SHIFT 60
+#define HGATP64_VMID_SHIFT 44
+#define HGATP64_VMID_MASK _ULL(0x03FFF00000000000)
+#define HGATP64_PPN _ULL(0x00000FFFFFFFFFFF)
+
+#define PMP_R _UL(0x01)
+#define PMP_W _UL(0x02)
+#define PMP_X _UL(0x04)
+#define PMP_A _UL(0x18)
+#define PMP_A_TOR _UL(0x08)
+#define PMP_A_NA4 _UL(0x10)
+#define PMP_A_NAPOT _UL(0x18)
+#define PMP_L _UL(0x80)
+
+#define PMP_SHIFT 2
+#define PMP_COUNT 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
+#define SSTATUS_SD SSTATUS64_SD
+#define SATP_MODE SATP64_MODE
+
+#define HGATP_PPN HGATP64_PPN
+#define HGATP_VMID_SHIFT HGATP64_VMID_SHIFT
+#define HGATP_VMID_MASK HGATP64_VMID_MASK
+#define HGATP_MODE_SHIFT HGATP64_MODE_SHIFT
+#else
+#define MSTATUS_SD MSTATUS32_SD
+#define SSTATUS_SD SSTATUS32_SD
+#define SATP_MODE SATP32_MODE
+
+#define HGATP_PPN HGATP32_PPN
+#define HGATP_VMID_SHIFT HGATP32_VMID_SHIFT
+#define HGATP_VMID_MASK HGATP32_VMID_MASK
+#define HGATP_MODE_SHIFT HGATP32_MODE_SHIFT
+#endif
+
+/* ===== 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_TIME 0xc01
+#define CSR_INSTRET 0xc02
+#define CSR_HPMCOUNTER3 0xc03
+#define CSR_HPMCOUNTER4 0xc04
+#define CSR_HPMCOUNTER5 0xc05
+#define CSR_HPMCOUNTER6 0xc06
+#define CSR_HPMCOUNTER7 0xc07
+#define CSR_HPMCOUNTER8 0xc08
+#define CSR_HPMCOUNTER9 0xc09
+#define CSR_HPMCOUNTER10 0xc0a
+#define CSR_HPMCOUNTER11 0xc0b
+#define CSR_HPMCOUNTER12 0xc0c
+#define CSR_HPMCOUNTER13 0xc0d
+#define CSR_HPMCOUNTER14 0xc0e
+#define CSR_HPMCOUNTER15 0xc0f
+#define CSR_HPMCOUNTER16 0xc10
+#define CSR_HPMCOUNTER17 0xc11
+#define CSR_HPMCOUNTER18 0xc12
+#define CSR_HPMCOUNTER19 0xc13
+#define CSR_HPMCOUNTER20 0xc14
+#define CSR_HPMCOUNTER21 0xc15
+#define CSR_HPMCOUNTER22 0xc16
+#define CSR_HPMCOUNTER23 0xc17
+#define CSR_HPMCOUNTER24 0xc18
+#define CSR_HPMCOUNTER25 0xc19
+#define CSR_HPMCOUNTER26 0xc1a
+#define CSR_HPMCOUNTER27 0xc1b
+#define CSR_HPMCOUNTER28 0xc1c
+#define CSR_HPMCOUNTER29 0xc1d
+#define CSR_HPMCOUNTER30 0xc1e
+#define CSR_HPMCOUNTER31 0xc1f
+#define CSR_CYCLEH 0xc80
+#define CSR_TIMEH 0xc81
+#define CSR_INSTRETH 0xc82
+#define CSR_HPMCOUNTER3H 0xc83
+#define CSR_HPMCOUNTER4H 0xc84
+#define CSR_HPMCOUNTER5H 0xc85
+#define CSR_HPMCOUNTER6H 0xc86
+#define CSR_HPMCOUNTER7H 0xc87
+#define CSR_HPMCOUNTER8H 0xc88
+#define CSR_HPMCOUNTER9H 0xc89
+#define CSR_HPMCOUNTER10H 0xc8a
+#define CSR_HPMCOUNTER11H 0xc8b
+#define CSR_HPMCOUNTER12H 0xc8c
+#define CSR_HPMCOUNTER13H 0xc8d
+#define CSR_HPMCOUNTER14H 0xc8e
+#define CSR_HPMCOUNTER15H 0xc8f
+#define CSR_HPMCOUNTER16H 0xc90
+#define CSR_HPMCOUNTER17H 0xc91
+#define CSR_HPMCOUNTER18H 0xc92
+#define CSR_HPMCOUNTER19H 0xc93
+#define CSR_HPMCOUNTER20H 0xc94
+#define CSR_HPMCOUNTER21H 0xc95
+#define CSR_HPMCOUNTER22H 0xc96
+#define CSR_HPMCOUNTER23H 0xc97
+#define CSR_HPMCOUNTER24H 0xc98
+#define CSR_HPMCOUNTER25H 0xc99
+#define CSR_HPMCOUNTER26H 0xc9a
+#define CSR_HPMCOUNTER27H 0xc9b
+#define CSR_HPMCOUNTER28H 0xc9c
+#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
+#define CSR_MHPMCOUNTER4H 0xb84
+#define CSR_MHPMCOUNTER5H 0xb85
+#define CSR_MHPMCOUNTER6H 0xb86
+#define CSR_MHPMCOUNTER7H 0xb87
+#define CSR_MHPMCOUNTER8H 0xb88
+#define CSR_MHPMCOUNTER9H 0xb89
+#define CSR_MHPMCOUNTER10H 0xb8a
+#define CSR_MHPMCOUNTER11H 0xb8b
+#define CSR_MHPMCOUNTER12H 0xb8c
+#define CSR_MHPMCOUNTER13H 0xb8d
+#define CSR_MHPMCOUNTER14H 0xb8e
+#define CSR_MHPMCOUNTER15H 0xb8f
+#define CSR_MHPMCOUNTER16H 0xb90
+#define CSR_MHPMCOUNTER17H 0xb91
+#define CSR_MHPMCOUNTER18H 0xb92
+#define CSR_MHPMCOUNTER19H 0xb93
+#define CSR_MHPMCOUNTER20H 0xb94
+#define CSR_MHPMCOUNTER21H 0xb95
+#define CSR_MHPMCOUNTER22H 0xb96
+#define CSR_MHPMCOUNTER23H 0xb97
+#define CSR_MHPMCOUNTER24H 0xb98
+#define CSR_MHPMCOUNTER25H 0xb99
+#define CSR_MHPMCOUNTER26H 0xb9a
+#define CSR_MHPMCOUNTER27H 0xb9b
+#define CSR_MHPMCOUNTER28H 0xb9c
+#define CSR_MHPMCOUNTER29H 0xb9d
+#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
+#define CAUSE_BREAKPOINT 0x3
+#define CAUSE_MISALIGNED_LOAD 0x4
+#define CAUSE_LOAD_ACCESS 0x5
+#define CAUSE_MISALIGNED_STORE 0x6
+#define CAUSE_STORE_ACCESS 0x7
+#define CAUSE_USER_ECALL 0x8
+#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
+#define CAUSE_STORE_PAGE_FAULT 0xf
+#define CAUSE_FETCH_GUEST_PAGE_FAULT 0x14
+#define CAUSE_LOAD_GUEST_PAGE_FAULT 0x15
+#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
+#define INSN_MASK_LH 0x707f
+#define INSN_MATCH_LW 0x2003
+#define INSN_MASK_LW 0x707f
+#define INSN_MATCH_LD 0x3003
+#define INSN_MASK_LD 0x707f
+#define INSN_MATCH_LBU 0x4003
+#define INSN_MASK_LBU 0x707f
+#define INSN_MATCH_LHU 0x5003
+#define INSN_MASK_LHU 0x707f
+#define INSN_MATCH_LWU 0x6003
+#define INSN_MASK_LWU 0x707f
+#define INSN_MATCH_SB 0x23
+#define INSN_MASK_SB 0x707f
+#define INSN_MATCH_SH 0x1023
+#define INSN_MASK_SH 0x707f
+#define INSN_MATCH_SW 0x2023
+#define INSN_MASK_SW 0x707f
+#define INSN_MATCH_SD 0x3023
+#define INSN_MASK_SD 0x707f
+
+#define INSN_MATCH_FLW 0x2007
+#define INSN_MASK_FLW 0x707f
+#define INSN_MATCH_FLD 0x3007
+#define INSN_MASK_FLD 0x707f
+#define INSN_MATCH_FLQ 0x4007
+#define INSN_MASK_FLQ 0x707f
+#define INSN_MATCH_FSW 0x2027
+#define INSN_MASK_FSW 0x707f
+#define INSN_MATCH_FSD 0x3027
+#define INSN_MASK_FSD 0x707f
+#define INSN_MATCH_FSQ 0x4027
+#define INSN_MASK_FSQ 0x707f
+
+#define INSN_MATCH_C_LD 0x6000
+#define INSN_MASK_C_LD 0xe003
+#define INSN_MATCH_C_SD 0xe000
+#define INSN_MASK_C_SD 0xe003
+#define INSN_MATCH_C_LW 0x4000
+#define INSN_MASK_C_LW 0xe003
+#define INSN_MATCH_C_SW 0xc000
+#define INSN_MASK_C_SW 0xe003
+#define INSN_MATCH_C_LDSP 0x6002
+#define INSN_MASK_C_LDSP 0xe003
+#define INSN_MATCH_C_SDSP 0xe002
+#define INSN_MASK_C_SDSP 0xe003
+#define INSN_MATCH_C_LWSP 0x4002
+#define INSN_MASK_C_LWSP 0xe003
+#define INSN_MATCH_C_SWSP 0xc002
+#define INSN_MASK_C_SWSP 0xe003
+
+#define INSN_MATCH_C_FLD 0x2000
+#define INSN_MASK_C_FLD 0xe003
+#define INSN_MATCH_C_FLW 0x6000
+#define INSN_MASK_C_FLW 0xe003
+#define INSN_MATCH_C_FSD 0xa000
+#define INSN_MASK_C_FSD 0xe003
+#define INSN_MATCH_C_FSW 0xe000
+#define INSN_MASK_C_FSW 0xe003
+#define INSN_MATCH_C_FLDSP 0x2002
+#define INSN_MASK_C_FLDSP 0xe003
+#define INSN_MATCH_C_FSDSP 0xa002
+#define INSN_MASK_C_FSDSP 0xe003
+#define INSN_MATCH_C_FLWSP 0x6002
+#define INSN_MASK_C_FLWSP 0xe003
+#define INSN_MATCH_C_FSWSP 0xe002
+#define INSN_MASK_C_FSWSP 0xe003
+
+#define INSN_MASK_WFI 0xffffff00
+#define INSN_MATCH_WFI 0x10500000
+
+#define INSN_16BIT_MASK 0x3
+#define INSN_32BIT_MASK 0x1c
+
+#define INSN_IS_16BIT(insn) \
+ (((insn) & INSN_16BIT_MASK) != INSN_16BIT_MASK)
+#define INSN_IS_32BIT(insn) \
+ (((insn) & INSN_16BIT_MASK) == INSN_16BIT_MASK && \
+ ((insn) & INSN_32BIT_MASK) != INSN_32BIT_MASK)
+
+#define INSN_LEN(insn) (INSN_IS_16BIT(insn) ? 2 : 4)
+
+#if __riscv_xlen == 64
+#define LOG_REGBYTES 3
+#else
+#define LOG_REGBYTES 2
+#endif
+#define REGBYTES (1 << LOG_REGBYTES)
+
+#define SH_RD 7
+#define SH_RS1 15
+#define SH_RS2 20
+#define SH_RS2C 2
+
+#define RV_X(x, s, n) (((x) >> (s)) & ((1 << (n)) - 1))
+#define RVC_LW_IMM(x) ((RV_X(x, 6, 1) << 2) | \
+ (RV_X(x, 10, 3) << 3) | \
+ (RV_X(x, 5, 1) << 6))
+#define RVC_LD_IMM(x) ((RV_X(x, 10, 3) << 3) | \
+ (RV_X(x, 5, 2) << 6))
+#define RVC_LWSP_IMM(x) ((RV_X(x, 4, 3) << 2) | \
+ (RV_X(x, 12, 1) << 5) | \
+ (RV_X(x, 2, 2) << 6))
+#define RVC_LDSP_IMM(x) ((RV_X(x, 5, 2) << 3) | \
+ (RV_X(x, 12, 1) << 5) | \
+ (RV_X(x, 2, 3) << 6))
+#define RVC_SWSP_IMM(x) ((RV_X(x, 9, 4) << 2) | \
+ (RV_X(x, 7, 2) << 6))
+#define RVC_SDSP_IMM(x) ((RV_X(x, 10, 3) << 3) | \
+ (RV_X(x, 7, 3) << 6))
+#define RVC_RS1S(insn) (8 + RV_X(insn, SH_RD, 3))
+#define RVC_RS2S(insn) (8 + RV_X(insn, SH_RS2C, 3))
+#define RVC_RS2(insn) RV_X(insn, SH_RS2C, 5)
+
+#define SHIFT_RIGHT(x, y) \
+ ((y) < 0 ? ((x) << -(y)) : ((x) >> (y)))
+
+#define REG_MASK \
+ ((1 << (5 + LOG_REGBYTES)) - (1 << LOG_REGBYTES))
+
+#define REG_OFFSET(insn, pos) \
+ (SHIFT_RIGHT((insn), (pos) - LOG_REGBYTES) & REG_MASK)
+
+#define REG_PTR(insn, pos, regs) \
+ (ulong *)((ulong)(regs) + REG_OFFSET(insn, pos))
+
+#define GET_RM(insn) (((insn) >> 12) & 7)
+
+#define GET_RS1(insn, regs) (*REG_PTR(insn, SH_RS1, regs))
+#define GET_RS2(insn, regs) (*REG_PTR(insn, SH_RS2, regs))
+#define GET_RS1S(insn, regs) (*REG_PTR(RVC_RS1S(insn), 0, regs))
+#define GET_RS2S(insn, regs) (*REG_PTR(RVC_RS2S(insn), 0, regs))
+#define GET_RS2C(insn, regs) (*REG_PTR(insn, SH_RS2C, regs))
+#define GET_SP(regs) (*REG_PTR(2, 0, regs))
+#define SET_RD(insn, regs, val) (*REG_PTR(insn, SH_RD, regs) = (val))
+#define IMM_I(insn) ((s32)(insn) >> 20)
+#define IMM_S(insn) (((s32)(insn) >> 25 << 5) | \
+ (s32)(((insn) >> 7) & 0x1f))
+#define MASK_FUNCT3 0x7000
+
+/* clang-format on */
+
+#endif
diff --git a/roms/opensbi/include/sbi/riscv_fp.h b/roms/opensbi/include/sbi/riscv_fp.h
new file mode 100644
index 000000000..a685884a5
--- /dev/null
+++ b/roms/opensbi/include/sbi/riscv_fp.h
@@ -0,0 +1,94 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __RISCV_FP_H__
+#define __RISCV_FP_H__
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_types.h>
+
+#define GET_PRECISION(insn) (((insn) >> 25) & 3)
+#define GET_RM(insn) (((insn) >> 12) & 7)
+#define PRECISION_S 0
+#define PRECISION_D 1
+
+#ifdef __riscv_flen
+
+#define GET_F32_REG(insn, pos, regs) \
+ ({ \
+ register s32 value asm("a0") = \
+ SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
+ ulong tmp; \
+ asm("1: auipc %0, %%pcrel_hi(get_f32_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" \
+ : "=&r"(tmp), "+&r"(value)::"t0"); \
+ value; \
+ })
+#define SET_F32_REG(insn, pos, regs, val) \
+ ({ \
+ register u32 value asm("a0") = (val); \
+ ulong offset = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
+ ulong tmp; \
+ asm volatile( \
+ "1: auipc %0, %%pcrel_hi(put_f32_reg); add %0, %0, %2; jalr t0, %0, %%pcrel_lo(1b)" \
+ : "=&r"(tmp) \
+ : "r"(value), "r"(offset) \
+ : "t0"); \
+ })
+#define init_fp_reg(i) SET_F32_REG((i) << 3, 3, 0, 0)
+#define GET_F64_REG(insn, pos, regs) \
+ ({ \
+ register ulong value asm("a0") = \
+ SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
+ ulong tmp; \
+ asm("1: auipc %0, %%pcrel_hi(get_f64_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" \
+ : "=&r"(tmp), "+&r"(value)::"t0"); \
+ sizeof(ulong) == 4 ? *(int64_t *)value : (int64_t)value; \
+ })
+#define SET_F64_REG(insn, pos, regs, val) \
+ ({ \
+ uint64_t __val = (val); \
+ register ulong value asm("a0") = \
+ sizeof(ulong) == 4 ? (ulong)&__val : (ulong)__val; \
+ ulong offset = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
+ ulong tmp; \
+ asm volatile( \
+ "1: auipc %0, %%pcrel_hi(put_f64_reg); add %0, %0, %2; jalr t0, %0, %%pcrel_lo(1b)" \
+ : "=&r"(tmp) \
+ : "r"(value), "r"(offset) \
+ : "t0"); \
+ })
+#define GET_FCSR() csr_read(CSR_FCSR)
+#define SET_FCSR(value) csr_write(CSR_FCSR, (value))
+#define GET_FRM() csr_read(CSR_FRM)
+#define SET_FRM(value) csr_write(CSR_FRM, (value))
+#define GET_FFLAGS() csr_read(CSR_FFLAGS)
+#define SET_FFLAGS(value) csr_write(CSR_FFLAGS, (value))
+
+#define SET_FS_DIRTY() ((void)0)
+
+#define GET_F32_RS1(insn, regs) (GET_F32_REG(insn, 15, regs))
+#define GET_F32_RS2(insn, regs) (GET_F32_REG(insn, 20, regs))
+#define GET_F32_RS3(insn, regs) (GET_F32_REG(insn, 27, regs))
+#define GET_F64_RS1(insn, regs) (GET_F64_REG(insn, 15, regs))
+#define GET_F64_RS2(insn, regs) (GET_F64_REG(insn, 20, regs))
+#define GET_F64_RS3(insn, regs) (GET_F64_REG(insn, 27, regs))
+#define SET_F32_RD(insn, regs, val) \
+ (SET_F32_REG(insn, 7, regs, val), SET_FS_DIRTY())
+#define SET_F64_RD(insn, regs, val) \
+ (SET_F64_REG(insn, 7, regs, val), SET_FS_DIRTY())
+
+#define GET_F32_RS2C(insn, regs) (GET_F32_REG(insn, 2, regs))
+#define GET_F32_RS2S(insn, regs) (GET_F32_REG(RVC_RS2S(insn), 0, regs))
+#define GET_F64_RS2C(insn, regs) (GET_F64_REG(insn, 2, regs))
+#define GET_F64_RS2S(insn, regs) (GET_F64_REG(RVC_RS2S(insn), 0, regs))
+
+#endif
+
+#endif
diff --git a/roms/opensbi/include/sbi/riscv_io.h b/roms/opensbi/include/sbi/riscv_io.h
new file mode 100644
index 000000000..491323283
--- /dev/null
+++ b/roms/opensbi/include/sbi/riscv_io.h
@@ -0,0 +1,114 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __RISCV_IO_H__
+#define __RISCV_IO_H__
+
+#include <sbi/riscv_barrier.h>
+#include <sbi/sbi_types.h>
+
+static inline void __raw_writeb(u8 val, volatile void *addr)
+{
+ asm volatile("sb %0, 0(%1)" : : "r"(val), "r"(addr));
+}
+
+static inline void __raw_writew(u16 val, volatile void *addr)
+{
+ asm volatile("sh %0, 0(%1)" : : "r"(val), "r"(addr));
+}
+
+static inline void __raw_writel(u32 val, volatile void *addr)
+{
+ asm volatile("sw %0, 0(%1)" : : "r"(val), "r"(addr));
+}
+
+#if __riscv_xlen != 32
+static inline void __raw_writeq(u64 val, volatile void *addr)
+{
+ asm volatile("sd %0, 0(%1)" : : "r"(val), "r"(addr));
+}
+#endif
+
+static inline u8 __raw_readb(const volatile void *addr)
+{
+ u8 val;
+
+ asm volatile("lb %0, 0(%1)" : "=r"(val) : "r"(addr));
+ return val;
+}
+
+static inline u16 __raw_readw(const volatile void *addr)
+{
+ u16 val;
+
+ asm volatile("lh %0, 0(%1)" : "=r"(val) : "r"(addr));
+ return val;
+}
+
+static inline u32 __raw_readl(const volatile void *addr)
+{
+ u32 val;
+
+ asm volatile("lw %0, 0(%1)" : "=r"(val) : "r"(addr));
+ return val;
+}
+
+#if __riscv_xlen != 32
+static inline u64 __raw_readq(const volatile void *addr)
+{
+ u64 val;
+
+ asm volatile("ld %0, 0(%1)" : "=r"(val) : "r"(addr));
+ return val;
+}
+#endif
+
+/* FIXME: These are now the same as asm-generic */
+
+/* clang-format off */
+
+#define __io_rbr() do {} while (0)
+#define __io_rar() do {} while (0)
+#define __io_rbw() do {} while (0)
+#define __io_raw() do {} while (0)
+
+#define readb_relaxed(c) ({ u8 __v; __io_rbr(); __v = __raw_readb(c); __io_rar(); __v; })
+#define readw_relaxed(c) ({ u16 __v; __io_rbr(); __v = __raw_readw(c); __io_rar(); __v; })
+#define readl_relaxed(c) ({ u32 __v; __io_rbr(); __v = __raw_readl(c); __io_rar(); __v; })
+
+#define writeb_relaxed(v,c) ({ __io_rbw(); __raw_writeb((v),(c)); __io_raw(); })
+#define writew_relaxed(v,c) ({ __io_rbw(); __raw_writew((v),(c)); __io_raw(); })
+#define writel_relaxed(v,c) ({ __io_rbw(); __raw_writel((v),(c)); __io_raw(); })
+
+#if __riscv_xlen != 32
+#define readq_relaxed(c) ({ u64 __v; __io_rbr(); __v = __raw_readq(c); __io_rar(); __v; })
+#define writeq_relaxed(v,c) ({ __io_rbw(); __raw_writeq((v),(c)); __io_raw(); })
+#endif
+
+#define __io_br() do {} while (0)
+#define __io_ar() __asm__ __volatile__ ("fence i,r" : : : "memory");
+#define __io_bw() __asm__ __volatile__ ("fence w,o" : : : "memory");
+#define __io_aw() do {} while (0)
+
+#define readb(c) ({ u8 __v; __io_br(); __v = __raw_readb(c); __io_ar(); __v; })
+#define readw(c) ({ u16 __v; __io_br(); __v = __raw_readw(c); __io_ar(); __v; })
+#define readl(c) ({ u32 __v; __io_br(); __v = __raw_readl(c); __io_ar(); __v; })
+
+#define writeb(v,c) ({ __io_bw(); __raw_writeb((v),(c)); __io_aw(); })
+#define writew(v,c) ({ __io_bw(); __raw_writew((v),(c)); __io_aw(); })
+#define writel(v,c) ({ __io_bw(); __raw_writel((v),(c)); __io_aw(); })
+
+#if __riscv_xlen != 32
+#define readq(c) ({ u64 __v; __io_br(); __v = __raw_readq(c); __io_ar(); __v; })
+#define writeq(v,c) ({ __io_bw(); __raw_writeq((v),(c)); __io_aw(); })
+#endif
+
+/* clang-format on */
+
+#endif
diff --git a/roms/opensbi/include/sbi/riscv_locks.h b/roms/opensbi/include/sbi/riscv_locks.h
new file mode 100644
index 000000000..55da7c01c
--- /dev/null
+++ b/roms/opensbi/include/sbi/riscv_locks.h
@@ -0,0 +1,34 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __RISCV_LOCKS_H__
+#define __RISCV_LOCKS_H__
+
+typedef struct {
+ volatile long lock;
+} spinlock_t;
+
+#define __RISCV_SPIN_UNLOCKED 0
+
+#define SPIN_LOCK_INIT(_lptr) (_lptr)->lock = __RISCV_SPIN_UNLOCKED
+
+#define SPIN_LOCK_INITIALIZER \
+ { \
+ .lock = __RISCV_SPIN_UNLOCKED, \
+ }
+
+int spin_lock_check(spinlock_t *lock);
+
+int spin_trylock(spinlock_t *lock);
+
+void spin_lock(spinlock_t *lock);
+
+void spin_unlock(spinlock_t *lock);
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_bitmap.h b/roms/opensbi/include/sbi/sbi_bitmap.h
new file mode 100644
index 000000000..4f0ebb63a
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_bitmap.h
@@ -0,0 +1,128 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_BITMAP_H__
+#define __SBI_BITMAP_H__
+
+#include <sbi/sbi_bitops.h>
+
+#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) % BITS_PER_LONG))
+#define BITMAP_LAST_WORD_MASK(nbits) \
+( \
+ ((nbits) % BITS_PER_LONG) ? \
+ ((1UL << ((nbits) % BITS_PER_LONG)) - 1) : ~0UL \
+)
+
+#define small_const_nbits(nbits) \
+ (__builtin_constant_p(nbits) && (nbits) <= BITS_PER_LONG)
+
+#define DECLARE_BITMAP(name, nbits) unsigned long name[BITS_TO_LONGS(nbits)]
+#define DEFINE_BITMAP(name) extern unsigned long name[]
+
+static inline unsigned long bitmap_estimate_size(int nbits)
+{
+ return (BITS_TO_LONGS(nbits) * sizeof(unsigned long));
+}
+
+void __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
+ const unsigned long *bitmap2, int bits);
+void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
+ const unsigned long *bitmap2, int bits);
+void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
+ const unsigned long *bitmap2, int bits);
+
+static inline void bitmap_set(unsigned long *bmap, int start, int len)
+{
+ int bit;
+ for (bit = start; bit < (start + len); bit++)
+ bmap[BIT_WORD(bit)] |= (0x1UL << BIT_WORD_OFFSET(bit));
+}
+
+static inline void bitmap_clear(unsigned long *bmap, int start, int len)
+{
+ int bit;
+ for (bit = start; bit < (start + len); bit++)
+ bmap[BIT_WORD(bit)] &= ~(0x1UL << BIT_WORD_OFFSET(bit));
+}
+
+static inline void bitmap_zero(unsigned long *dst, int nbits)
+{
+ if (small_const_nbits(nbits))
+ *dst = 0UL;
+ else {
+ size_t i, len = BITS_TO_LONGS(nbits);
+ for (i = 0; i < len; i++)
+ dst[i] = 0;
+ }
+}
+
+static inline void bitmap_zero_except(unsigned long *dst,
+ int exception, int nbits)
+{
+ if (small_const_nbits(nbits))
+ *dst = 0UL;
+ else {
+ size_t i, len = BITS_TO_LONGS(nbits);
+ for (i = 0; i < len; i++)
+ dst[i] = 0;
+ }
+ if (exception < nbits)
+ __set_bit(exception, dst);
+}
+
+static inline void bitmap_fill(unsigned long *dst, int nbits)
+{
+ size_t i, nlongs = BITS_TO_LONGS(nbits);
+ if (!small_const_nbits(nbits)) {
+ for (i = 0; i < (nlongs - 1); i++)
+ dst[i] = -1UL;
+ }
+ dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits);
+}
+
+static inline void bitmap_copy(unsigned long *dst,
+ const unsigned long *src, int nbits)
+{
+ if (small_const_nbits(nbits))
+ *dst = *src;
+ else {
+ size_t i, len = BITS_TO_LONGS(nbits);
+ for (i = 0; i < len; i++)
+ dst[i] = src[i];
+ }
+}
+
+static inline void bitmap_and(unsigned long *dst, const unsigned long *src1,
+ const unsigned long *src2, int nbits)
+{
+ if (small_const_nbits(nbits))
+ *dst = *src1 & *src2;
+ else
+ __bitmap_and(dst, src1, src2, nbits);
+}
+
+static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
+ const unsigned long *src2, int nbits)
+{
+ if (small_const_nbits(nbits))
+ *dst = *src1 | *src2;
+ else
+ __bitmap_or(dst, src1, src2, nbits);
+}
+
+static inline void bitmap_xor(unsigned long *dst, const unsigned long *src1,
+ const unsigned long *src2, int nbits)
+{
+ if (small_const_nbits(nbits))
+ *dst = *src1 ^ *src2;
+ else
+ __bitmap_xor(dst, src1, src2, nbits);
+}
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_bitops.h b/roms/opensbi/include/sbi/sbi_bitops.h
new file mode 100644
index 000000000..879430d4b
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_bitops.h
@@ -0,0 +1,320 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Atish Patra <atish.patra@wdc.com>
+ */
+
+#ifndef __SBI_BITOPS_H__
+#define __SBI_BITOPS_H__
+
+#include <sbi/sbi_types.h>
+
+#if __SIZEOF_POINTER__ == 8
+#define BITS_PER_LONG 64
+#elif __SIZEOF_POINTER__ == 4
+#define BITS_PER_LONG 32
+#else
+#error "Unexpected __SIZEOF_POINTER__"
+#endif
+
+#define EXTRACT_FIELD(val, which) \
+ (((val) & (which)) / ((which) & ~((which)-1)))
+#define INSERT_FIELD(val, which, fieldval) \
+ (((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1))))
+
+#define BITS_TO_LONGS(nbits) (((nbits) + BITS_PER_LONG - 1) / \
+ BITS_PER_LONG)
+
+#define BIT(nr) (1UL << (nr))
+#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
+#define BIT_WORD(bit) ((bit) / BITS_PER_LONG)
+#define BIT_WORD_OFFSET(bit) ((bit) & (BITS_PER_LONG - 1))
+
+#define GENMASK(h, l) \
+ (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
+
+/**
+ * ffs - Find first bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+static inline int ffs(int x)
+{
+ int r = 1;
+
+ if (!x)
+ return 0;
+ if (!(x & 0xffff)) {
+ x >>= 16;
+ r += 16;
+ }
+ if (!(x & 0xff)) {
+ x >>= 8;
+ r += 8;
+ }
+ if (!(x & 0xf)) {
+ x >>= 4;
+ r += 4;
+ }
+ if (!(x & 3)) {
+ x >>= 2;
+ r += 2;
+ }
+ if (!(x & 1))
+ r += 1;
+ return r;
+}
+
+/**
+ * __ffs - find first bit in word.
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static inline int __ffs(unsigned long word)
+{
+ int num = 0;
+
+#if BITS_PER_LONG == 64
+ if ((word & 0xffffffff) == 0) {
+ num += 32;
+ word >>= 32;
+ }
+#endif
+ if ((word & 0xffff) == 0) {
+ num += 16;
+ word >>= 16;
+ }
+ if ((word & 0xff) == 0) {
+ num += 8;
+ word >>= 8;
+ }
+ if ((word & 0xf) == 0) {
+ num += 4;
+ word >>= 4;
+ }
+ if ((word & 0x3) == 0) {
+ num += 2;
+ word >>= 2;
+ }
+ if ((word & 0x1) == 0)
+ num += 1;
+ return num;
+}
+
+/*
+ * ffz - find first zero in word.
+ * @word: The word to search
+ *
+ * Undefined if no zero exists, so code should check against ~0UL first.
+ */
+#define ffz(x) __ffs(~(x))
+
+/**
+ * fls - find last (most-significant) bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as ffs.
+ * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
+ */
+
+static inline int fls(int x)
+{
+ int r = 32;
+
+ if (!x)
+ return 0;
+ if (!(x & 0xffff0000u)) {
+ x <<= 16;
+ r -= 16;
+ }
+ if (!(x & 0xff000000u)) {
+ x <<= 8;
+ r -= 8;
+ }
+ if (!(x & 0xf0000000u)) {
+ x <<= 4;
+ r -= 4;
+ }
+ if (!(x & 0xc0000000u)) {
+ x <<= 2;
+ r -= 2;
+ }
+ if (!(x & 0x80000000u))
+ r -= 1;
+ return r;
+}
+
+/**
+ * __fls - find last (most-significant) set bit in a long word
+ * @word: the word to search
+ *
+ * Undefined if no set bit exists, so code should check against 0 first.
+ */
+static inline unsigned long __fls(unsigned long word)
+{
+ int num = BITS_PER_LONG - 1;
+
+#if BITS_PER_LONG == 64
+ if (!(word & (~0ul << 32))) {
+ num -= 32;
+ word <<= 32;
+ }
+#endif
+ if (!(word & (~0ul << (BITS_PER_LONG-16)))) {
+ num -= 16;
+ word <<= 16;
+ }
+ if (!(word & (~0ul << (BITS_PER_LONG-8)))) {
+ num -= 8;
+ word <<= 8;
+ }
+ if (!(word & (~0ul << (BITS_PER_LONG-4)))) {
+ num -= 4;
+ word <<= 4;
+ }
+ if (!(word & (~0ul << (BITS_PER_LONG-2)))) {
+ num -= 2;
+ word <<= 2;
+ }
+ if (!(word & (~0ul << (BITS_PER_LONG-1))))
+ num -= 1;
+ return num;
+}
+
+#define for_each_set_bit(bit, addr, size) \
+ for ((bit) = find_first_bit((addr), (size)); \
+ (bit) < (size); \
+ (bit) = find_next_bit((addr), (size), (bit) + 1))
+
+/* same as for_each_set_bit() but use bit as value to start with */
+#define for_each_set_bit_from(bit, addr, size) \
+ for ((bit) = find_next_bit((addr), (size), (bit)); \
+ (bit) < (size); \
+ (bit) = find_next_bit((addr), (size), (bit) + 1))
+
+#define for_each_clear_bit(bit, addr, size) \
+ for ((bit) = find_first_zero_bit((addr), (size)); \
+ (bit) < (size); \
+ (bit) = find_next_zero_bit((addr), (size), (bit) + 1))
+
+/* same as for_each_clear_bit() but use bit as value to start with */
+#define for_each_clear_bit_from(bit, addr, size) \
+ for ((bit) = find_next_zero_bit((addr), (size), (bit)); \
+ (bit) < (size); \
+ (bit) = find_next_zero_bit((addr), (size), (bit) + 1))
+
+unsigned long find_first_bit(const unsigned long *addr,
+ unsigned long size);
+
+unsigned long find_first_zero_bit(const unsigned long *addr,
+ unsigned long size);
+
+unsigned long find_last_bit(const unsigned long *addr,
+ unsigned long size);
+
+unsigned long find_next_bit(const unsigned long *addr,
+ unsigned long size, unsigned long offset);
+
+unsigned long find_next_zero_bit(const unsigned long *addr,
+ unsigned long size,
+ unsigned long offset);
+
+/**
+ * __set_bit - Set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * This function is non-atomic and may be reordered.
+ */
+static inline void __set_bit(int nr, volatile unsigned long *addr)
+{
+ unsigned long mask = BIT_MASK(nr);
+ unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+ *p |= mask;
+}
+
+/**
+ * __clear_bit - Clear a bit in memory
+ * @nr: the bit to clear
+ * @addr: the address to start counting from
+ *
+ * This function is non-atomic and may be reordered.
+ */
+static inline void __clear_bit(int nr, volatile unsigned long *addr)
+{
+ unsigned long mask = BIT_MASK(nr);
+ unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+ *p &= ~mask;
+}
+
+/**
+ * __change_bit - Toggle a bit in memory
+ * @nr: the bit to change
+ * @addr: the address to start counting from
+ *
+ * This function is non-atomic and may be reordered.
+ */
+static inline void __change_bit(int nr, volatile unsigned long *addr)
+{
+ unsigned long mask = BIT_MASK(nr);
+ unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+ *p ^= mask;
+}
+
+/**
+ * __test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.
+ */
+static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
+{
+ unsigned long mask = BIT_MASK(nr);
+ unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+ unsigned long old = *p;
+
+ *p = old | mask;
+ return (old & mask) != 0;
+}
+
+/**
+ * __test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to clear
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.
+ */
+static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
+{
+ unsigned long mask = BIT_MASK(nr);
+ unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+ unsigned long old = *p;
+
+ *p = old & ~mask;
+ return (old & mask) != 0;
+}
+
+/**
+ * __test_bit - Determine whether a bit is set
+ * @nr: bit number to test
+ * @addr: Address to start counting from
+ *
+ * This operation is non-atomic and can be reordered.
+ */
+static inline int __test_bit(int nr, const volatile unsigned long *addr)
+{
+ return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
+}
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_console.h b/roms/opensbi/include/sbi/sbi_console.h
new file mode 100644
index 000000000..7d648f0b5
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_console.h
@@ -0,0 +1,39 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_CONSOLE_H__
+#define __SBI_CONSOLE_H__
+
+#include <sbi/sbi_types.h>
+
+#define __printf(a, b) __attribute__((format(printf, a, b)))
+
+bool sbi_isprintable(char ch);
+
+int sbi_getc(void);
+
+void sbi_putc(char ch);
+
+void sbi_puts(const char *str);
+
+void sbi_gets(char *s, int maxwidth, char endchar);
+
+int __printf(2, 3) sbi_sprintf(char *out, const char *format, ...);
+
+int __printf(3, 4) sbi_snprintf(char *out, u32 out_sz, const char *format, ...);
+
+int __printf(1, 2) sbi_printf(const char *format, ...);
+
+int __printf(1, 2) sbi_dprintf(const char *format, ...);
+
+struct sbi_scratch;
+
+int sbi_console_init(struct sbi_scratch *scratch);
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_const.h b/roms/opensbi/include/sbi/sbi_const.h
new file mode 100644
index 000000000..37866546a
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_const.h
@@ -0,0 +1,48 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_CONST_H__
+#define __SBI_CONST_H__
+
+/*
+ * Some constant macros are used in both assembler and
+ * C code. Therefore we cannot annotate them always with
+ * 'UL' and other type specifiers unilaterally. We
+ * use the following macros to deal with this.
+ *
+ * Similarly, _AT() will cast an expression with a type in C, but
+ * leave it unchanged in asm.
+ */
+
+/* clang-format off */
+
+#ifdef __ASSEMBLY__
+#define _AC(X,Y) X
+#define _AT(T,X) X
+#else
+#define __AC(X,Y) (X##Y)
+#define _AC(X,Y) __AC(X,Y)
+#define _AT(T,X) ((T)(X))
+#endif
+
+#define _UL(x) (_AC(x, UL))
+#define _ULL(x) (_AC(x, ULL))
+
+#define _BITUL(x) (_UL(1) << (x))
+#define _BITULL(x) (_ULL(1) << (x))
+
+#define UL(x) (_UL(x))
+#define ULL(x) (_ULL(x))
+
+#define __STR(s) #s
+#define STRINGIFY(s) __STR(s)
+
+/* clang-format on */
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_csr_detect.h b/roms/opensbi/include/sbi/sbi_csr_detect.h
new file mode 100644
index 000000000..f29488845
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_csr_detect.h
@@ -0,0 +1,50 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Atish Patra <atish.patra@wdc.com>
+ */
+
+#ifndef __SBI_CSR_DETECT__H
+#define __SBI_CSR_DETECT__H
+
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_hart.h>
+
+#define csr_read_allowed(csr_num, trap) \
+ ({ \
+ register ulong tinfo asm("a3") = (ulong)trap; \
+ register ulong ttmp asm("a4"); \
+ register ulong mtvec = sbi_hart_expected_trap_addr(); \
+ register ulong ret = 0; \
+ asm volatile( \
+ "add %[ttmp], %[tinfo], zero\n" \
+ "csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
+ "csrr %[ret], %[csr]\n" \
+ "csrw " STR(CSR_MTVEC) ", %[mtvec]" \
+ : [mtvec] "+&r"(mtvec), [tinfo] "+&r"(tinfo), \
+ [ttmp] "+&r"(ttmp), [ret] "=&r" (ret) \
+ : [csr] "i" (csr_num) \
+ : "memory"); \
+ ret; \
+ }) \
+
+#define csr_write_allowed(csr_num, trap, value) \
+ ({ \
+ register ulong tinfo asm("a3") = (ulong)trap; \
+ register ulong ttmp asm("a4"); \
+ register ulong mtvec = sbi_hart_expected_trap_addr(); \
+ asm volatile( \
+ "add %[ttmp], %[tinfo], zero\n" \
+ "csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
+ "csrw %[csr], %[val]\n" \
+ "csrw " STR(CSR_MTVEC) ", %[mtvec]" \
+ : [mtvec] "+&r"(mtvec), \
+ [tinfo] "+&r"(tinfo), [ttmp] "+&r"(ttmp) \
+ : [csr] "i" (csr_num), [val] "r" (value) \
+ : "memory"); \
+ }) \
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_domain.h b/roms/opensbi/include/sbi/sbi_domain.h
new file mode 100644
index 000000000..1f8b942c4
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_domain.h
@@ -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
diff --git a/roms/opensbi/include/sbi/sbi_ecall.h b/roms/opensbi/include/sbi/sbi_ecall.h
new file mode 100644
index 000000000..d35708544
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_ecall.h
@@ -0,0 +1,61 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_ECALL_H__
+#define __SBI_ECALL_H__
+
+#include <sbi/sbi_types.h>
+#include <sbi/sbi_list.h>
+
+#define SBI_ECALL_VERSION_MAJOR 0
+#define SBI_ECALL_VERSION_MINOR 2
+#define SBI_OPENSBI_IMPID 1
+
+struct sbi_trap_regs;
+struct sbi_trap_info;
+
+struct sbi_ecall_extension {
+ struct sbi_dlist head;
+ unsigned long extid_start;
+ unsigned long extid_end;
+ int (* probe)(unsigned long extid, unsigned long *out_val);
+ int (* handle)(unsigned long extid, unsigned long funcid,
+ const struct sbi_trap_regs *regs,
+ unsigned long *out_val,
+ struct sbi_trap_info *out_trap);
+};
+
+extern struct sbi_ecall_extension ecall_base;
+extern struct sbi_ecall_extension ecall_legacy;
+extern struct sbi_ecall_extension ecall_time;
+extern struct sbi_ecall_extension ecall_rfence;
+extern struct sbi_ecall_extension ecall_ipi;
+extern struct sbi_ecall_extension ecall_vendor;
+extern struct sbi_ecall_extension ecall_hsm;
+extern struct sbi_ecall_extension ecall_srst;
+
+u16 sbi_ecall_version_major(void);
+
+u16 sbi_ecall_version_minor(void);
+
+unsigned long sbi_ecall_get_impid(void);
+
+void sbi_ecall_set_impid(unsigned long impid);
+
+struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid);
+
+int sbi_ecall_register_extension(struct sbi_ecall_extension *ext);
+
+void sbi_ecall_unregister_extension(struct sbi_ecall_extension *ext);
+
+int sbi_ecall_handler(struct sbi_trap_regs *regs);
+
+int sbi_ecall_init(void);
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_ecall_interface.h b/roms/opensbi/include/sbi/sbi_ecall_interface.h
new file mode 100644
index 000000000..002c6f9cb
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_ecall_interface.h
@@ -0,0 +1,98 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_ECALL_INTERFACE_H__
+#define __SBI_ECALL_INTERFACE_H__
+
+/* clang-format off */
+
+/* SBI Extension IDs */
+#define SBI_EXT_0_1_SET_TIMER 0x0
+#define SBI_EXT_0_1_CONSOLE_PUTCHAR 0x1
+#define SBI_EXT_0_1_CONSOLE_GETCHAR 0x2
+#define SBI_EXT_0_1_CLEAR_IPI 0x3
+#define SBI_EXT_0_1_SEND_IPI 0x4
+#define SBI_EXT_0_1_REMOTE_FENCE_I 0x5
+#define SBI_EXT_0_1_REMOTE_SFENCE_VMA 0x6
+#define SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID 0x7
+#define SBI_EXT_0_1_SHUTDOWN 0x8
+#define SBI_EXT_BASE 0x10
+#define SBI_EXT_TIME 0x54494D45
+#define SBI_EXT_IPI 0x735049
+#define SBI_EXT_RFENCE 0x52464E43
+#define SBI_EXT_HSM 0x48534D
+#define SBI_EXT_SRST 0x53525354
+
+/* SBI function IDs for BASE extension*/
+#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
+#define SBI_EXT_BASE_GET_IMP_ID 0x1
+#define SBI_EXT_BASE_GET_IMP_VERSION 0x2
+#define SBI_EXT_BASE_PROBE_EXT 0x3
+#define SBI_EXT_BASE_GET_MVENDORID 0x4
+#define SBI_EXT_BASE_GET_MARCHID 0x5
+#define SBI_EXT_BASE_GET_MIMPID 0x6
+
+/* SBI function IDs for TIME extension*/
+#define SBI_EXT_TIME_SET_TIMER 0x0
+
+/* SBI function IDs for IPI extension*/
+#define SBI_EXT_IPI_SEND_IPI 0x0
+
+/* SBI function IDs for RFENCE extension*/
+#define SBI_EXT_RFENCE_REMOTE_FENCE_I 0x0
+#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA 0x1
+#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID 0x2
+#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA 0x3
+#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID 0x4
+#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA 0x5
+#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID 0x6
+
+/* SBI function IDs for HSM extension */
+#define SBI_EXT_HSM_HART_START 0x0
+#define SBI_EXT_HSM_HART_STOP 0x1
+#define SBI_EXT_HSM_HART_GET_STATUS 0x2
+
+#define SBI_HSM_HART_STATUS_STARTED 0x0
+#define SBI_HSM_HART_STATUS_STOPPED 0x1
+#define SBI_HSM_HART_STATUS_START_PENDING 0x2
+#define SBI_HSM_HART_STATUS_STOP_PENDING 0x3
+
+/* 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
+#define SBI_EXT_VENDOR_START 0x09000000
+#define SBI_EXT_VENDOR_END 0x09FFFFFF
+#define SBI_EXT_FIRMWARE_START 0x0A000000
+#define SBI_EXT_FIRMWARE_END 0x0AFFFFFF
+
+/* SBI return error codes */
+#define SBI_SUCCESS 0
+#define SBI_ERR_FAILED -1
+#define SBI_ERR_NOT_SUPPORTED -2
+#define SBI_ERR_INVALID_PARAM -3
+#define SBI_ERR_DENIED -4
+#define SBI_ERR_INVALID_ADDRESS -5
+#define SBI_ERR_ALREADY_AVAILABLE -6
+
+#define SBI_LAST_ERR SBI_ERR_ALREADY_AVAILABLE
+
+/* clang-format on */
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_emulate_csr.h b/roms/opensbi/include/sbi/sbi_emulate_csr.h
new file mode 100644
index 000000000..548056a11
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_emulate_csr.h
@@ -0,0 +1,23 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_EMULATE_CSR_H__
+#define __SBI_EMULATE_CSR_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_trap_regs;
+
+int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs,
+ ulong *csr_val);
+
+int sbi_emulate_csr_write(int csr_num, struct sbi_trap_regs *regs,
+ ulong csr_val);
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_error.h b/roms/opensbi/include/sbi/sbi_error.h
new file mode 100644
index 000000000..3655d1220
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_error.h
@@ -0,0 +1,38 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_ERROR_H__
+#define __SBI_ERROR_H__
+
+#include <sbi/sbi_ecall_interface.h>
+
+/* clang-format off */
+
+#define SBI_OK 0
+#define SBI_EFAIL SBI_ERR_FAILED
+#define SBI_ENOTSUPP SBI_ERR_NOT_SUPPORTED
+#define SBI_EINVAL SBI_ERR_INVALID_PARAM
+#define SBI_EDENIED SBI_ERR_DENIED
+#define SBI_EINVALID_ADDR SBI_ERR_INVALID_ADDRESS
+#define SBI_EALREADY SBI_ERR_ALREADY_AVAILABLE
+
+#define SBI_ENODEV -1000
+#define SBI_ENOSYS -1001
+#define SBI_ETIMEDOUT -1002
+#define SBI_EIO -1003
+#define SBI_EILL -1004
+#define SBI_ENOSPC -1005
+#define SBI_ENOMEM -1006
+#define SBI_ETRAP -1007
+#define SBI_EUNKNOWN -1008
+#define SBI_ENOENT -1009
+
+/* clang-format on */
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_fifo.h b/roms/opensbi/include/sbi/sbi_fifo.h
new file mode 100644
index 000000000..bc8f8f600
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_fifo.h
@@ -0,0 +1,42 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Atish Patra<atish.patra@wdc.com>
+ *
+ */
+
+#ifndef __SBI_FIFO_H__
+#define __SBI_FIFO_H__
+
+#include <sbi/riscv_locks.h>
+#include <sbi/sbi_types.h>
+
+struct sbi_fifo {
+ void *queue;
+ spinlock_t qlock;
+ u16 entry_size;
+ u16 num_entries;
+ u16 avail;
+ u16 tail;
+};
+
+enum sbi_fifo_inplace_update_types {
+ SBI_FIFO_SKIP,
+ SBI_FIFO_UPDATED,
+ SBI_FIFO_UNCHANGED,
+};
+
+int sbi_fifo_dequeue(struct sbi_fifo *fifo, void *data);
+int sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data);
+void sbi_fifo_init(struct sbi_fifo *fifo, void *queue_mem, u16 entries,
+ u16 entry_size);
+bool sbi_fifo_is_empty(struct sbi_fifo *fifo);
+bool sbi_fifo_is_full(struct sbi_fifo *fifo);
+int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
+ int (*fptr)(void *in, void *data));
+u16 sbi_fifo_avail(struct sbi_fifo *fifo);
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_hart.h b/roms/opensbi/include/sbi/sbi_hart.h
new file mode 100644
index 000000000..ec9e30f91
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_hart.h
@@ -0,0 +1,56 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_HART_H__
+#define __SBI_HART_H__
+
+#include <sbi/sbi_types.h>
+
+/** Possible feature flags of a hart */
+enum sbi_hart_features {
+ /** Hart has S-mode counter enable */
+ SBI_HART_HAS_SCOUNTEREN = (1 << 0),
+ /** Hart has M-mode counter enable */
+ SBI_HART_HAS_MCOUNTEREN = (1 << 1),
+ /** HART has timer csr implementation in hardware */
+ SBI_HART_HAS_TIME = (1 << 2),
+
+ /** Last index of Hart features*/
+ SBI_HART_HAS_LAST_FEATURE = SBI_HART_HAS_TIME,
+};
+
+struct sbi_scratch;
+
+int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot);
+
+extern void (*sbi_hart_expected_trap)(void);
+static inline ulong sbi_hart_expected_trap_addr(void)
+{
+ return (ulong)sbi_hart_expected_trap;
+}
+
+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);
+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);
+
+void __attribute__((noreturn)) sbi_hart_hang(void);
+
+void __attribute__((noreturn))
+sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
+ unsigned long next_addr, unsigned long next_mode,
+ bool next_virt);
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_hartmask.h b/roms/opensbi/include/sbi/sbi_hartmask.h
new file mode 100644
index 000000000..f1cef0c2a
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_hartmask.h
@@ -0,0 +1,141 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_HARTMASK_H__
+#define __SBI_HARTMASK_H__
+
+#include <sbi/sbi_bitmap.h>
+
+/**
+ * Maximum number of bits in a hartmask
+ *
+ * The hartmask is indexed using physical HART id so this define
+ * also represents the maximum number of HART ids generic OpenSBI
+ * can handle.
+ */
+#define SBI_HARTMASK_MAX_BITS 128
+
+/** Representation of hartmask */
+struct sbi_hartmask {
+ DECLARE_BITMAP(bits, SBI_HARTMASK_MAX_BITS);
+};
+
+/** Initialize hartmask to zero */
+#define SBI_HARTMASK_INIT(__m) \
+ bitmap_zero(((__m)->bits), SBI_HARTMASK_MAX_BITS)
+
+/** Initialize hartmask to zero except a particular HART id */
+#define SBI_HARTMASK_INIT_EXCEPT(__m, __h) \
+ bitmap_zero_except(((__m)->bits), (__h), SBI_HARTMASK_MAX_BITS)
+
+/**
+ * Get underlying bitmap of hartmask
+ * @param m the hartmask pointer
+ */
+#define sbi_hartmask_bits(__m) ((__m)->bits)
+
+/**
+ * Set a HART in hartmask
+ * @param h HART id to set
+ * @param m the hartmask pointer
+ */
+static inline void sbi_hartmask_set_hart(u32 h, struct sbi_hartmask *m)
+{
+ if (h < SBI_HARTMASK_MAX_BITS)
+ __set_bit(h, m->bits);
+}
+
+/**
+ * Clear a HART in hartmask
+ * @param h HART id to clear
+ * @param m the hartmask pointer
+ */
+static inline void sbi_hartmask_clear_hart(u32 h, struct sbi_hartmask *m)
+{
+ if (h < SBI_HARTMASK_MAX_BITS)
+ __clear_bit(h, m->bits);
+}
+
+/**
+ * Test a HART in hartmask
+ * @param h HART id to test
+ * @param m the hartmask pointer
+ */
+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);
+ return 0;
+}
+
+/**
+ * Set all HARTs in a hartmask
+ * @param dstp the hartmask pointer
+ */
+static inline void sbi_hartmask_set_all(struct sbi_hartmask *dstp)
+{
+ bitmap_fill(sbi_hartmask_bits(dstp), SBI_HARTMASK_MAX_BITS);
+}
+
+/**
+ * Clear all HARTs in a hartmask
+ * @param dstp the hartmask pointer
+ */
+static inline void sbi_hartmask_clear_all(struct sbi_hartmask *dstp)
+{
+ bitmap_zero(sbi_hartmask_bits(dstp), SBI_HARTMASK_MAX_BITS);
+}
+
+/**
+ * *dstp = *src1p & *src2p
+ * @param dstp the hartmask result
+ * @param src1p the first input
+ * @param src2p the second input
+ */
+static inline void sbi_hartmask_and(struct sbi_hartmask *dstp,
+ const struct sbi_hartmask *src1p,
+ const struct sbi_hartmask *src2p)
+{
+ bitmap_and(sbi_hartmask_bits(dstp), sbi_hartmask_bits(src1p),
+ sbi_hartmask_bits(src2p), SBI_HARTMASK_MAX_BITS);
+}
+
+/**
+ * *dstp = *src1p | *src2p
+ * @param dstp the hartmask result
+ * @param src1p the first input
+ * @param src2p the second input
+ */
+static inline void sbi_hartmask_or(struct sbi_hartmask *dstp,
+ const struct sbi_hartmask *src1p,
+ const struct sbi_hartmask *src2p)
+{
+ bitmap_or(sbi_hartmask_bits(dstp), sbi_hartmask_bits(src1p),
+ sbi_hartmask_bits(src2p), SBI_HARTMASK_MAX_BITS);
+}
+
+/**
+ * *dstp = *src1p ^ *src2p
+ * @param dstp the hartmask result
+ * @param src1p the first input
+ * @param src2p the second input
+ */
+static inline void sbi_hartmask_xor(struct sbi_hartmask *dstp,
+ const struct sbi_hartmask *src1p,
+ const struct sbi_hartmask *src2p)
+{
+ bitmap_xor(sbi_hartmask_bits(dstp), sbi_hartmask_bits(src1p),
+ sbi_hartmask_bits(src2p), SBI_HARTMASK_MAX_BITS);
+}
+
+/** Iterate over each HART in hartmask */
+#define sbi_hartmask_for_each_hart(__h, __m) \
+ for_each_set_bit(__h, (__m)->bits, SBI_HARTMASK_MAX_BITS)
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_hfence.h b/roms/opensbi/include/sbi/sbi_hfence.h
new file mode 100644
index 000000000..4420f2793
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_hfence.h
@@ -0,0 +1,38 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Atish Patra <atish.patra@wdc.com>
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_FENCE_H__
+#define __SBI_FENCE_H__
+
+/** Invalidate Stage2 TLBs for given VMID and guest physical address */
+void __sbi_hfence_gvma_vmid_gpa(unsigned long gpa, unsigned long vmid);
+
+/** Invalidate Stage2 TLBs for given VMID */
+void __sbi_hfence_gvma_vmid(unsigned long vmid);
+
+/** Invalidate Stage2 TLBs for given guest physical address */
+void __sbi_hfence_gvma_gpa(unsigned long gpa);
+
+/** Invalidate all possible Stage2 TLBs */
+void __sbi_hfence_gvma_all(void);
+
+/** Invalidate unified TLB entries for given asid and guest virtual address */
+void __sbi_hfence_vvma_asid_va(unsigned long va, unsigned long asid);
+
+/** Invalidate unified TLB entries for given ASID for a guest*/
+void __sbi_hfence_vvma_asid(unsigned long asid);
+
+/** Invalidate unified TLB entries for a given guest virtual address */
+void __sbi_hfence_vvma_va(unsigned long va);
+
+/** Invalidate all possible Stage2 TLBs */
+void __sbi_hfence_vvma_all(void);
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_hsm.h b/roms/opensbi/include/sbi/sbi_hsm.h
new file mode 100644
index 000000000..482338309
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_hsm.h
@@ -0,0 +1,38 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Atish Patra <atish.patra@wdc.com>
+ */
+
+#ifndef __SBI_HSM_H__
+#define __SBI_HSM_H__
+
+#include <sbi/sbi_types.h>
+
+/** Hart state values **/
+#define SBI_HART_STOPPED 0
+#define SBI_HART_STOPPING 1
+#define SBI_HART_STARTING 2
+#define SBI_HART_STARTED 3
+#define SBI_HART_UNKNOWN 4
+
+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,
+ 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(const struct sbi_domain *dom, u32 hartid);
+int sbi_hsm_hart_state_to_status(int state);
+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
diff --git a/roms/opensbi/include/sbi/sbi_illegal_insn.h b/roms/opensbi/include/sbi/sbi_illegal_insn.h
new file mode 100644
index 000000000..0397935e2
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_illegal_insn.h
@@ -0,0 +1,19 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_ILLEGAl_INSN_H__
+#define __SBI_ILLEGAl_INSN_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_trap_regs;
+
+int sbi_illegal_insn_handler(ulong insn, struct sbi_trap_regs *regs);
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_init.h b/roms/opensbi/include/sbi/sbi_init.h
new file mode 100644
index 000000000..74eb1c075
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_init.h
@@ -0,0 +1,23 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_INIT_H__
+#define __SBI_INIT_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_scratch;
+
+void __noreturn sbi_init(struct sbi_scratch *scratch);
+
+unsigned long sbi_init_count(u32 hartid);
+
+void __noreturn sbi_exit(struct sbi_scratch *scratch);
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_ipi.h b/roms/opensbi/include/sbi/sbi_ipi.h
new file mode 100644
index 000000000..617872c1b
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_ipi.h
@@ -0,0 +1,70 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_IPI_H__
+#define __SBI_IPI_H__
+
+#include <sbi/sbi_types.h>
+
+/* clang-format off */
+
+#define SBI_IPI_EVENT_MAX __riscv_xlen
+
+/* clang-format on */
+
+struct sbi_scratch;
+
+/** IPI event operations or callbacks */
+struct sbi_ipi_event_ops {
+ /** Name of the IPI event operations */
+ char name[32];
+
+ /**
+ * Update callback to save/enqueue data for remote HART
+ * Note: This is an optional callback and it is called just before
+ * triggering IPI to remote HART.
+ */
+ int (* update)(struct sbi_scratch *scratch,
+ struct sbi_scratch *remote_scratch,
+ u32 remote_hartid, void *data);
+
+ /**
+ * Sync callback to wait for remote HART
+ * Note: This is an optional callback and it is called just after
+ * triggering IPI to remote HART.
+ */
+ void (* sync)(struct sbi_scratch *scratch);
+
+ /**
+ * Process callback to handle IPI event
+ * Note: This is a mandatory callback and it is called on the
+ * remote HART after IPI is triggered.
+ */
+ void (* process)(struct sbi_scratch *scratch);
+};
+
+int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data);
+
+int sbi_ipi_event_create(const struct sbi_ipi_event_ops *ops);
+
+void sbi_ipi_event_destroy(u32 event);
+
+int sbi_ipi_send_smode(ulong hmask, ulong hbase);
+
+void sbi_ipi_clear_smode(void);
+
+int sbi_ipi_send_halt(ulong hmask, ulong hbase);
+
+void sbi_ipi_process(void);
+
+int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot);
+
+void sbi_ipi_exit(struct sbi_scratch *scratch);
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_list.h b/roms/opensbi/include/sbi/sbi_list.h
new file mode 100644
index 000000000..1174ad274
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_list.h
@@ -0,0 +1,152 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Simple doubly-linked list library.
+ *
+ * Adapted from Xvisor source file libs/include/libs/list.h
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_LIST_H__
+#define __SBI_LIST_H__
+
+#include <sbi/sbi_types.h>
+
+#define SBI_LIST_POISON_PREV 0xDEADBEEF
+#define SBI_LIST_POISON_NEXT 0xFADEBABE
+
+struct sbi_dlist {
+ struct sbi_dlist *next, *prev;
+};
+
+#define SBI_LIST_HEAD_INIT(__lname) { &(__lname), &(__lname) }
+
+#define SBI_LIST_HEAD(_lname) \
+struct sbi_dlist _lname = SBI_LIST_HEAD_INIT(_lname)
+
+#define SBI_INIT_LIST_HEAD(ptr) \
+do { \
+ (ptr)->next = ptr; (ptr)->prev = ptr; \
+} while (0);
+
+static inline void __sbi_list_add(struct sbi_dlist *new,
+ struct sbi_dlist *prev,
+ struct sbi_dlist *next)
+{
+ new->prev = prev;
+ new->next = next;
+ prev->next = new;
+ next->prev = new;
+}
+
+/**
+ * Adds the new node after the given head.
+ * @param new New node that needs to be added to list.
+ * @param head List head after which the "new" node should be added.
+ * Note: the new node is added after the head.
+ */
+static inline void sbi_list_add(struct sbi_dlist *new, struct sbi_dlist *head)
+{
+ __sbi_list_add(new, head, head->next);
+}
+
+/**
+ * Adds a node at the tail where tnode points to tail node.
+ * @param new The new node to be added before tail.
+ * @param tnode The current tail node.
+ * Note: the new node is added before tail node.
+ */
+static inline void sbi_list_add_tail(struct sbi_dlist *new,
+ struct sbi_dlist *tnode)
+{
+ __sbi_list_add(new, tnode->prev, tnode);
+}
+
+static inline void __sbi_list_del(struct sbi_dlist *prev,
+ struct sbi_dlist *next)
+{
+ prev->next = next;
+ next->prev = prev;
+}
+
+static inline void __sbi_list_del_entry(struct sbi_dlist *entry)
+{
+ __sbi_list_del(entry->prev, entry->next);
+}
+
+/**
+ * Deletes a given entry from list.
+ * @param node Node to be deleted.
+ */
+static inline void sbi_list_del(struct sbi_dlist *entry)
+{
+ __sbi_list_del(entry->prev, entry->next);
+ entry->next = (void *)SBI_LIST_POISON_NEXT;
+ entry->prev = (void *)SBI_LIST_POISON_PREV;
+}
+
+/**
+ * Deletes entry from list and reinitialize it.
+ * @param entry the element to delete from the list.
+ */
+static inline void sbi_list_del_init(struct sbi_dlist *entry)
+{
+ __sbi_list_del_entry(entry);
+ SBI_INIT_LIST_HEAD(entry);
+}
+
+/**
+ * Get the struct for this entry
+ * @param ptr the &struct list_head pointer.
+ * @param type the type of the struct this is embedded in.
+ * @param member the name of the list_struct within the struct.
+ */
+#define sbi_list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * Get the first element from a list
+ * @param ptr the list head to take the element from.
+ * @param type the type of the struct this is embedded in.
+ * @param member the name of the list_struct within the struct.
+ *
+ * Note: that list is expected to be not empty.
+ */
+#define sbi_list_first_entry(ptr, type, member) \
+ sbi_list_entry((ptr)->next, type, member)
+
+/**
+ * Get the last element from a list
+ * @param ptr the list head to take the element from.
+ * @param type the type of the struct this is embedded in.
+ * @param member the name of the list_head within the struct.
+ *
+ * Note: that list is expected to be not empty.
+ */
+#define sbi_list_last_entry(ptr, type, member) \
+ sbi_list_entry((ptr)->prev, type, member)
+
+/**
+ * Iterate over a list
+ * @param pos the &struct list_head to use as a loop cursor.
+ * @param head the head for your list.
+ */
+#define sbi_list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * Iterate over list of given type
+ * @param pos the type * to use as a loop cursor.
+ * @param head the head for your list.
+ * @param member the name of the list_struct within the struct.
+ */
+#define sbi_list_for_each_entry(pos, head, member) \
+ for (pos = sbi_list_entry((head)->next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = sbi_list_entry(pos->member.next, typeof(*pos), member))
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_math.h b/roms/opensbi/include/sbi/sbi_math.h
new file mode 100644
index 000000000..564fd585c
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_math.h
@@ -0,0 +1,15 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Atish Patra <atish.patra@wdc.com>
+ */
+
+#ifndef __SBI_MATH_H__
+#define __SBI_MATH_H__
+
+unsigned long log2roundup(unsigned long x);
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_misaligned_ldst.h b/roms/opensbi/include/sbi/sbi_misaligned_ldst.h
new file mode 100644
index 000000000..ab27eb422
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_misaligned_ldst.h
@@ -0,0 +1,23 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_MISALIGNED_LDST_H__
+#define __SBI_MISALIGNED_LDST_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_trap_regs;
+
+int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
+ struct sbi_trap_regs *regs);
+
+int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
+ struct sbi_trap_regs *regs);
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_platform.h b/roms/opensbi/include/sbi/sbi_platform.h
new file mode 100644
index 000000000..cc7e3ff99
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_platform.h
@@ -0,0 +1,757 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_PLATFORM_H__
+#define __SBI_PLATFORM_H__
+
+/**
+ * OpenSBI 32-bit platform version with:
+ * 1. upper 16-bits as major number
+ * 2. lower 16-bits as minor number
+ */
+#define SBI_PLATFORM_VERSION(Major, Minor) ((Major << 16) | Minor)
+
+/** Offset of opensbi_version in struct sbi_platform */
+#define SBI_PLATFORM_OPENSBI_VERSION_OFFSET (0x00)
+/** Offset of platform_version in struct sbi_platform */
+#define SBI_PLATFORM_VERSION_OFFSET (0x04)
+/** Offset of name in struct sbi_platform */
+#define SBI_PLATFORM_NAME_OFFSET (0x08)
+/** Offset of features in struct sbi_platform */
+#define SBI_PLATFORM_FEATURES_OFFSET (0x48)
+/** Offset of hart_count in struct sbi_platform */
+#define SBI_PLATFORM_HART_COUNT_OFFSET (0x50)
+/** Offset of hart_stack_size in struct sbi_platform */
+#define SBI_PLATFORM_HART_STACK_SIZE_OFFSET (0x54)
+/** Offset of platform_ops_addr in struct sbi_platform */
+#define SBI_PLATFORM_OPS_OFFSET (0x58)
+/** Offset of firmware_context in struct sbi_platform */
+#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x58 + __SIZEOF_POINTER__)
+/** Offset of hart_index2id in struct sbi_platform */
+#define SBI_PLATFORM_HART_INDEX2ID_OFFSET (0x58 + (__SIZEOF_POINTER__ * 2))
+
+#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT (1UL << 12)
+
+#ifndef __ASSEMBLY__
+
+#include <sbi/sbi_ecall_interface.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_scratch.h>
+#include <sbi/sbi_version.h>
+
+struct sbi_domain_memregion;
+struct sbi_trap_info;
+struct sbi_trap_regs;
+
+/** Possible feature flags of a platform */
+enum sbi_platform_features {
+ /** Platform has timer value */
+ SBI_PLATFORM_HAS_TIMER_VALUE = (1 << 0),
+ /** Platform has HART hotplug support */
+ SBI_PLATFORM_HAS_HART_HOTPLUG = (1 << 1),
+ /** Platform has fault delegation support */
+ SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 2),
+ /** Platform has custom secondary hart booting support */
+ SBI_PLATFORM_HAS_HART_SECONDARY_BOOT = (1 << 3),
+
+ /** Last index of Platform features*/
+ SBI_PLATFORM_HAS_LAST_FEATURE = SBI_PLATFORM_HAS_HART_SECONDARY_BOOT,
+};
+
+/** Default feature set for a platform */
+#define SBI_PLATFORM_DEFAULT_FEATURES \
+ (SBI_PLATFORM_HAS_TIMER_VALUE | SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
+
+/** Platform functions */
+struct sbi_platform_operations {
+ /** Platform early initialization */
+ int (*early_init)(bool cold_boot);
+ /** Platform final initialization */
+ int (*final_init)(bool cold_boot);
+
+ /** Platform early exit */
+ void (*early_exit)(void);
+ /** Platform final exit */
+ void (*final_exit)(void);
+
+ /**
+ * For platforms that do not implement misa, non-standard
+ * methods are needed to determine cpu extension.
+ */
+ int (*misa_check_extension)(char ext);
+
+ /**
+ * For platforms that do not implement misa, non-standard
+ * methods are needed to get MXL field of misa.
+ */
+ int (*misa_get_xlen)(void);
+
+ /** Get 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);
+ /** Read a character from the platform console input */
+ int (*console_getc)(void);
+ /** Initialize the platform console */
+ int (*console_init)(void);
+
+ /** Initialize the platform interrupt controller for current HART */
+ int (*irqchip_init)(bool cold_boot);
+ /** Exit the platform interrupt controller for current HART */
+ void (*irqchip_exit)(void);
+
+ /** Send IPI to a target HART */
+ void (*ipi_send)(u32 target_hart);
+ /** Clear IPI for a target HART */
+ void (*ipi_clear)(u32 target_hart);
+ /** Initialize IPI for current HART */
+ int (*ipi_init)(bool cold_boot);
+ /** Exit IPI for current HART */
+ void (*ipi_exit)(void);
+
+ /** Get tlb flush limit value **/
+ u64 (*get_tlbr_flush_limit)(void);
+
+ /** Get platform timer value */
+ u64 (*timer_value)(void);
+ /** Start platform timer event for current HART */
+ void (*timer_event_start)(u64 next_event);
+ /** Stop platform timer event for current HART */
+ void (*timer_event_stop)(void);
+ /** Initialize platform timer for current HART */
+ int (*timer_init)(bool cold_boot);
+ /** Exit platform timer for current HART */
+ void (*timer_exit)(void);
+
+ /** Bringup the given hart */
+ int (*hart_start)(u32 hartid, ulong saddr);
+ /**
+ * Stop the current hart from running. This call doesn't expect to
+ * return if success.
+ */
+ int (*hart_stop)(void);
+
+ /* Check whether reset type and reason supported by the platform */
+ int (*system_reset_check)(u32 reset_type, u32 reset_reason);
+ /** Reset the platform */
+ 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,
+ const struct sbi_trap_regs *regs,
+ unsigned long *out_value,
+ struct sbi_trap_info *out_trap);
+};
+
+/** Platform default per-HART stack size for exception/interrupt handling */
+#define SBI_PLATFORM_DEFAULT_HART_STACK_SIZE 8192
+
+/** Representation of a platform */
+struct sbi_platform {
+ /**
+ * OpenSBI version this sbi_platform is based on.
+ * It's a 32-bit value where upper 16-bits are major number
+ * and lower 16-bits are minor number
+ */
+ u32 opensbi_version;
+ /**
+ * OpenSBI platform version released by vendor.
+ * It's a 32-bit value where upper 16-bits are major number
+ * and lower 16-bits are minor number
+ */
+ u32 platform_version;
+ /** Name of the platform */
+ char name[64];
+ /** Supported features */
+ u64 features;
+ /** Total number of HARTs */
+ u32 hart_count;
+ /** Per-HART stack size for exception/interrupt handling */
+ u32 hart_stack_size;
+ /** Pointer to sbi platform operations */
+ unsigned long platform_ops_addr;
+ /** Pointer to system firmware specific context */
+ unsigned long firmware_context;
+ /**
+ * HART index to HART id table
+ *
+ * For used HART index <abc>:
+ * hart_index2id[<abc>] = some HART id
+ * For unused HART index <abc>:
+ * hart_index2id[<abc>] = -1U
+ *
+ * If hart_index2id == NULL then we assume identity mapping
+ * hart_index2id[<abc>] = <abc>
+ *
+ * We have only two restrictions:
+ * 1. HART index < sbi_platform hart_count
+ * 2. HART id < SBI_HARTMASK_MAX_BITS
+ */
+ const u32 *hart_index2id;
+};
+
+/** Get pointer to sbi_platform for sbi_scratch pointer */
+#define sbi_platform_ptr(__s) \
+ ((const struct sbi_platform *)((__s)->platform_addr))
+/** Get pointer to sbi_platform for current HART */
+#define sbi_platform_thishart_ptr() ((const struct sbi_platform *) \
+ (sbi_scratch_thishart_ptr()->platform_addr))
+/** Get pointer to platform_ops_addr from platform pointer **/
+#define sbi_platform_ops(__p) \
+ ((const struct sbi_platform_operations *)(__p)->platform_ops_addr)
+
+/** Check whether the platform supports timer value */
+#define sbi_platform_has_timer_value(__p) \
+ ((__p)->features & SBI_PLATFORM_HAS_TIMER_VALUE)
+/** Check whether the platform supports HART hotplug */
+#define sbi_platform_has_hart_hotplug(__p) \
+ ((__p)->features & SBI_PLATFORM_HAS_HART_HOTPLUG)
+/** Check whether the platform supports fault delegation */
+#define sbi_platform_has_mfaults_delegation(__p) \
+ ((__p)->features & SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
+/** Check whether the platform supports custom secondary hart booting support */
+#define sbi_platform_has_hart_secondary_boot(__p) \
+ ((__p)->features & SBI_PLATFORM_HAS_HART_SECONDARY_BOOT)
+
+/**
+ * Get HART index for the given HART
+ *
+ * @param plat pointer to struct sbi_platform
+ * @param hartid HART ID
+ *
+ * @return 0 <= value < hart_count for valid HART otherwise -1U
+ */
+u32 sbi_platform_hart_index(const struct sbi_platform *plat, u32 hartid);
+
+/**
+ * Get the platform features in string format
+ *
+ * @param plat pointer to struct sbi_platform
+ * @param features_str pointer to a char array where the features string will be
+ * updated
+ * @param nfstr length of the features_str. The feature string will be truncated
+ * if nfstr is not long enough.
+ */
+void sbi_platform_get_features_str(const struct sbi_platform *plat,
+ char *features_str, int nfstr);
+
+/**
+ * Get name of the platform
+ *
+ * @param plat pointer to struct sbi_platform
+ *
+ * @return pointer to platform name on success and "Unknown" on failure
+ */
+static inline const char *sbi_platform_name(const struct sbi_platform *plat)
+{
+ if (plat)
+ return plat->name;
+ return "Unknown";
+}
+
+/**
+ * Get the platform features
+ *
+ * @param plat pointer to struct sbi_platform
+ *
+ * @return the features value currently set for the given platform
+ */
+static inline unsigned long sbi_platform_get_features(
+ const struct sbi_platform *plat)
+{
+ if (plat)
+ return plat->features;
+ return 0;
+}
+
+/**
+ * Get platform specific tlb range flush maximum value. Any request with size
+ * higher than this is upgraded to a full flush.
+ *
+ * @param plat pointer to struct sbi_platform
+ *
+ * @return tlb range flush limit value. Returns a default (page size) if not
+ * defined by platform.
+ */
+static inline u64 sbi_platform_tlbr_flush_limit(const struct sbi_platform *plat)
+{
+ if (plat && sbi_platform_ops(plat)->get_tlbr_flush_limit)
+ return sbi_platform_ops(plat)->get_tlbr_flush_limit();
+ return SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT;
+}
+
+/**
+ * Get total number of HARTs supported by the platform
+ *
+ * @param plat pointer to struct sbi_platform
+ *
+ * @return total number of HARTs
+ */
+static inline u32 sbi_platform_hart_count(const struct sbi_platform *plat)
+{
+ if (plat)
+ return plat->hart_count;
+ return 0;
+}
+
+/**
+ * Get per-HART stack size for exception/interrupt handling
+ *
+ * @param plat pointer to struct sbi_platform
+ *
+ * @return stack size in bytes
+ */
+static inline u32 sbi_platform_hart_stack_size(const struct sbi_platform *plat)
+{
+ if (plat)
+ return plat->hart_stack_size;
+ return 0;
+}
+
+/**
+ * Check whether given HART is invalid
+ *
+ * @param plat pointer to struct sbi_platform
+ * @param hartid HART ID
+ *
+ * @return TRUE if HART is invalid and FALSE otherwise
+ */
+static inline bool sbi_platform_hart_invalid(const struct sbi_platform *plat,
+ u32 hartid)
+{
+ if (!plat)
+ return TRUE;
+ if (plat->hart_count <= sbi_platform_hart_index(plat, hartid))
+ return TRUE;
+ return FALSE;
+}
+
+/**
+ * Bringup a given hart from previous stage. Platform should implement this
+ * operation if they support a custom mechanism to start a hart. Otherwise,
+ * a generic WFI based approach will be used to start/stop a hart in OpenSBI.
+ *
+ * @param plat pointer to struct sbi_platform
+ * @param hartid HART id
+ * @param saddr M-mode start physical address for the HART
+ *
+ * @return 0 if sucessful and negative error code on failure
+ */
+static inline int sbi_platform_hart_start(const struct sbi_platform *plat,
+ u32 hartid, ulong saddr)
+{
+ if (plat && sbi_platform_ops(plat)->hart_start)
+ return sbi_platform_ops(plat)->hart_start(hartid, saddr);
+ return SBI_ENOTSUPP;
+}
+
+/**
+ * Stop the current hart in OpenSBI.
+ *
+ * @param plat pointer to struct sbi_platform
+ *
+ * @return Negative error code on failure. It doesn't return on success.
+ */
+static inline int sbi_platform_hart_stop(const struct sbi_platform *plat)
+{
+ if (plat && sbi_platform_ops(plat)->hart_stop)
+ return sbi_platform_ops(plat)->hart_stop();
+ return SBI_ENOTSUPP;
+}
+
+/**
+ * Early initialization for current HART
+ *
+ * @param plat pointer to struct sbi_platform
+ * @param cold_boot whether cold boot (TRUE) or warm_boot (FALSE)
+ *
+ * @return 0 on success and negative error code on failure
+ */
+static inline int sbi_platform_early_init(const struct sbi_platform *plat,
+ bool cold_boot)
+{
+ if (plat && sbi_platform_ops(plat)->early_init)
+ return sbi_platform_ops(plat)->early_init(cold_boot);
+ return 0;
+}
+
+/**
+ * Final initialization for current HART
+ *
+ * @param plat pointer to struct sbi_platform
+ * @param cold_boot whether cold boot (TRUE) or warm_boot (FALSE)
+ *
+ * @return 0 on success and negative error code on failure
+ */
+static inline int sbi_platform_final_init(const struct sbi_platform *plat,
+ bool cold_boot)
+{
+ if (plat && sbi_platform_ops(plat)->final_init)
+ return sbi_platform_ops(plat)->final_init(cold_boot);
+ return 0;
+}
+
+/**
+ * Early exit for current HART
+ *
+ * @param plat pointer to struct sbi_platform
+ */
+static inline void sbi_platform_early_exit(const struct sbi_platform *plat)
+{
+ if (plat && sbi_platform_ops(plat)->early_exit)
+ sbi_platform_ops(plat)->early_exit();
+}
+
+/**
+ * Final exit for current HART
+ *
+ * @param plat pointer to struct sbi_platform
+ */
+static inline void sbi_platform_final_exit(const struct sbi_platform *plat)
+{
+ if (plat && sbi_platform_ops(plat)->final_exit)
+ sbi_platform_ops(plat)->final_exit();
+}
+
+/**
+ * Check CPU extension in MISA
+ *
+ * @param plat pointer to struct sbi_platform
+ * @param ext shorthand letter for CPU extensions
+ *
+ * @return zero for not-supported and non-zero for supported
+ */
+static inline int sbi_platform_misa_extension(const struct sbi_platform *plat,
+ char ext)
+{
+ if (plat && sbi_platform_ops(plat)->misa_check_extension)
+ return sbi_platform_ops(plat)->misa_check_extension(ext);
+ return 0;
+}
+
+/**
+ * Get MXL field of MISA
+ *
+ * @param plat pointer to struct sbi_platform
+ *
+ * @return 1/2/3 on success and error code on failure
+ */
+static inline int sbi_platform_misa_xlen(const struct sbi_platform *plat)
+{
+ if (plat && sbi_platform_ops(plat)->misa_get_xlen)
+ return sbi_platform_ops(plat)->misa_get_xlen();
+ return -1;
+}
+
+/**
+ * Get platform specific root domain memory regions
+ *
+ * @param plat pointer to struct sbi_platform
+ *
+ * @return an array of memory regions terminated by a region with order zero
+ * or NULL for no memory regions
+ */
+static inline struct sbi_domain_memregion *
+sbi_platform_domains_root_regions(const struct sbi_platform *plat)
+{
+ if (plat && sbi_platform_ops(plat)->domains_root_regions)
+ return sbi_platform_ops(plat)->domains_root_regions();
+ return NULL;
+}
+
+/**
+ * Initialize (or populate) domains for the platform
+ *
+ * @param plat pointer to struct sbi_platform
+ *
+ * @return 0 on success and negative error code on failure
+ */
+static inline int sbi_platform_domains_init(const struct sbi_platform *plat)
+{
+ if (plat && sbi_platform_ops(plat)->domains_init)
+ return sbi_platform_ops(plat)->domains_init();
+ return 0;
+}
+
+/**
+ * Write a character to the platform console output
+ *
+ * @param plat pointer to struct sbi_platform
+ * @param ch character to write
+ */
+static inline void sbi_platform_console_putc(const struct sbi_platform *plat,
+ char ch)
+{
+ if (plat && sbi_platform_ops(plat)->console_putc)
+ sbi_platform_ops(plat)->console_putc(ch);
+}
+
+/**
+ * Read a character from the platform console input
+ *
+ * @param plat pointer to struct sbi_platform
+ *
+ * @return character read from console input
+ */
+static inline int sbi_platform_console_getc(const struct sbi_platform *plat)
+{
+ if (plat && sbi_platform_ops(plat)->console_getc)
+ return sbi_platform_ops(plat)->console_getc();
+ return -1;
+}
+
+/**
+ * Initialize the platform console
+ *
+ * @param plat pointer to struct sbi_platform
+ *
+ * @return 0 on success and negative error code on failure
+ */
+static inline int sbi_platform_console_init(const struct sbi_platform *plat)
+{
+ if (plat && sbi_platform_ops(plat)->console_init)
+ return sbi_platform_ops(plat)->console_init();
+ return 0;
+}
+
+/**
+ * Initialize the platform interrupt controller for current HART
+ *
+ * @param plat pointer to struct sbi_platform
+ * @param cold_boot whether cold boot (TRUE) or warm_boot (FALSE)
+ *
+ * @return 0 on success and negative error code on failure
+ */
+static inline int sbi_platform_irqchip_init(const struct sbi_platform *plat,
+ bool cold_boot)
+{
+ if (plat && sbi_platform_ops(plat)->irqchip_init)
+ return sbi_platform_ops(plat)->irqchip_init(cold_boot);
+ return 0;
+}
+
+/**
+ * Exit the platform interrupt controller for current HART
+ *
+ * @param plat pointer to struct sbi_platform
+ */
+static inline void sbi_platform_irqchip_exit(const struct sbi_platform *plat)
+{
+ if (plat && sbi_platform_ops(plat)->irqchip_exit)
+ sbi_platform_ops(plat)->irqchip_exit();
+}
+
+/**
+ * Send IPI to a target HART
+ *
+ * @param plat pointer to struct sbi_platform
+ * @param target_hart HART ID of IPI target
+ */
+static inline void sbi_platform_ipi_send(const struct sbi_platform *plat,
+ u32 target_hart)
+{
+ if (plat && sbi_platform_ops(plat)->ipi_send)
+ sbi_platform_ops(plat)->ipi_send(target_hart);
+}
+
+/**
+ * Clear IPI for a target HART
+ *
+ * @param plat pointer to struct sbi_platform
+ * @param target_hart HART ID of IPI target
+ */
+static inline void sbi_platform_ipi_clear(const struct sbi_platform *plat,
+ u32 target_hart)
+{
+ if (plat && sbi_platform_ops(plat)->ipi_clear)
+ sbi_platform_ops(plat)->ipi_clear(target_hart);
+}
+
+/**
+ * Initialize the platform IPI support for current HART
+ *
+ * @param plat pointer to struct sbi_platform
+ * @param cold_boot whether cold boot (TRUE) or warm_boot (FALSE)
+ *
+ * @return 0 on success and negative error code on failure
+ */
+static inline int sbi_platform_ipi_init(const struct sbi_platform *plat,
+ bool cold_boot)
+{
+ if (plat && sbi_platform_ops(plat)->ipi_init)
+ return sbi_platform_ops(plat)->ipi_init(cold_boot);
+ return 0;
+}
+
+/**
+ * Exit the platform IPI support for current HART
+ *
+ * @param plat pointer to struct sbi_platform
+ */
+static inline void sbi_platform_ipi_exit(const struct sbi_platform *plat)
+{
+ if (plat && sbi_platform_ops(plat)->ipi_exit)
+ sbi_platform_ops(plat)->ipi_exit();
+}
+
+/**
+ * Get platform timer value
+ *
+ * @param plat pointer to struct sbi_platform
+ *
+ * @return 64-bit timer value
+ */
+static inline u64 sbi_platform_timer_value(const struct sbi_platform *plat)
+{
+ if (plat && sbi_platform_ops(plat)->timer_value)
+ return sbi_platform_ops(plat)->timer_value();
+ return 0;
+}
+
+/**
+ * Start platform timer event for current HART
+ *
+ * @param plat pointer to struct struct sbi_platform
+ * @param next_event timer value when timer event will happen
+ */
+static inline void
+sbi_platform_timer_event_start(const struct sbi_platform *plat, u64 next_event)
+{
+ if (plat && sbi_platform_ops(plat)->timer_event_start)
+ sbi_platform_ops(plat)->timer_event_start(next_event);
+}
+
+/**
+ * Stop platform timer event for current HART
+ *
+ * @param plat pointer to struct sbi_platform
+ */
+static inline void
+sbi_platform_timer_event_stop(const struct sbi_platform *plat)
+{
+ if (plat && sbi_platform_ops(plat)->timer_event_stop)
+ sbi_platform_ops(plat)->timer_event_stop();
+}
+
+/**
+ * Initialize the platform timer for current HART
+ *
+ * @param plat pointer to struct sbi_platform
+ * @param cold_boot whether cold boot (TRUE) or warm_boot (FALSE)
+ *
+ * @return 0 on success and negative error code on failure
+ */
+static inline int sbi_platform_timer_init(const struct sbi_platform *plat,
+ bool cold_boot)
+{
+ if (plat && sbi_platform_ops(plat)->timer_init)
+ return sbi_platform_ops(plat)->timer_init(cold_boot);
+ return 0;
+}
+
+/**
+ * Exit the platform timer for current HART
+ *
+ * @param plat pointer to struct sbi_platform
+ */
+static inline void sbi_platform_timer_exit(const struct sbi_platform *plat)
+{
+ if (plat && sbi_platform_ops(plat)->timer_exit)
+ sbi_platform_ops(plat)->timer_exit();
+}
+
+/**
+ * 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 if reset type and reason not supported and 1 if supported
+ */
+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)
+ sbi_platform_ops(plat)->system_reset(reset_type, reset_reason);
+}
+
+/**
+ * Check if a vendor extension is implemented or not.
+ *
+ * @param plat pointer to struct sbi_platform
+ * @param extid vendor SBI extension id
+ *
+ * @return 0 if extid is not implemented and 1 if implemented
+ */
+static inline int sbi_platform_vendor_ext_check(const struct sbi_platform *plat,
+ long extid)
+{
+ if (plat && sbi_platform_ops(plat)->vendor_ext_check)
+ return sbi_platform_ops(plat)->vendor_ext_check(extid);
+
+ return 0;
+}
+
+/**
+ * Invoke platform specific vendor SBI extension implementation.
+ *
+ * @param plat pointer to struct sbi_platform
+ * @param extid vendor SBI extension id
+ * @param funcid SBI function id within the extension id
+ * @param 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
+ *
+ * @return 0 on success and negative error code on failure
+ */
+static inline int sbi_platform_vendor_ext_provider(
+ const struct sbi_platform *plat,
+ long extid, long funcid,
+ 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, regs,
+ out_value,
+ out_trap);
+ }
+
+ return SBI_ENOTSUPP;
+}
+
+#endif
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_scratch.h b/roms/opensbi/include/sbi/sbi_scratch.h
new file mode 100644
index 000000000..e35122bed
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_scratch.h
@@ -0,0 +1,128 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_SCRATCH_H__
+#define __SBI_SCRATCH_H__
+
+#include <sbi/riscv_asm.h>
+
+/* clang-format off */
+
+/** Offset of fw_start member in sbi_scratch */
+#define SBI_SCRATCH_FW_START_OFFSET (0 * __SIZEOF_POINTER__)
+/** Offset of fw_size member in sbi_scratch */
+#define SBI_SCRATCH_FW_SIZE_OFFSET (1 * __SIZEOF_POINTER__)
+/** Offset of next_arg1 member in sbi_scratch */
+#define SBI_SCRATCH_NEXT_ARG1_OFFSET (2 * __SIZEOF_POINTER__)
+/** Offset of next_addr member in sbi_scratch */
+#define SBI_SCRATCH_NEXT_ADDR_OFFSET (3 * __SIZEOF_POINTER__)
+/** Offset of next_mode member in sbi_scratch */
+#define SBI_SCRATCH_NEXT_MODE_OFFSET (4 * __SIZEOF_POINTER__)
+/** Offset of warmboot_addr member in sbi_scratch */
+#define SBI_SCRATCH_WARMBOOT_ADDR_OFFSET (5 * __SIZEOF_POINTER__)
+/** Offset of platform_addr member in sbi_scratch */
+#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 (9 * __SIZEOF_POINTER__)
+/** Offset of options member in sbi_scratch */
+#define SBI_SCRATCH_OPTIONS_OFFSET (10 * __SIZEOF_POINTER__)
+/** Offset of extra space in sbi_scratch */
+#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (11 * __SIZEOF_POINTER__)
+/** Maximum size of sbi_scratch (4KB) */
+#define SBI_SCRATCH_SIZE (0x1000)
+
+/* clang-format on */
+
+#ifndef __ASSEMBLY__
+
+#include <sbi/sbi_types.h>
+
+/** Representation of per-HART scratch space */
+struct sbi_scratch {
+ /** Start (or base) address of firmware linked to OpenSBI library */
+ unsigned long fw_start;
+ /** Size (in bytes) of firmware linked to OpenSBI library */
+ unsigned long fw_size;
+ /** Arg1 (or 'a1' register) of next booting stage for this HART */
+ unsigned long next_arg1;
+ /** Address of next booting stage for this HART */
+ unsigned long next_addr;
+ /** Priviledge mode of next booting stage for this HART */
+ unsigned long next_mode;
+ /** Warm boot entry point address for this HART */
+ unsigned long warmboot_addr;
+ /** Address of sbi_platform */
+ 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;
+};
+
+/** Possible options for OpenSBI library */
+enum sbi_scratch_options {
+ /** Disable prints during boot */
+ SBI_SCRATCH_NO_BOOT_PRINTS = (1 << 0),
+ /** Enable runtime debug prints */
+ SBI_SCRATCH_DEBUG_PRINTS = (1 << 1),
+};
+
+/** Get pointer to sbi_scratch for current HART */
+#define sbi_scratch_thishart_ptr() \
+ ((struct sbi_scratch *)csr_read(CSR_MSCRATCH))
+
+/** Get Arg1 of next booting stage for current HART */
+#define sbi_scratch_thishart_arg1_ptr() \
+ ((void *)(sbi_scratch_thishart_ptr()->next_arg1))
+
+/** Initialize scratch table and allocator */
+int sbi_scratch_init(struct sbi_scratch *scratch);
+
+/**
+ * Allocate from extra space in sbi_scratch
+ *
+ * @return zero on failure and non-zero (>= SBI_SCRATCH_EXTRA_SPACE_OFFSET)
+ * on success
+ */
+unsigned long sbi_scratch_alloc_offset(unsigned long size, const char *owner);
+
+/** Free-up extra space in sbi_scratch */
+void sbi_scratch_free_offset(unsigned long offset);
+
+/** Get pointer from offset in sbi_scratch */
+#define sbi_scratch_offset_ptr(scratch, offset) ((void *)scratch + (offset))
+
+/** Get pointer from offset in sbi_scratch for current HART */
+#define sbi_scratch_thishart_offset_ptr(offset) \
+ ((void *)sbi_scratch_thishart_ptr() + (offset))
+
+/** HART id to scratch table */
+extern struct sbi_scratch *hartid_to_scratch_table[];
+
+/** Get sbi_scratch from HART id */
+#define sbi_hartid_to_scratch(__hartid) \
+ hartid_to_scratch_table[__hartid]
+
+/** Last HART id having a sbi_scratch pointer */
+extern u32 last_hartid_having_scratch;
+
+/** Get last HART id having a sbi_scratch pointer */
+#define sbi_scratch_last_hartid() last_hartid_having_scratch
+
+#endif
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_string.h b/roms/opensbi/include/sbi/sbi_string.h
new file mode 100644
index 000000000..b7c2bc22a
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_string.h
@@ -0,0 +1,46 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Atish Patra <atish.patra@wdc.com>
+ */
+
+#ifndef __STRING_H__
+#define __STRING_H__
+
+#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);
+
+char *sbi_strcpy(char *dest, const char *src);
+
+char *sbi_strncpy(char *dest, const char *src, size_t count);
+
+char *sbi_strchr(const char *s, int c);
+
+char *sbi_strrchr(const char *s, int c);
+
+void *sbi_memset(void *s, int c, size_t count);
+
+void *sbi_memcpy(void *dest, const void *src, size_t count);
+
+void *sbi_memmove(void *dest, const void *src, size_t count);
+
+int sbi_memcmp(const void *s1, const void *s2, size_t count);
+
+void *sbi_memchr(const void *s, int c, size_t count);
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_system.h b/roms/opensbi/include/sbi/sbi_system.h
new file mode 100644
index 000000000..34ba7669a
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_system.h
@@ -0,0 +1,19 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_SYSTEM_H__
+#define __SBI_SYSTEM_H__
+
+#include <sbi/sbi_types.h>
+
+bool sbi_system_reset_supported(u32 reset_type, u32 reset_reason);
+
+void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason);
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_timer.h b/roms/opensbi/include/sbi/sbi_timer.h
new file mode 100644
index 000000000..87bbdbfa0
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_timer.h
@@ -0,0 +1,44 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_TIMER_H__
+#define __SBI_TIMER_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_scratch;
+
+/** Get timer value for current HART */
+u64 sbi_timer_value(void);
+
+/** Get virtualized timer value for current HART */
+u64 sbi_timer_virt_value(void);
+
+/** Get timer delta value for current HART */
+u64 sbi_timer_get_delta(void);
+
+/** Set timer delta value for current HART */
+void sbi_timer_set_delta(ulong delta);
+
+/** Set upper 32-bits of timer delta value for current HART */
+void sbi_timer_set_delta_upper(ulong delta_upper);
+
+/** Start timer event for current HART */
+void sbi_timer_event_start(u64 next_event);
+
+/** Process timer event for current HART */
+void sbi_timer_process(void);
+
+/* Initialize timer */
+int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot);
+
+/* Exit timer */
+void sbi_timer_exit(struct sbi_scratch *scratch);
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_tlb.h b/roms/opensbi/include/sbi/sbi_tlb.h
new file mode 100644
index 000000000..48f1962d7
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_tlb.h
@@ -0,0 +1,60 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Atish Patra <atish.patra@wdc.com>
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_TLB_H__
+#define __SBI_TLB_H__
+
+#include <sbi/sbi_types.h>
+#include <sbi/sbi_hartmask.h>
+
+/* clang-format off */
+
+#define SBI_TLB_FLUSH_ALL ((unsigned long)-1)
+
+/* clang-format on */
+
+#define SBI_TLB_FIFO_NUM_ENTRIES 8
+
+struct sbi_scratch;
+
+struct sbi_tlb_info {
+ unsigned long start;
+ unsigned long size;
+ unsigned long asid;
+ unsigned long vmid;
+ void (*local_fn)(struct sbi_tlb_info *tinfo);
+ struct sbi_hartmask smask;
+};
+
+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)->local_fn = (__lfn); \
+ SBI_HARTMASK_INIT_EXCEPT(&(__p)->smask, (__src)); \
+} while (0)
+
+#define SBI_TLB_INFO_SIZE sizeof(struct sbi_tlb_info)
+
+int sbi_tlb_request(ulong hmask, ulong hbase, struct sbi_tlb_info *tinfo);
+
+int sbi_tlb_init(struct sbi_scratch *scratch, bool cold_boot);
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_trap.h b/roms/opensbi/include/sbi/sbi_trap.h
new file mode 100644
index 000000000..5fb94f980
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_trap.h
@@ -0,0 +1,214 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_TRAP_H__
+#define __SBI_TRAP_H__
+
+/* clang-format off */
+
+/** Index of zero member in sbi_trap_regs */
+#define SBI_TRAP_REGS_zero 0
+/** Index of ra member in sbi_trap_regs */
+#define SBI_TRAP_REGS_ra 1
+/** Index of sp member in sbi_trap_regs */
+#define SBI_TRAP_REGS_sp 2
+/** Index of gp member in sbi_trap_regs */
+#define SBI_TRAP_REGS_gp 3
+/** Index of tp member in sbi_trap_regs */
+#define SBI_TRAP_REGS_tp 4
+/** Index of t0 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_t0 5
+/** Index of t1 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_t1 6
+/** Index of t2 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_t2 7
+/** Index of s0 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_s0 8
+/** Index of s1 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_s1 9
+/** Index of a0 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_a0 10
+/** Index of a1 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_a1 11
+/** Index of a2 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_a2 12
+/** Index of a3 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_a3 13
+/** Index of a4 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_a4 14
+/** Index of a5 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_a5 15
+/** Index of a6 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_a6 16
+/** Index of a7 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_a7 17
+/** Index of s2 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_s2 18
+/** Index of s3 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_s3 19
+/** Index of s4 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_s4 20
+/** Index of s5 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_s5 21
+/** Index of s6 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_s6 22
+/** Index of s7 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_s7 23
+/** Index of s8 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_s8 24
+/** Index of s9 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_s9 25
+/** Index of s10 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_s10 26
+/** Index of s11 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_s11 27
+/** Index of t3 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_t3 28
+/** Index of t4 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_t4 29
+/** Index of t5 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_t5 30
+/** Index of t6 member in sbi_trap_regs */
+#define SBI_TRAP_REGS_t6 31
+/** Index of mepc member in sbi_trap_regs */
+#define SBI_TRAP_REGS_mepc 32
+/** Index of mstatus member in sbi_trap_regs */
+#define SBI_TRAP_REGS_mstatus 33
+/** Index of mstatusH member in sbi_trap_regs */
+#define SBI_TRAP_REGS_mstatusH 34
+/** Last member index in sbi_trap_regs */
+#define SBI_TRAP_REGS_last 35
+
+/** Index of epc member in sbi_trap_info */
+#define SBI_TRAP_INFO_epc 0
+/** Index of cause member in sbi_trap_info */
+#define SBI_TRAP_INFO_cause 1
+/** Index of tval member in sbi_trap_info */
+#define SBI_TRAP_INFO_tval 2
+/** Index of tval2 member in sbi_trap_info */
+#define SBI_TRAP_INFO_tval2 3
+/** Index of tinst member in sbi_trap_info */
+#define SBI_TRAP_INFO_tinst 4
+/** Last member index in sbi_trap_info */
+#define SBI_TRAP_INFO_last 5
+
+/* clang-format on */
+
+/** Get offset of member with name 'x' in sbi_trap_regs */
+#define SBI_TRAP_REGS_OFFSET(x) ((SBI_TRAP_REGS_##x) * __SIZEOF_POINTER__)
+/** Size (in bytes) of sbi_trap_regs */
+#define SBI_TRAP_REGS_SIZE SBI_TRAP_REGS_OFFSET(last)
+
+/** Get offset of member with name 'x' in sbi_trap_info */
+#define SBI_TRAP_INFO_OFFSET(x) ((SBI_TRAP_INFO_##x) * __SIZEOF_POINTER__)
+/** Size (in bytes) of sbi_trap_info */
+#define SBI_TRAP_INFO_SIZE SBI_TRAP_INFO_OFFSET(last)
+
+#ifndef __ASSEMBLY__
+
+#include <sbi/sbi_types.h>
+
+/** Representation of register state at time of trap/interrupt */
+struct sbi_trap_regs {
+ /** zero register state */
+ unsigned long zero;
+ /** ra register state */
+ unsigned long ra;
+ /** sp register state */
+ unsigned long sp;
+ /** gp register state */
+ unsigned long gp;
+ /** tp register state */
+ unsigned long tp;
+ /** t0 register state */
+ unsigned long t0;
+ /** t1 register state */
+ unsigned long t1;
+ /** t2 register state */
+ unsigned long t2;
+ /** s0 register state */
+ unsigned long s0;
+ /** s1 register state */
+ unsigned long s1;
+ /** a0 register state */
+ unsigned long a0;
+ /** a1 register state */
+ unsigned long a1;
+ /** a2 register state */
+ unsigned long a2;
+ /** a3 register state */
+ unsigned long a3;
+ /** a4 register state */
+ unsigned long a4;
+ /** a5 register state */
+ unsigned long a5;
+ /** a6 register state */
+ unsigned long a6;
+ /** a7 register state */
+ unsigned long a7;
+ /** s2 register state */
+ unsigned long s2;
+ /** s3 register state */
+ unsigned long s3;
+ /** s4 register state */
+ unsigned long s4;
+ /** s5 register state */
+ unsigned long s5;
+ /** s6 register state */
+ unsigned long s6;
+ /** s7 register state */
+ unsigned long s7;
+ /** s8 register state */
+ unsigned long s8;
+ /** s9 register state */
+ unsigned long s9;
+ /** s10 register state */
+ unsigned long s10;
+ /** s11 register state */
+ unsigned long s11;
+ /** t3 register state */
+ unsigned long t3;
+ /** t4 register state */
+ unsigned long t4;
+ /** t5 register state */
+ unsigned long t5;
+ /** t6 register state */
+ unsigned long t6;
+ /** mepc register state */
+ unsigned long mepc;
+ /** mstatus register state */
+ unsigned long mstatus;
+ /** mstatusH register state (only for 32-bit) */
+ unsigned long mstatusH;
+};
+
+/** Representation of trap details */
+struct sbi_trap_info {
+ /** epc Trap program counter */
+ unsigned long epc;
+ /** cause Trap exception cause */
+ unsigned long cause;
+ /** tval Trap value */
+ unsigned long tval;
+ /** tval2 Trap value 2 */
+ unsigned long tval2;
+ /** tinst Trap instruction */
+ unsigned long tinst;
+};
+
+int sbi_trap_redirect(struct sbi_trap_regs *regs,
+ struct sbi_trap_info *trap);
+
+void sbi_trap_handler(struct sbi_trap_regs *regs);
+
+void __noreturn sbi_trap_exit(const struct sbi_trap_regs *regs);
+
+#endif
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_types.h b/roms/opensbi/include/sbi/sbi_types.h
new file mode 100644
index 000000000..0952d5c82
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_types.h
@@ -0,0 +1,109 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_TYPES_H__
+#define __SBI_TYPES_H__
+
+#ifndef OPENSBI_EXTERNAL_SBI_TYPES
+
+/* clang-format off */
+
+typedef char s8;
+typedef unsigned char u8;
+typedef unsigned char uint8_t;
+
+typedef short s16;
+typedef unsigned short u16;
+typedef short int16_t;
+typedef unsigned short uint16_t;
+
+typedef int s32;
+typedef unsigned int u32;
+typedef int int32_t;
+typedef unsigned int uint32_t;
+
+#if __riscv_xlen == 64
+typedef long s64;
+typedef unsigned long u64;
+typedef long int64_t;
+typedef unsigned long uint64_t;
+#define PRILX "016lx"
+#elif __riscv_xlen == 32
+typedef long long s64;
+typedef unsigned long long u64;
+typedef long long int64_t;
+typedef unsigned long long uint64_t;
+#define PRILX "08lx"
+#else
+#error "Unexpected __riscv_xlen"
+#endif
+
+typedef int bool;
+typedef unsigned long ulong;
+typedef unsigned long uintptr_t;
+typedef unsigned long size_t;
+typedef long ssize_t;
+typedef unsigned long virtual_addr_t;
+typedef unsigned long virtual_size_t;
+typedef unsigned long physical_addr_t;
+typedef unsigned long physical_size_t;
+
+#define TRUE 1
+#define FALSE 0
+#define true TRUE
+#define false FALSE
+
+#define NULL ((void *)0)
+
+#define __packed __attribute__((packed))
+#define __noreturn __attribute__((noreturn))
+
+#define likely(x) __builtin_expect((x), 1)
+#define unlikely(x) __builtin_expect((x), 0)
+
+#undef offsetof
+#ifdef __compiler_offsetof
+#define offsetof(TYPE, MEMBER) __compiler_offsetof(TYPE,MEMBER)
+#else
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#define container_of(ptr, type, member) ({ \
+ const typeof(((type *)0)->member) * __mptr = (ptr); \
+ (type *)((char *)__mptr - offsetof(type, member)); })
+
+#define array_size(x) (sizeof(x) / sizeof((x)[0]))
+
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define CLAMP(a, lo, hi) MIN(MAX(a, lo), hi)
+
+#define STR(x) XSTR(x)
+#define XSTR(x) #x
+
+#define ROUNDUP(a, b) ((((a)-1) / (b) + 1) * (b))
+#define ROUNDDOWN(a, b) ((a) / (b) * (b))
+
+/* clang-format on */
+
+#else
+/*
+ * OPENSBI_EXTERNAL_SBI_TYPES could be defined in CFLAGS for using the
+ * external definitions of data types and common macros.
+ * OPENSBI_EXTERNAL_SBI_TYPES is the file name to external header file,
+ * the external build system should address the additional include
+ * directory ccordingly.
+ */
+
+#define XSTR(x) #x
+#define STR(x) XSTR(x)
+#include STR(OPENSBI_EXTERNAL_SBI_TYPES)
+#endif
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_unpriv.h b/roms/opensbi/include/sbi/sbi_unpriv.h
new file mode 100644
index 000000000..8cbd3de0c
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_unpriv.h
@@ -0,0 +1,41 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_UNPRIV_H__
+#define __SBI_UNPRIV_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_scratch;
+struct sbi_trap_info;
+
+#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type) \
+ type sbi_load_##type(const type *addr, \
+ struct sbi_trap_info *trap);
+
+#define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type) \
+ void sbi_store_##type(type *addr, type val, \
+ struct sbi_trap_info *trap);
+
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u8)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u16)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s8)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s16)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s32)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(u8)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(u16)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(u32)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u32)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u64)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(u64)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong)
+
+ulong sbi_get_insn(ulong mepc, struct sbi_trap_info *trap);
+
+#endif
diff --git a/roms/opensbi/include/sbi/sbi_version.h b/roms/opensbi/include/sbi/sbi_version.h
new file mode 100644
index 000000000..3f734fe9d
--- /dev/null
+++ b/roms/opensbi/include/sbi/sbi_version.h
@@ -0,0 +1,24 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SBI_VERSION_H__
+#define __SBI_VERSION_H__
+
+#define OPENSBI_VERSION_MAJOR 0
+#define OPENSBI_VERSION_MINOR 9
+
+/**
+ * OpenSBI 32-bit version with:
+ * 1. upper 16-bits as major number
+ * 2. lower 16-bits as minor number
+ */
+#define OPENSBI_VERSION ((OPENSBI_VERSION_MAJOR << 16) | \
+ (OPENSBI_VERSION_MINOR))
+
+#endif
diff --git a/roms/opensbi/include/sbi_utils/fdt/fdt_domain.h b/roms/opensbi/include/sbi_utils/fdt/fdt_domain.h
new file mode 100644
index 000000000..5448eb4d9
--- /dev/null
+++ b/roms/opensbi/include/sbi_utils/fdt/fdt_domain.h
@@ -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__ */
diff --git a/roms/opensbi/include/sbi_utils/fdt/fdt_fixup.h b/roms/opensbi/include/sbi_utils/fdt/fdt_fixup.h
new file mode 100644
index 000000000..0697a18ee
--- /dev/null
+++ b/roms/opensbi/include/sbi_utils/fdt/fdt_fixup.h
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * fdt_fixup.h - Flat Device Tree manipulation helper routines
+ * Implement platform specific DT fixups on top of libfdt.
+ *
+ * Copyright (C) 2020 Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#ifndef __FDT_FIXUP_H__
+#define __FDT_FIXUP_H__
+
+/**
+ * Fix up the CPU node in the device tree
+ *
+ * This routine updates the "status" property of a CPU node in the device tree
+ * to "disabled" if that hart is in disabled state in OpenSBI.
+ *
+ * It is recommended that platform codes call this helper in their final_init()
+ *
+ * @param fdt: device tree blob
+ */
+void fdt_cpu_fixup(void *fdt);
+
+/**
+ * Fix up the PLIC node in the device tree
+ *
+ * This routine updates the "interrupt-extended" property of the PLIC node in
+ * the device tree to hide the M-mode external interrupt from CPUs.
+ *
+ * It is recommended that platform codes call this helper in their final_init()
+ *
+ * @param fdt: device tree blob
+ * @param compat: PLIC node compatible string
+ */
+void fdt_plic_fixup(void *fdt, const char *compat);
+
+/**
+ * Fix up the reserved memory node in the device tree
+ *
+ * This routine inserts a child node of the reserved memory node in the device
+ * tree that describes the protected memory region done by OpenSBI via PMP.
+ *
+ * It is recommended that platform codes call this helper in their final_init()
+ *
+ * @param fdt: device tree blob
+ * @return zero on success and -ve on failure
+ */
+int fdt_reserved_memory_fixup(void *fdt);
+
+/**
+ * Fix up the reserved memory subnodes in the device tree
+ *
+ * This routine adds the no-map property to the reserved memory subnodes so
+ * that the OS does not map those PMP protected memory regions.
+ *
+ * Platform codes must call this helper in their final_init() after fdt_fixups()
+ * if the OS should not map the PMP protected reserved regions.
+ *
+ * @param fdt: device tree blob
+ * @return zero on success and -ve on failure
+ */
+int fdt_reserved_memory_nomap_fixup(void *fdt);
+
+/**
+ * General device tree fix-up
+ *
+ * This routine do all required device tree fix-ups for a typical platform.
+ * It fixes up the PLIC node and the reserved memory node in the device tree
+ * by calling the corresponding helper routines to accomplish the task.
+ *
+ * It is recommended that platform codes call this helper in their final_init()
+ *
+ * @param fdt: device tree blob
+ */
+void fdt_fixups(void *fdt);
+
+#endif /* __FDT_FIXUP_H__ */
+
diff --git a/roms/opensbi/include/sbi_utils/fdt/fdt_helper.h b/roms/opensbi/include/sbi_utils/fdt/fdt_helper.h
new file mode 100644
index 000000000..f5222deb4
--- /dev/null
+++ b/roms/opensbi/include/sbi_utils/fdt/fdt_helper.h
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * fdt_helper.h - Flat Device Tree parsing helper routines
+ * Implement helper routines to parse FDT nodes on top of
+ * libfdt for OpenSBI usage
+ *
+ * Copyright (C) 2020 Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#ifndef __FDT_HELPER_H__
+#define __FDT_HELPER_H__
+
+#include <sbi/sbi_types.h>
+
+struct fdt_match {
+ const char *compatible;
+ void *data;
+};
+
+struct platform_uart_data {
+ unsigned long addr;
+ unsigned long freq;
+ unsigned long baud;
+ unsigned long reg_shift;
+ unsigned long reg_io_width;
+};
+
+const struct fdt_match *fdt_match_node(void *fdt, int nodeoff,
+ const struct fdt_match *match_table);
+
+int fdt_find_match(void *fdt, int startoff,
+ const struct fdt_match *match_table,
+ const struct fdt_match **out_match);
+
+int fdt_get_node_addr_size(void *fdt, int node, unsigned long *addr,
+ unsigned long *size);
+
+int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid);
+
+int fdt_parse_max_hart_id(void *fdt, u32 *max_hartid);
+
+int fdt_parse_shakti_uart_node(void *fdt, int nodeoffset,
+ struct platform_uart_data *uart);
+
+int fdt_parse_sifive_uart_node(void *fdt, int nodeoffset,
+ struct platform_uart_data *uart);
+
+int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
+ struct platform_uart_data *uart);
+
+int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
+ const char *compatible);
+
+struct plic_data;
+
+int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic);
+
+int fdt_parse_plic(void *fdt, struct plic_data *plic, const char *compat);
+
+struct clint_data;
+
+int fdt_parse_clint_node(void *fdt, int nodeoffset, bool for_timer,
+ struct clint_data *clint);
+
+int fdt_parse_compat_addr(void *fdt, unsigned long *addr,
+ const char *compatible);
+
+#endif /* __FDT_HELPER_H__ */
diff --git a/roms/opensbi/include/sbi_utils/ipi/fdt_ipi.h b/roms/opensbi/include/sbi_utils/ipi/fdt_ipi.h
new file mode 100644
index 000000000..e817141ac
--- /dev/null
+++ b/roms/opensbi/include/sbi_utils/ipi/fdt_ipi.h
@@ -0,0 +1,32 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __FDT_IPI_H__
+#define __FDT_IPI_H__
+
+#include <sbi/sbi_types.h>
+
+struct fdt_ipi {
+ const struct fdt_match *match_table;
+ int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
+ int (*warm_init)(void);
+ void (*exit)(void);
+ void (*send)(u32 target_hart);
+ void (*clear)(u32 target_hart);
+};
+
+void fdt_ipi_send(u32 target_hart);
+
+void fdt_ipi_clear(u32 target_hart);
+
+void fdt_ipi_exit(void);
+
+int fdt_ipi_init(bool cold_boot);
+
+#endif
diff --git a/roms/opensbi/include/sbi_utils/irqchip/fdt_irqchip.h b/roms/opensbi/include/sbi_utils/irqchip/fdt_irqchip.h
new file mode 100644
index 000000000..13ef6f711
--- /dev/null
+++ b/roms/opensbi/include/sbi_utils/irqchip/fdt_irqchip.h
@@ -0,0 +1,26 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __FDT_IRQCHIP_H__
+#define __FDT_IRQCHIP_H__
+
+#include <sbi/sbi_types.h>
+
+struct fdt_irqchip {
+ const struct fdt_match *match_table;
+ int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
+ int (*warm_init)(void);
+ void (*exit)(void);
+};
+
+void fdt_irqchip_exit(void);
+
+int fdt_irqchip_init(bool cold_boot);
+
+#endif
diff --git a/roms/opensbi/include/sbi_utils/irqchip/plic.h b/roms/opensbi/include/sbi_utils/irqchip/plic.h
new file mode 100644
index 000000000..0e56d801e
--- /dev/null
+++ b/roms/opensbi/include/sbi_utils/irqchip/plic.h
@@ -0,0 +1,29 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __IRQCHIP_PLIC_H__
+#define __IRQCHIP_PLIC_H__
+
+#include <sbi/sbi_types.h>
+
+struct plic_data {
+ unsigned long addr;
+ unsigned long num_src;
+};
+
+int plic_warm_irqchip_init(struct plic_data *plic,
+ int m_cntx_id, int s_cntx_id);
+
+int plic_cold_irqchip_init(struct plic_data *plic);
+
+void plic_set_thresh(struct plic_data *plic, u32 cntxid, u32 val);
+
+void plic_set_ie(struct plic_data *plic, u32 cntxid, u32 word_index, u32 val);
+
+#endif
diff --git a/roms/opensbi/include/sbi_utils/reset/fdt_reset.h b/roms/opensbi/include/sbi_utils/reset/fdt_reset.h
new file mode 100644
index 000000000..cce441a84
--- /dev/null
+++ b/roms/opensbi/include/sbi_utils/reset/fdt_reset.h
@@ -0,0 +1,28 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __FDT_RESET_H__
+#define __FDT_RESET_H__
+
+#include <sbi/sbi_types.h>
+
+struct fdt_reset {
+ const struct fdt_match *match_table;
+ int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
+ int (*system_reset_check)(u32 reset_type, u32 reset_reason);
+ void (*system_reset)(u32 reset_type, u32 reset_reason);
+};
+
+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);
+
+#endif
diff --git a/roms/opensbi/include/sbi_utils/serial/fdt_serial.h b/roms/opensbi/include/sbi_utils/serial/fdt_serial.h
new file mode 100644
index 000000000..08f97996f
--- /dev/null
+++ b/roms/opensbi/include/sbi_utils/serial/fdt_serial.h
@@ -0,0 +1,28 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __FDT_SERIAL_H__
+#define __FDT_SERIAL_H__
+
+#include <sbi/sbi_types.h>
+
+struct fdt_serial {
+ const struct fdt_match *match_table;
+ int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
+ void (*putc)(char ch);
+ int (*getc)(void);
+};
+
+void fdt_serial_putc(char ch);
+
+int fdt_serial_getc(void);
+
+int fdt_serial_init(void);
+
+#endif
diff --git a/roms/opensbi/include/sbi_utils/serial/shakti-uart.h b/roms/opensbi/include/sbi_utils/serial/shakti-uart.h
new file mode 100644
index 000000000..08043be11
--- /dev/null
+++ b/roms/opensbi/include/sbi_utils/serial/shakti-uart.h
@@ -0,0 +1,18 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Vijai Kumar K <vijai@behindbytes.com>
+ */
+
+#ifndef __SERIAL_SHAKTI_UART_H__
+#define __SERIAL_SHAKTI_UART_H__
+
+#include <sbi/sbi_types.h>
+
+void shakti_uart_putc(char ch);
+
+int shakti_uart_getc(void);
+
+int shakti_uart_init(unsigned long base, u32 in_freq, u32 baudrate);
+
+#endif
diff --git a/roms/opensbi/include/sbi_utils/serial/sifive-uart.h b/roms/opensbi/include/sbi_utils/serial/sifive-uart.h
new file mode 100644
index 000000000..f3233921f
--- /dev/null
+++ b/roms/opensbi/include/sbi_utils/serial/sifive-uart.h
@@ -0,0 +1,21 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SERIAL_SIFIVE_UART_H__
+#define __SERIAL_SIFIVE_UART_H__
+
+#include <sbi/sbi_types.h>
+
+void sifive_uart_putc(char ch);
+
+int sifive_uart_getc(void);
+
+int sifive_uart_init(unsigned long base, u32 in_freq, u32 baudrate);
+
+#endif
diff --git a/roms/opensbi/include/sbi_utils/serial/uart8250.h b/roms/opensbi/include/sbi_utils/serial/uart8250.h
new file mode 100644
index 000000000..0a1b5d368
--- /dev/null
+++ b/roms/opensbi/include/sbi_utils/serial/uart8250.h
@@ -0,0 +1,22 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SERIAL_UART8250_H__
+#define __SERIAL_UART8250_H__
+
+#include <sbi/sbi_types.h>
+
+void uart8250_putc(char ch);
+
+int uart8250_getc(void);
+
+int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
+ u32 reg_width);
+
+#endif
diff --git a/roms/opensbi/include/sbi_utils/sys/clint.h b/roms/opensbi/include/sbi_utils/sys/clint.h
new file mode 100644
index 000000000..b07cf62ef
--- /dev/null
+++ b/roms/opensbi/include/sbi_utils/sys/clint.h
@@ -0,0 +1,51 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SYS_CLINT_H__
+#define __SYS_CLINT_H__
+
+#include <sbi/sbi_types.h>
+
+struct clint_data {
+ /* Public details */
+ unsigned long addr;
+ u32 first_hartid;
+ u32 hart_count;
+ bool has_64bit_mmio;
+ /* Private details (initialized and used by CLINT library)*/
+ u32 *ipi;
+ struct clint_data *time_delta_reference;
+ unsigned long time_delta_computed;
+ u64 time_delta;
+ u64 *time_val;
+ u64 *time_cmp;
+ u64 (*time_rd)(volatile u64 *addr);
+ void (*time_wr)(u64 value, volatile u64 *addr);
+};
+
+void clint_ipi_send(u32 target_hart);
+
+void clint_ipi_clear(u32 target_hart);
+
+int clint_warm_ipi_init(void);
+
+int clint_cold_ipi_init(struct clint_data *clint);
+
+u64 clint_timer_value(void);
+
+void clint_timer_event_stop(void);
+
+void clint_timer_event_start(u64 next_event);
+
+int clint_warm_timer_init(void);
+
+int clint_cold_timer_init(struct clint_data *clint,
+ struct clint_data *reference);
+
+#endif
diff --git a/roms/opensbi/include/sbi_utils/sys/htif.h b/roms/opensbi/include/sbi_utils/sys/htif.h
new file mode 100644
index 000000000..a43172348
--- /dev/null
+++ b/roms/opensbi/include/sbi_utils/sys/htif.h
@@ -0,0 +1,21 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2010-2020, The Regents of the University of California
+ * (Regents). All Rights Reserved.
+ */
+
+#ifndef __SYS_HTIF_H__
+#define __SYS_HTIF_H__
+
+#include <sbi/sbi_types.h>
+
+void htif_putc(char ch);
+
+int htif_getc(void);
+
+int htif_system_reset_check(u32 type, u32 reason);
+
+void htif_system_reset(u32 type, u32 reason);
+
+#endif
diff --git a/roms/opensbi/include/sbi_utils/sys/sifive_test.h b/roms/opensbi/include/sbi_utils/sys/sifive_test.h
new file mode 100644
index 000000000..958622e6a
--- /dev/null
+++ b/roms/opensbi/include/sbi_utils/sys/sifive_test.h
@@ -0,0 +1,21 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __SYS_SIFIVE_TEST_H__
+#define __SYS_SIFIVE_TEST_H__
+
+#include <sbi/sbi_types.h>
+
+int sifive_test_system_reset_check(u32 type, u32 reason);
+
+void sifive_test_system_reset(u32 type, u32 reason);
+
+int sifive_test_init(unsigned long base);
+
+#endif
diff --git a/roms/opensbi/include/sbi_utils/timer/fdt_timer.h b/roms/opensbi/include/sbi_utils/timer/fdt_timer.h
new file mode 100644
index 000000000..770a0f3c5
--- /dev/null
+++ b/roms/opensbi/include/sbi_utils/timer/fdt_timer.h
@@ -0,0 +1,35 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __FDT_TIMER_H__
+#define __FDT_TIMER_H__
+
+#include <sbi/sbi_types.h>
+
+struct fdt_timer {
+ const struct fdt_match *match_table;
+ int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
+ int (*warm_init)(void);
+ void (*exit)(void);
+ u64 (*value)(void);
+ void (*event_stop)(void);
+ void (*event_start)(u64 next_event);
+};
+
+u64 fdt_timer_value(void);
+
+void fdt_timer_event_stop(void);
+
+void fdt_timer_event_start(u64 next_event);
+
+void fdt_timer_exit(void);
+
+int fdt_timer_init(bool cold_boot);
+
+#endif
diff --git a/roms/opensbi/lib/sbi/objects.mk b/roms/opensbi/lib/sbi/objects.mk
new file mode 100644
index 000000000..6f2c06f5b
--- /dev/null
+++ b/roms/opensbi/lib/sbi/objects.mk
@@ -0,0 +1,43 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2019 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+
+libsbi-objs-y += riscv_asm.o
+libsbi-objs-y += riscv_atomic.o
+libsbi-objs-y += riscv_hardfp.o
+libsbi-objs-y += riscv_locks.o
+
+libsbi-objs-y += sbi_bitmap.o
+libsbi-objs-y += sbi_bitops.o
+libsbi-objs-y += sbi_console.o
+libsbi-objs-y += sbi_domain.o
+libsbi-objs-y += sbi_ecall.o
+libsbi-objs-y += sbi_ecall_base.o
+libsbi-objs-y += sbi_ecall_hsm.o
+libsbi-objs-y += sbi_ecall_legacy.o
+libsbi-objs-y += sbi_ecall_replace.o
+libsbi-objs-y += sbi_ecall_vendor.o
+libsbi-objs-y += sbi_emulate_csr.o
+libsbi-objs-y += sbi_fifo.o
+libsbi-objs-y += sbi_hart.o
+libsbi-objs-y += sbi_math.o
+libsbi-objs-y += sbi_hfence.o
+libsbi-objs-y += sbi_hsm.o
+libsbi-objs-y += sbi_illegal_insn.o
+libsbi-objs-y += sbi_init.o
+libsbi-objs-y += sbi_ipi.o
+libsbi-objs-y += sbi_misaligned_ldst.o
+libsbi-objs-y += sbi_platform.o
+libsbi-objs-y += sbi_scratch.o
+libsbi-objs-y += sbi_string.o
+libsbi-objs-y += sbi_system.o
+libsbi-objs-y += sbi_timer.o
+libsbi-objs-y += sbi_tlb.o
+libsbi-objs-y += sbi_trap.o
+libsbi-objs-y += sbi_unpriv.o
+libsbi-objs-y += sbi_expected_trap.o
diff --git a/roms/opensbi/lib/sbi/riscv_asm.c b/roms/opensbi/lib/sbi/riscv_asm.c
new file mode 100644
index 000000000..8c54c1114
--- /dev/null
+++ b/roms/opensbi/lib/sbi/riscv_asm.c
@@ -0,0 +1,295 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_platform.h>
+
+/* determine CPU extension, return non-zero support */
+int misa_extension_imp(char ext)
+{
+ unsigned long misa = csr_read(CSR_MISA);
+
+ if (misa) {
+ if ('A' <= ext && ext <= 'Z')
+ return misa & (1 << (ext - 'A'));
+ if ('a' <= ext && ext <= 'z')
+ return misa & (1 << (ext - 'a'));
+ return 0;
+ }
+
+ return sbi_platform_misa_extension(sbi_platform_thishart_ptr(), ext);
+}
+
+int misa_xlen(void)
+{
+ long r;
+
+ if (csr_read(CSR_MISA) == 0)
+ return sbi_platform_misa_xlen(sbi_platform_thishart_ptr());
+
+ __asm__ __volatile__(
+ "csrr t0, misa\n\t"
+ "slti t1, t0, 0\n\t"
+ "slli t1, t1, 1\n\t"
+ "slli t0, t0, 1\n\t"
+ "slti t0, t0, 0\n\t"
+ "add %0, t0, t1"
+ : "=r"(r)
+ :
+ : "t0", "t1");
+
+ return r ? r : -1;
+}
+
+void misa_string(int xlen, char *out, unsigned int out_sz)
+{
+ unsigned int i, pos = 0;
+ const char valid_isa_order[] = "iemafdqclbjtpvnsuhkorwxyzg";
+
+ if (!out)
+ return;
+
+ if (5 <= (out_sz - pos)) {
+ out[pos++] = 'r';
+ out[pos++] = 'v';
+ switch (xlen) {
+ case 1:
+ out[pos++] = '3';
+ out[pos++] = '2';
+ break;
+ case 2:
+ out[pos++] = '6';
+ out[pos++] = '4';
+ break;
+ case 3:
+ out[pos++] = '1';
+ out[pos++] = '2';
+ out[pos++] = '8';
+ break;
+ default:
+ return;
+ }
+ }
+
+ for (i = 0; i < array_size(valid_isa_order) && (pos < out_sz); i++) {
+ if (misa_extension_imp(valid_isa_order[i]))
+ out[pos++] = valid_isa_order[i];
+ }
+
+ if (pos < out_sz)
+ out[pos++] = '\0';
+}
+
+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) {
+ 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) {
+ 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)
+{
+ unsigned long ret = 0;
+
+ while (!(x & 1UL)) {
+ ret++;
+ x = x >> 1;
+ }
+
+ return ret;
+}
+
+int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
+ unsigned long log2len)
+{
+ int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr;
+ unsigned long cfgmask, pmpcfg;
+ unsigned long addrmask, pmpaddr;
+
+ /* check parameters */
+ if (n >= PMP_COUNT || log2len > __riscv_xlen || log2len < PMP_SHIFT)
+ return SBI_EINVAL;
+
+ /* calculate PMP register and offset */
+#if __riscv_xlen == 32
+ pmpcfg_csr = CSR_PMPCFG0 + (n >> 2);
+ pmpcfg_shift = (n & 3) << 3;
+#elif __riscv_xlen == 64
+ pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
+ pmpcfg_shift = (n & 7) << 3;
+#else
+ pmpcfg_csr = -1;
+ pmpcfg_shift = -1;
+#endif
+ pmpaddr_csr = CSR_PMPADDR0 + n;
+ if (pmpcfg_csr < 0 || pmpcfg_shift < 0)
+ return SBI_ENOTSUPP;
+
+ /* encode PMP config */
+ prot |= (log2len == PMP_SHIFT) ? PMP_A_NA4 : PMP_A_NAPOT;
+ cfgmask = ~(0xffUL << pmpcfg_shift);
+ pmpcfg = (csr_read_num(pmpcfg_csr) & cfgmask);
+ pmpcfg |= ((prot << pmpcfg_shift) & ~cfgmask);
+
+ /* encode PMP address */
+ if (log2len == PMP_SHIFT) {
+ pmpaddr = (addr >> PMP_SHIFT);
+ } else {
+ if (log2len == __riscv_xlen) {
+ pmpaddr = -1UL;
+ } else {
+ addrmask = (1UL << (log2len - PMP_SHIFT)) - 1;
+ pmpaddr = ((addr >> PMP_SHIFT) & ~addrmask);
+ pmpaddr |= (addrmask >> 1);
+ }
+ }
+
+ /* write csrs */
+ csr_write_num(pmpaddr_csr, pmpaddr);
+ csr_write_num(pmpcfg_csr, pmpcfg);
+
+ return 0;
+}
+
+int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
+ unsigned long *log2len)
+{
+ int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr;
+ unsigned long cfgmask, pmpcfg, prot;
+ unsigned long t1, addr, len;
+
+ /* check parameters */
+ if (n >= PMP_COUNT || !prot_out || !addr_out || !log2len)
+ return SBI_EINVAL;
+ *prot_out = *addr_out = *log2len = 0;
+
+ /* calculate PMP register and offset */
+#if __riscv_xlen == 32
+ pmpcfg_csr = CSR_PMPCFG0 + (n >> 2);
+ pmpcfg_shift = (n & 3) << 3;
+#elif __riscv_xlen == 64
+ pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
+ pmpcfg_shift = (n & 7) << 3;
+#else
+ pmpcfg_csr = -1;
+ pmpcfg_shift = -1;
+#endif
+ pmpaddr_csr = CSR_PMPADDR0 + n;
+ if (pmpcfg_csr < 0 || pmpcfg_shift < 0)
+ return SBI_ENOTSUPP;
+
+ /* decode PMP config */
+ cfgmask = (0xffUL << pmpcfg_shift);
+ pmpcfg = csr_read_num(pmpcfg_csr) & cfgmask;
+ prot = pmpcfg >> pmpcfg_shift;
+
+ /* decode PMP address */
+ if ((prot & PMP_A) == PMP_A_NAPOT) {
+ addr = csr_read_num(pmpaddr_csr);
+ if (addr == -1UL) {
+ addr = 0;
+ len = __riscv_xlen;
+ } else {
+ t1 = ctz(~addr);
+ addr = (addr & ~((1UL << t1) - 1)) << PMP_SHIFT;
+ len = (t1 + PMP_SHIFT + 1);
+ }
+ } else {
+ addr = csr_read_num(pmpaddr_csr) << PMP_SHIFT;
+ len = PMP_SHIFT;
+ }
+
+ /* return details */
+ *prot_out = prot;
+ *addr_out = addr;
+ *log2len = len;
+
+ return 0;
+}
diff --git a/roms/opensbi/lib/sbi/riscv_atomic.c b/roms/opensbi/lib/sbi/riscv_atomic.c
new file mode 100644
index 000000000..558bca8c1
--- /dev/null
+++ b/roms/opensbi/lib/sbi/riscv_atomic.c
@@ -0,0 +1,255 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/sbi_bitops.h>
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_atomic.h>
+#include <sbi/riscv_barrier.h>
+
+long atomic_read(atomic_t *atom)
+{
+ long ret = atom->counter;
+ rmb();
+ return ret;
+}
+
+void atomic_write(atomic_t *atom, long value)
+{
+ atom->counter = value;
+ wmb();
+}
+
+long atomic_add_return(atomic_t *atom, long value)
+{
+ long ret;
+
+ __asm__ __volatile__(" amoadd.w.aqrl %1, %2, %0"
+ : "+A"(atom->counter), "=r"(ret)
+ : "r"(value)
+ : "memory");
+
+ return ret + value;
+}
+
+long atomic_sub_return(atomic_t *atom, long value)
+{
+ long ret;
+
+ __asm__ __volatile__(" amoadd.w.aqrl %1, %2, %0"
+ : "+A"(atom->counter), "=r"(ret)
+ : "r"(-value)
+ : "memory");
+
+ return ret - value;
+}
+
+#define __axchg(ptr, new, size) \
+ ({ \
+ __typeof__(ptr) __ptr = (ptr); \
+ __typeof__(new) __new = (new); \
+ __typeof__(*(ptr)) __ret; \
+ switch (size) { \
+ case 4: \
+ __asm__ __volatile__ ( \
+ " amoswap.w.aqrl %0, %2, %1\n" \
+ : "=r" (__ret), "+A" (*__ptr) \
+ : "r" (__new) \
+ : "memory"); \
+ break; \
+ case 8: \
+ __asm__ __volatile__ ( \
+ " amoswap.d.aqrl %0, %2, %1\n" \
+ : "=r" (__ret), "+A" (*__ptr) \
+ : "r" (__new) \
+ : "memory"); \
+ break; \
+ default: \
+ break; \
+ } \
+ __ret; \
+ })
+
+#define axchg(ptr, x) \
+ ({ \
+ __typeof__(*(ptr)) _x_ = (x); \
+ (__typeof__(*(ptr))) __axchg((ptr), _x_, sizeof(*(ptr))); \
+ })
+
+
+#define __xchg(ptr, new, size) \
+ ({ \
+ __typeof__(ptr) __ptr = (ptr); \
+ __typeof__(*(ptr)) __new = (new); \
+ __typeof__(*(ptr)) __ret; \
+ register unsigned int __rc; \
+ switch (size) { \
+ case 4: \
+ __asm__ __volatile__("0: lr.w %0, %2\n" \
+ " sc.w.rl %1, %z3, %2\n" \
+ " bnez %1, 0b\n" \
+ " fence rw, rw\n" \
+ : "=&r"(__ret), "=&r"(__rc), \
+ "+A"(*__ptr) \
+ : "rJ"(__new) \
+ : "memory"); \
+ break; \
+ case 8: \
+ __asm__ __volatile__("0: lr.d %0, %2\n" \
+ " sc.d.rl %1, %z3, %2\n" \
+ " bnez %1, 0b\n" \
+ " fence rw, rw\n" \
+ : "=&r"(__ret), "=&r"(__rc), \
+ "+A"(*__ptr) \
+ : "rJ"(__new) \
+ : "memory"); \
+ break; \
+ default: \
+ break; \
+ } \
+ __ret; \
+ })
+
+#define xchg(ptr, n) \
+ ({ \
+ __typeof__(*(ptr)) _n_ = (n); \
+ (__typeof__(*(ptr))) __xchg((ptr), _n_, sizeof(*(ptr))); \
+ })
+
+#define __cmpxchg(ptr, old, new, size) \
+ ({ \
+ __typeof__(ptr) __ptr = (ptr); \
+ __typeof__(*(ptr)) __old = (old); \
+ __typeof__(*(ptr)) __new = (new); \
+ __typeof__(*(ptr)) __ret; \
+ register unsigned int __rc; \
+ switch (size) { \
+ case 4: \
+ __asm__ __volatile__("0: lr.w %0, %2\n" \
+ " bne %0, %z3, 1f\n" \
+ " sc.w.rl %1, %z4, %2\n" \
+ " bnez %1, 0b\n" \
+ " fence rw, rw\n" \
+ "1:\n" \
+ : "=&r"(__ret), "=&r"(__rc), \
+ "+A"(*__ptr) \
+ : "rJ"(__old), "rJ"(__new) \
+ : "memory"); \
+ break; \
+ case 8: \
+ __asm__ __volatile__("0: lr.d %0, %2\n" \
+ " bne %0, %z3, 1f\n" \
+ " sc.d.rl %1, %z4, %2\n" \
+ " bnez %1, 0b\n" \
+ " fence rw, rw\n" \
+ "1:\n" \
+ : "=&r"(__ret), "=&r"(__rc), \
+ "+A"(*__ptr) \
+ : "rJ"(__old), "rJ"(__new) \
+ : "memory"); \
+ break; \
+ default: \
+ break; \
+ } \
+ __ret; \
+ })
+
+#define cmpxchg(ptr, o, n) \
+ ({ \
+ __typeof__(*(ptr)) _o_ = (o); \
+ __typeof__(*(ptr)) _n_ = (n); \
+ (__typeof__(*(ptr))) \
+ __cmpxchg((ptr), _o_, _n_, sizeof(*(ptr))); \
+ })
+
+long atomic_cmpxchg(atomic_t *atom, long oldval, long newval)
+{
+#ifdef __riscv_atomic
+ return __sync_val_compare_and_swap(&atom->counter, oldval, newval);
+#else
+ return cmpxchg(&atom->counter, oldval, newval);
+#endif
+}
+
+long atomic_xchg(atomic_t *atom, long newval)
+{
+ /* Atomically set new value and return old value. */
+#ifdef __riscv_atomic
+ return axchg(&atom->counter, newval);
+#else
+ return xchg(&atom->counter, newval);
+#endif
+}
+
+unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
+ unsigned int newval)
+{
+ /* Atomically set new value and return old value. */
+#ifdef __riscv_atomic
+ return axchg(ptr, newval);
+#else
+ return xchg(ptr, newval);
+#endif
+}
+
+unsigned long atomic_raw_xchg_ulong(volatile unsigned long *ptr,
+ unsigned long newval)
+{
+ /* Atomically set new value and return old value. */
+#ifdef __riscv_atomic
+ return axchg(ptr, newval);
+#else
+ return xchg(ptr, newval);
+#endif
+}
+
+#if (__SIZEOF_POINTER__ == 8)
+#define __AMO(op) "amo" #op ".d"
+#elif (__SIZEOF_POINTER__ == 4)
+#define __AMO(op) "amo" #op ".w"
+#else
+#error "Unexpected __SIZEOF_POINTER__"
+#endif
+
+#define __atomic_op_bit_ord(op, mod, nr, addr, ord) \
+ ({ \
+ unsigned long __res, __mask; \
+ __mask = BIT_MASK(nr); \
+ __asm__ __volatile__(__AMO(op) #ord " %0, %2, %1" \
+ : "=r"(__res), "+A"(addr[BIT_WORD(nr)]) \
+ : "r"(mod(__mask)) \
+ : "memory"); \
+ __res; \
+ })
+
+#define __atomic_op_bit(op, mod, nr, addr) \
+ __atomic_op_bit_ord(op, mod, nr, addr, .aqrl)
+
+/* Bitmask modifiers */
+#define __NOP(x) (x)
+#define __NOT(x) (~(x))
+
+inline int atomic_raw_set_bit(int nr, volatile unsigned long *addr)
+{
+ return __atomic_op_bit(or, __NOP, nr, addr);
+}
+
+inline int atomic_raw_clear_bit(int nr, volatile unsigned long *addr)
+{
+ return __atomic_op_bit(and, __NOT, nr, addr);
+}
+
+inline int atomic_set_bit(int nr, atomic_t *atom)
+{
+ return atomic_raw_set_bit(nr, (unsigned long *)&atom->counter);
+}
+
+inline int atomic_clear_bit(int nr, atomic_t *atom)
+{
+ return atomic_raw_clear_bit(nr, (unsigned long *)&atom->counter);
+}
diff --git a/roms/opensbi/lib/sbi/riscv_hardfp.S b/roms/opensbi/lib/sbi/riscv_hardfp.S
new file mode 100644
index 000000000..f363908a4
--- /dev/null
+++ b/roms/opensbi/lib/sbi/riscv_hardfp.S
@@ -0,0 +1,171 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifdef __riscv_flen
+
+#if __riscv_flen != 64
+# error single-float only is not supported
+#endif
+
+#define get_f32(which) fmv.x.s a0, which; jr t0
+#define put_f32(which) fmv.s.x which, a0; jr t0
+#if __riscv_xlen == 64
+# define get_f64(which) fmv.x.d a0, which; jr t0
+# define put_f64(which) fmv.d.x which, a0; jr t0
+#else
+# define get_f64(which) fsd which, 0(a0); jr t0
+# define put_f64(which) fld which, 0(a0); jr t0
+#endif
+
+ .text
+ .option norvc
+ .globl get_f32_reg
+ get_f32_reg:
+ get_f32(f0)
+ get_f32(f1)
+ get_f32(f2)
+ get_f32(f3)
+ get_f32(f4)
+ get_f32(f5)
+ get_f32(f6)
+ get_f32(f7)
+ get_f32(f8)
+ get_f32(f9)
+ get_f32(f10)
+ get_f32(f11)
+ get_f32(f12)
+ get_f32(f13)
+ get_f32(f14)
+ get_f32(f15)
+ get_f32(f16)
+ get_f32(f17)
+ get_f32(f18)
+ get_f32(f19)
+ get_f32(f20)
+ get_f32(f21)
+ get_f32(f22)
+ get_f32(f23)
+ get_f32(f24)
+ get_f32(f25)
+ get_f32(f26)
+ get_f32(f27)
+ get_f32(f28)
+ get_f32(f29)
+ get_f32(f30)
+ get_f32(f31)
+
+ .text
+ .globl put_f32_reg
+ put_f32_reg:
+ put_f32(f0)
+ put_f32(f1)
+ put_f32(f2)
+ put_f32(f3)
+ put_f32(f4)
+ put_f32(f5)
+ put_f32(f6)
+ put_f32(f7)
+ put_f32(f8)
+ put_f32(f9)
+ put_f32(f10)
+ put_f32(f11)
+ put_f32(f12)
+ put_f32(f13)
+ put_f32(f14)
+ put_f32(f15)
+ put_f32(f16)
+ put_f32(f17)
+ put_f32(f18)
+ put_f32(f19)
+ put_f32(f20)
+ put_f32(f21)
+ put_f32(f22)
+ put_f32(f23)
+ put_f32(f24)
+ put_f32(f25)
+ put_f32(f26)
+ put_f32(f27)
+ put_f32(f28)
+ put_f32(f29)
+ put_f32(f30)
+ put_f32(f31)
+
+ .text
+ .globl get_f64_reg
+ get_f64_reg:
+ get_f64(f0)
+ get_f64(f1)
+ get_f64(f2)
+ get_f64(f3)
+ get_f64(f4)
+ get_f64(f5)
+ get_f64(f6)
+ get_f64(f7)
+ get_f64(f8)
+ get_f64(f9)
+ get_f64(f10)
+ get_f64(f11)
+ get_f64(f12)
+ get_f64(f13)
+ get_f64(f14)
+ get_f64(f15)
+ get_f64(f16)
+ get_f64(f17)
+ get_f64(f18)
+ get_f64(f19)
+ get_f64(f20)
+ get_f64(f21)
+ get_f64(f22)
+ get_f64(f23)
+ get_f64(f24)
+ get_f64(f25)
+ get_f64(f26)
+ get_f64(f27)
+ get_f64(f28)
+ get_f64(f29)
+ get_f64(f30)
+ get_f64(f31)
+
+ .text
+ .globl put_f64_reg
+ put_f64_reg:
+ put_f64(f0)
+ put_f64(f1)
+ put_f64(f2)
+ put_f64(f3)
+ put_f64(f4)
+ put_f64(f5)
+ put_f64(f6)
+ put_f64(f7)
+ put_f64(f8)
+ put_f64(f9)
+ put_f64(f10)
+ put_f64(f11)
+ put_f64(f12)
+ put_f64(f13)
+ put_f64(f14)
+ put_f64(f15)
+ put_f64(f16)
+ put_f64(f17)
+ put_f64(f18)
+ put_f64(f19)
+ put_f64(f20)
+ put_f64(f21)
+ put_f64(f22)
+ put_f64(f23)
+ put_f64(f24)
+ put_f64(f25)
+ put_f64(f26)
+ put_f64(f27)
+ put_f64(f28)
+ put_f64(f29)
+ put_f64(f30)
+ put_f64(f31)
+
+#endif
diff --git a/roms/opensbi/lib/sbi/riscv_locks.c b/roms/opensbi/lib/sbi/riscv_locks.c
new file mode 100644
index 000000000..4d1d9c0c1
--- /dev/null
+++ b/roms/opensbi/lib/sbi/riscv_locks.c
@@ -0,0 +1,45 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/riscv_barrier.h>
+#include <sbi/riscv_locks.h>
+
+int spin_lock_check(spinlock_t *lock)
+{
+ return (lock->lock == __RISCV_SPIN_UNLOCKED) ? 0 : 1;
+}
+
+int spin_trylock(spinlock_t *lock)
+{
+ int tmp = 1, busy;
+
+ __asm__ __volatile__(
+ " amoswap.w %0, %2, %1\n" RISCV_ACQUIRE_BARRIER
+ : "=r"(busy), "+A"(lock->lock)
+ : "r"(tmp)
+ : "memory");
+
+ return !busy;
+}
+
+void spin_lock(spinlock_t *lock)
+{
+ while (1) {
+ if (spin_lock_check(lock))
+ continue;
+
+ if (spin_trylock(lock))
+ break;
+ }
+}
+
+void spin_unlock(spinlock_t *lock)
+{
+ __smp_store_release(&lock->lock, __RISCV_SPIN_UNLOCKED);
+}
diff --git a/roms/opensbi/lib/sbi/sbi_bitmap.c b/roms/opensbi/lib/sbi/sbi_bitmap.c
new file mode 100644
index 000000000..e74b6bbec
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_bitmap.c
@@ -0,0 +1,40 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/sbi_bitmap.h>
+
+void __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
+ const unsigned long *bitmap2, int bits)
+{
+ int k;
+ int nr = BITS_TO_LONGS(bits);
+
+ for (k = 0; k < nr; k++)
+ dst[k] = bitmap1[k] & bitmap2[k];
+}
+
+void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
+ const unsigned long *bitmap2, int bits)
+{
+ int k;
+ int nr = BITS_TO_LONGS(bits);
+
+ for (k = 0; k < nr; k++)
+ dst[k] = bitmap1[k] | bitmap2[k];
+}
+
+void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
+ const unsigned long *bitmap2, int bits)
+{
+ int k;
+ int nr = BITS_TO_LONGS(bits);
+
+ for (k = 0; k < nr; k++)
+ dst[k] = bitmap1[k] ^ bitmap2[k];
+}
diff --git a/roms/opensbi/lib/sbi/sbi_bitops.c b/roms/opensbi/lib/sbi/sbi_bitops.c
new file mode 100644
index 000000000..de9d0457b
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_bitops.c
@@ -0,0 +1,200 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Atish Patra <atish.patra@wdc.com>
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/sbi_bitops.h>
+
+#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG)
+
+/**
+ * find_first_bit - find the first set bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit number of the first set bit.
+ */
+unsigned long find_first_bit(const unsigned long *addr,
+ unsigned long size)
+{
+ const unsigned long *p = addr;
+ unsigned long result = 0;
+ unsigned long tmp;
+
+ while (size & ~(BITS_PER_LONG-1)) {
+ if ((tmp = *(p++)))
+ goto found;
+ result += BITS_PER_LONG;
+ size -= BITS_PER_LONG;
+ }
+ if (!size)
+ return result;
+
+ tmp = (*p) & (~0UL >> (BITS_PER_LONG - size));
+ if (tmp == 0UL) /* Are any bits set? */
+ return result + size; /* Nope. */
+found:
+ return result + __ffs(tmp);
+}
+
+/**
+ * find_first_zero_bit - find the first cleared bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit number of the first cleared bit.
+ */
+unsigned long find_first_zero_bit(const unsigned long *addr,
+ unsigned long size)
+{
+ const unsigned long *p = addr;
+ unsigned long result = 0;
+ unsigned long tmp;
+
+ while (size & ~(BITS_PER_LONG-1)) {
+ if (~(tmp = *(p++)))
+ goto found;
+ result += BITS_PER_LONG;
+ size -= BITS_PER_LONG;
+ }
+ if (!size)
+ return result;
+
+ tmp = (*p) | (~0UL << size);
+ if (tmp == ~0UL) /* Are any bits zero? */
+ return result + size; /* Nope. */
+found:
+ return result + ffz(tmp);
+}
+
+/**
+ * find_last_bit - find the last set bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit number of the first set bit, or size.
+ */
+unsigned long find_last_bit(const unsigned long *addr,
+ unsigned long size)
+{
+ unsigned long words;
+ unsigned long tmp;
+
+ /* Start at final word. */
+ words = size / BITS_PER_LONG;
+
+ /* Partial final word? */
+ if (size & (BITS_PER_LONG-1)) {
+ tmp = (addr[words] & (~0UL >> (BITS_PER_LONG
+ - (size & (BITS_PER_LONG-1)))));
+ if (tmp)
+ goto found;
+ }
+
+ while (words) {
+ tmp = addr[--words];
+ if (tmp) {
+found:
+ return words * BITS_PER_LONG + __fls(tmp);
+ }
+ }
+
+ /* Not found */
+ return size;
+}
+
+/**
+ * find_next_bit - find the next set bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The bitmap size in bits
+ */
+unsigned long find_next_bit(const unsigned long *addr,
+ unsigned long size, unsigned long offset)
+{
+ const unsigned long *p = addr + BITOP_WORD(offset);
+ unsigned long result = offset & ~(BITS_PER_LONG-1);
+ unsigned long tmp;
+
+ if (offset >= size)
+ return size;
+ size -= result;
+ offset %= BITS_PER_LONG;
+ if (offset) {
+ tmp = *(p++);
+ tmp &= (~0UL << offset);
+ if (size < BITS_PER_LONG)
+ goto found_first;
+ if (tmp)
+ goto found_middle;
+ size -= BITS_PER_LONG;
+ result += BITS_PER_LONG;
+ }
+ while (size & ~(BITS_PER_LONG-1)) {
+ if ((tmp = *(p++)))
+ goto found_middle;
+ result += BITS_PER_LONG;
+ size -= BITS_PER_LONG;
+ }
+ if (!size)
+ return result;
+ tmp = *p;
+
+found_first:
+ tmp &= (~0UL >> (BITS_PER_LONG - size));
+ if (tmp == 0UL) /* Are any bits set? */
+ return result + size; /* Nope. */
+found_middle:
+ return result + __ffs(tmp);
+}
+
+/**
+ * find_next_zero_bit - find the next cleared bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The bitmap size in bits
+ */
+unsigned long find_next_zero_bit(const unsigned long *addr,
+ unsigned long size,
+ unsigned long offset)
+{
+ const unsigned long *p = addr + BITOP_WORD(offset);
+ unsigned long result = offset & ~(BITS_PER_LONG-1);
+ unsigned long tmp;
+
+ if (offset >= size)
+ return size;
+ size -= result;
+ offset %= BITS_PER_LONG;
+ if (offset) {
+ tmp = *(p++);
+ tmp |= ~0UL >> (BITS_PER_LONG - offset);
+ if (size < BITS_PER_LONG)
+ goto found_first;
+ if (~tmp)
+ goto found_middle;
+ size -= BITS_PER_LONG;
+ result += BITS_PER_LONG;
+ }
+ while (size & ~(BITS_PER_LONG-1)) {
+ if (~(tmp = *(p++)))
+ goto found_middle;
+ result += BITS_PER_LONG;
+ size -= BITS_PER_LONG;
+ }
+ if (!size)
+ return result;
+ tmp = *p;
+
+found_first:
+ tmp |= ~0UL << size;
+ if (tmp == ~0UL) /* Are any bits zero? */
+ return result + size; /* Nope. */
+found_middle:
+ return result + ffz(tmp);
+}
diff --git a/roms/opensbi/lib/sbi/sbi_console.c b/roms/opensbi/lib/sbi/sbi_console.c
new file mode 100644
index 000000000..7189b9bf2
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_console.c
@@ -0,0 +1,398 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/riscv_locks.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_scratch.h>
+
+static const struct sbi_platform *console_plat = NULL;
+static spinlock_t console_out_lock = SPIN_LOCK_INITIALIZER;
+
+bool sbi_isprintable(char c)
+{
+ if (((31 < c) && (c < 127)) || (c == '\f') || (c == '\r') ||
+ (c == '\n') || (c == '\t')) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+int sbi_getc(void)
+{
+ return sbi_platform_console_getc(console_plat);
+}
+
+void sbi_putc(char ch)
+{
+ if (ch == '\n')
+ sbi_platform_console_putc(console_plat, '\r');
+ sbi_platform_console_putc(console_plat, ch);
+}
+
+void sbi_puts(const char *str)
+{
+ spin_lock(&console_out_lock);
+ while (*str) {
+ sbi_putc(*str);
+ str++;
+ }
+ spin_unlock(&console_out_lock);
+}
+
+void sbi_gets(char *s, int maxwidth, char endchar)
+{
+ int ch;
+ char *retval = s;
+
+ while ((ch = sbi_getc()) != endchar && ch >= 0 && maxwidth > 1) {
+ *retval = (char)ch;
+ retval++;
+ maxwidth--;
+ }
+ *retval = '\0';
+}
+
+#define PAD_RIGHT 1
+#define PAD_ZERO 2
+#define PAD_ALTERNATE 4
+#define PRINT_BUF_LEN 64
+
+#define va_start(v, l) __builtin_va_start((v), l)
+#define va_end __builtin_va_end
+#define va_arg __builtin_va_arg
+typedef __builtin_va_list va_list;
+
+static void printc(char **out, u32 *out_len, char ch)
+{
+ if (out) {
+ if (*out) {
+ if (out_len && (0 < *out_len)) {
+ **out = ch;
+ ++(*out);
+ (*out_len)--;
+ } else {
+ **out = ch;
+ ++(*out);
+ }
+ }
+ } else {
+ sbi_putc(ch);
+ }
+}
+
+static int prints(char **out, u32 *out_len, const char *string, int width,
+ int flags)
+{
+ int pc = 0;
+ char padchar = ' ';
+
+ if (width > 0) {
+ int len = 0;
+ const char *ptr;
+ for (ptr = string; *ptr; ++ptr)
+ ++len;
+ if (len >= width)
+ width = 0;
+ else
+ width -= len;
+ if (flags & PAD_ZERO)
+ padchar = '0';
+ }
+ if (!(flags & PAD_RIGHT)) {
+ for (; width > 0; --width) {
+ printc(out, out_len, padchar);
+ ++pc;
+ }
+ }
+ for (; *string; ++string) {
+ printc(out, out_len, *string);
+ ++pc;
+ }
+ for (; width > 0; --width) {
+ printc(out, out_len, padchar);
+ ++pc;
+ }
+
+ return pc;
+}
+
+static int printi(char **out, u32 *out_len, long long i, int b, int sg,
+ int width, int flags, int letbase)
+{
+ char print_buf[PRINT_BUF_LEN];
+ char *s;
+ int neg = 0, pc = 0;
+ u64 t;
+ unsigned long long u = i;
+
+ if (sg && b == 10 && i < 0) {
+ neg = 1;
+ u = -i;
+ }
+
+ s = print_buf + PRINT_BUF_LEN - 1;
+ *s = '\0';
+
+ if (!u) {
+ *--s = '0';
+ } else {
+ while (u) {
+ t = u % b;
+ u = u / b;
+ if (t >= 10)
+ t += letbase - '0' - 10;
+ *--s = t + '0';
+ }
+ }
+
+ if (flags & PAD_ALTERNATE) {
+ if ((b == 16) && (letbase == 'A')) {
+ *--s = 'X';
+ } else if ((b == 16) && (letbase == 'a')) {
+ *--s = 'x';
+ }
+ *--s = '0';
+ }
+
+ if (neg) {
+ if (width && (flags & PAD_ZERO)) {
+ printc(out, out_len, '-');
+ ++pc;
+ --width;
+ } else {
+ *--s = '-';
+ }
+ }
+
+ return pc + prints(out, out_len, s, width, flags);
+}
+
+static int print(char **out, u32 *out_len, const char *format, va_list args)
+{
+ int width, flags, acnt = 0;
+ int pc = 0;
+ char scr[2];
+ unsigned long long tmp;
+
+ for (; *format != 0; ++format) {
+ if (*format == '%') {
+ ++format;
+ width = flags = 0;
+ if (*format == '\0')
+ break;
+ if (*format == '%')
+ goto out;
+ /* Get flags */
+ if (*format == '-') {
+ ++format;
+ flags = PAD_RIGHT;
+ }
+ if (*format == '#') {
+ ++format;
+ flags |= PAD_ALTERNATE;
+ }
+ while (*format == '0') {
+ ++format;
+ flags |= PAD_ZERO;
+ }
+ /* Get width */
+ for (; *format >= '0' && *format <= '9'; ++format) {
+ width *= 10;
+ width += *format - '0';
+ }
+ if (*format == 's') {
+ char *s = va_arg(args, char *);
+ acnt += sizeof(char *);
+ pc += prints(out, out_len, s ? s : "(null)",
+ width, flags);
+ continue;
+ }
+ if ((*format == 'd') || (*format == 'i')) {
+ pc += printi(out, out_len, va_arg(args, int),
+ 10, 1, width, flags, '0');
+ acnt += sizeof(int);
+ continue;
+ }
+ if (*format == 'x') {
+ pc += printi(out, out_len,
+ va_arg(args, unsigned int), 16, 0,
+ width, flags, 'a');
+ acnt += sizeof(unsigned int);
+ continue;
+ }
+ if (*format == 'X') {
+ pc += printi(out, out_len,
+ va_arg(args, unsigned int), 16, 0,
+ width, flags, 'A');
+ acnt += sizeof(unsigned int);
+ continue;
+ }
+ if (*format == 'u') {
+ pc += printi(out, out_len,
+ va_arg(args, unsigned int), 10, 0,
+ width, flags, 'a');
+ acnt += sizeof(unsigned int);
+ continue;
+ }
+ if (*format == 'p') {
+ pc += printi(out, out_len,
+ va_arg(args, unsigned long), 16, 0,
+ width, flags, 'a');
+ acnt += sizeof(unsigned long);
+ continue;
+ }
+ if (*format == 'P') {
+ pc += printi(out, out_len,
+ va_arg(args, unsigned long), 16, 0,
+ width, flags, 'A');
+ acnt += sizeof(unsigned long);
+ continue;
+ }
+ if (*format == 'l' && *(format + 1) == 'l') {
+ while (acnt &
+ (sizeof(unsigned long long) - 1)) {
+ va_arg(args, int);
+ acnt += sizeof(int);
+ }
+ if (sizeof(unsigned long long) ==
+ sizeof(unsigned long)) {
+ tmp = va_arg(args, unsigned long long);
+ acnt += sizeof(unsigned long long);
+ } else {
+ ((unsigned long *)&tmp)[0] =
+ va_arg(args, unsigned long);
+ ((unsigned long *)&tmp)[1] =
+ va_arg(args, unsigned long);
+ acnt += 2 * sizeof(unsigned long);
+ }
+ if (*(format + 2) == 'u') {
+ format += 2;
+ pc += printi(out, out_len, tmp, 10, 0,
+ width, flags, 'a');
+ } else if (*(format + 2) == 'x') {
+ format += 2;
+ pc += printi(out, out_len, tmp, 16, 0,
+ width, flags, 'a');
+ } else if (*(format + 2) == 'X') {
+ format += 2;
+ pc += printi(out, out_len, tmp, 16, 0,
+ width, flags, 'A');
+ } else {
+ format += 1;
+ pc += printi(out, out_len, tmp, 10, 1,
+ width, flags, '0');
+ }
+ continue;
+ } else if (*format == 'l') {
+ if (*(format + 1) == 'u') {
+ format += 1;
+ pc += printi(
+ out, out_len,
+ va_arg(args, unsigned long), 10,
+ 0, width, flags, 'a');
+ } else if (*(format + 1) == 'x') {
+ format += 1;
+ pc += printi(
+ out, out_len,
+ va_arg(args, unsigned long), 16,
+ 0, width, flags, 'a');
+ acnt += sizeof(unsigned long);
+ } else if (*(format + 1) == 'X') {
+ format += 1;
+ pc += printi(
+ out, out_len,
+ va_arg(args, unsigned long), 16,
+ 0, width, flags, 'A');
+ acnt += sizeof(unsigned long);
+ } else {
+ pc += printi(out, out_len,
+ va_arg(args, long), 10, 1,
+ width, flags, '0');
+ acnt += sizeof(long);
+ }
+ }
+ if (*format == 'c') {
+ /* char are converted to int then pushed on the stack */
+ scr[0] = va_arg(args, int);
+ scr[1] = '\0';
+ pc += prints(out, out_len, scr, width, flags);
+ acnt += sizeof(int);
+ continue;
+ }
+ } else {
+ out:
+ printc(out, out_len, *format);
+ ++pc;
+ }
+ }
+ if (out)
+ **out = '\0';
+
+ return pc;
+}
+
+int sbi_sprintf(char *out, const char *format, ...)
+{
+ va_list args;
+ int retval;
+
+ va_start(args, format);
+ retval = print(&out, NULL, format, args);
+ va_end(args);
+
+ return retval;
+}
+
+int sbi_snprintf(char *out, u32 out_sz, const char *format, ...)
+{
+ va_list args;
+ int retval;
+
+ va_start(args, format);
+ retval = print(&out, &out_sz, format, args);
+ va_end(args);
+
+ return retval;
+}
+
+int sbi_printf(const char *format, ...)
+{
+ va_list args;
+ int retval;
+
+ spin_lock(&console_out_lock);
+ va_start(args, format);
+ retval = print(NULL, NULL, format, args);
+ va_end(args);
+ spin_unlock(&console_out_lock);
+
+ return retval;
+}
+
+int sbi_dprintf(const char *format, ...)
+{
+ va_list args;
+ int retval = 0;
+ struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
+
+ va_start(args, format);
+ if (scratch->options & SBI_SCRATCH_DEBUG_PRINTS)
+ retval = print(NULL, NULL, format, args);
+ va_end(args);
+
+ return retval;
+}
+
+int sbi_console_init(struct sbi_scratch *scratch)
+{
+ console_plat = sbi_platform_ptr(scratch);
+
+ return sbi_platform_console_init(console_plat);
+}
diff --git a/roms/opensbi/lib/sbi/sbi_domain.c b/roms/opensbi/lib/sbi/sbi_domain.c
new file mode 100644
index 000000000..195c9413c
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_domain.c
@@ -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);
+}
diff --git a/roms/opensbi/lib/sbi/sbi_ecall.c b/roms/opensbi/lib/sbi/sbi_ecall.c
new file mode 100644
index 000000000..e92a53930
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_ecall.c
@@ -0,0 +1,175 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_ecall.h>
+#include <sbi/sbi_ecall_interface.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_trap.h>
+
+u16 sbi_ecall_version_major(void)
+{
+ return SBI_ECALL_VERSION_MAJOR;
+}
+
+u16 sbi_ecall_version_minor(void)
+{
+ return SBI_ECALL_VERSION_MINOR;
+}
+
+static unsigned long ecall_impid = SBI_OPENSBI_IMPID;
+
+unsigned long sbi_ecall_get_impid(void)
+{
+ return ecall_impid;
+}
+
+void sbi_ecall_set_impid(unsigned long impid)
+{
+ ecall_impid = impid;
+}
+
+static SBI_LIST_HEAD(ecall_exts_list);
+
+struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
+{
+ struct sbi_ecall_extension *t, *ret = NULL;
+
+ sbi_list_for_each_entry(t, &ecall_exts_list, head) {
+ if (t->extid_start <= extid && extid <= t->extid_end) {
+ ret = t;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)
+{
+ struct sbi_ecall_extension *t;
+
+ if (!ext || (ext->extid_end < ext->extid_start) || !ext->handle)
+ return SBI_EINVAL;
+
+ sbi_list_for_each_entry(t, &ecall_exts_list, head) {
+ unsigned long start = t->extid_start;
+ unsigned long end = t->extid_end;
+ if (end < ext->extid_start || ext->extid_end < start)
+ /* no overlap */;
+ else
+ return SBI_EINVAL;
+ }
+
+ SBI_INIT_LIST_HEAD(&ext->head);
+ sbi_list_add_tail(&ext->head, &ecall_exts_list);
+
+ return 0;
+}
+
+void sbi_ecall_unregister_extension(struct sbi_ecall_extension *ext)
+{
+ bool found = FALSE;
+ struct sbi_ecall_extension *t;
+
+ if (!ext)
+ return;
+
+ sbi_list_for_each_entry(t, &ecall_exts_list, head) {
+ if (t == ext) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (found)
+ sbi_list_del_init(&ext->head);
+}
+
+int sbi_ecall_handler(struct sbi_trap_regs *regs)
+{
+ int ret = 0;
+ struct sbi_ecall_extension *ext;
+ unsigned long extension_id = regs->a7;
+ unsigned long func_id = regs->a6;
+ struct sbi_trap_info trap = {0};
+ unsigned long out_val = 0;
+ bool is_0_1_spec = 0;
+
+ ext = sbi_ecall_find_extension(extension_id);
+ if (ext && ext->handle) {
+ ret = ext->handle(extension_id, func_id,
+ 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;
+ } else {
+ ret = SBI_ENOTSUPP;
+ }
+
+ if (ret == SBI_ETRAP) {
+ trap.epc = regs->mepc;
+ sbi_trap_redirect(regs, &trap);
+ } else {
+ if (ret < SBI_LAST_ERR) {
+ sbi_printf("%s: Invalid error %d for ext=0x%lx "
+ "func=0x%lx\n", __func__, ret,
+ extension_id, func_id);
+ ret = SBI_ERR_FAILED;
+ }
+
+ /*
+ * This function should return non-zero value only in case of
+ * fatal error. However, there is no good way to distinguish
+ * between a fatal and non-fatal errors yet. That's why we treat
+ * every return value except ETRAP as non-fatal and just return
+ * accordingly for now. Once fatal errors are defined, that
+ * case should be handled differently.
+ */
+ regs->mepc += 4;
+ regs->a0 = ret;
+ if (!is_0_1_spec)
+ regs->a1 = out_val;
+ }
+
+ return 0;
+}
+
+int sbi_ecall_init(void)
+{
+ int ret;
+
+ /* The order of below registrations is performance optimized */
+ ret = sbi_ecall_register_extension(&ecall_time);
+ if (ret)
+ return ret;
+ ret = sbi_ecall_register_extension(&ecall_rfence);
+ if (ret)
+ return ret;
+ ret = sbi_ecall_register_extension(&ecall_ipi);
+ if (ret)
+ return ret;
+ ret = sbi_ecall_register_extension(&ecall_base);
+ if (ret)
+ return ret;
+ ret = sbi_ecall_register_extension(&ecall_hsm);
+ if (ret)
+ return ret;
+ ret = sbi_ecall_register_extension(&ecall_srst);
+ if (ret)
+ return ret;
+ ret = sbi_ecall_register_extension(&ecall_legacy);
+ if (ret)
+ return ret;
+ ret = sbi_ecall_register_extension(&ecall_vendor);
+ if (ret)
+ return ret;
+
+ return 0;
+}
diff --git a/roms/opensbi/lib/sbi/sbi_ecall_base.c b/roms/opensbi/lib/sbi/sbi_ecall_base.c
new file mode 100644
index 000000000..786d2ac67
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_ecall_base.c
@@ -0,0 +1,79 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ * Atish Patra <atish.patra@wdc.com>
+ */
+
+#include <sbi/sbi_ecall.h>
+#include <sbi/sbi_ecall_interface.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_trap.h>
+#include <sbi/sbi_version.h>
+#include <sbi/riscv_asm.h>
+
+static int sbi_ecall_base_probe(unsigned long extid, unsigned long *out_val)
+{
+ struct sbi_ecall_extension *ext;
+
+ ext = sbi_ecall_find_extension(extid);
+ if (!ext) {
+ *out_val = 0;
+ return 0;
+ }
+
+ if (ext->probe)
+ return ext->probe(extid, out_val);
+
+ *out_val = 1;
+ return 0;
+}
+
+static int sbi_ecall_base_handler(unsigned long extid, unsigned long funcid,
+ const struct sbi_trap_regs *regs,
+ unsigned long *out_val,
+ struct sbi_trap_info *out_trap)
+{
+ int ret = 0;
+
+ switch (funcid) {
+ case SBI_EXT_BASE_GET_SPEC_VERSION:
+ *out_val = (SBI_ECALL_VERSION_MAJOR <<
+ SBI_SPEC_VERSION_MAJOR_OFFSET) &
+ (SBI_SPEC_VERSION_MAJOR_MASK <<
+ SBI_SPEC_VERSION_MAJOR_OFFSET);
+ *out_val = *out_val | SBI_ECALL_VERSION_MINOR;
+ break;
+ case SBI_EXT_BASE_GET_IMP_ID:
+ *out_val = sbi_ecall_get_impid();
+ break;
+ case SBI_EXT_BASE_GET_IMP_VERSION:
+ *out_val = OPENSBI_VERSION;
+ break;
+ case SBI_EXT_BASE_GET_MVENDORID:
+ *out_val = csr_read(CSR_MVENDORID);
+ break;
+ case SBI_EXT_BASE_GET_MARCHID:
+ *out_val = csr_read(CSR_MARCHID);
+ break;
+ case SBI_EXT_BASE_GET_MIMPID:
+ *out_val = csr_read(CSR_MIMPID);
+ break;
+ case SBI_EXT_BASE_PROBE_EXT:
+ ret = sbi_ecall_base_probe(regs->a0, out_val);
+ break;
+ default:
+ ret = SBI_ENOTSUPP;
+ }
+
+ return ret;
+}
+
+struct sbi_ecall_extension ecall_base = {
+ .extid_start = SBI_EXT_BASE,
+ .extid_end = SBI_EXT_BASE,
+ .handle = sbi_ecall_base_handler,
+};
diff --git a/roms/opensbi/lib/sbi/sbi_ecall_hsm.c b/roms/opensbi/lib/sbi/sbi_ecall_hsm.c
new file mode 100644
index 000000000..df29d5196
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_ecall_hsm.c
@@ -0,0 +1,59 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * 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,
+ 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:
+ 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(sbi_domain_thishart_ptr(),
+ regs->a0);
+ ret = sbi_hsm_hart_state_to_status(hstate);
+ break;
+ default:
+ ret = SBI_ENOTSUPP;
+ };
+ if (ret >= 0) {
+ *out_val = ret;
+ ret = 0;
+ }
+
+ return ret;
+}
+
+struct sbi_ecall_extension ecall_hsm = {
+ .extid_start = SBI_EXT_HSM,
+ .extid_end = SBI_EXT_HSM,
+ .handle = sbi_ecall_hsm_handler,
+};
diff --git a/roms/opensbi/lib/sbi/sbi_ecall_legacy.c b/roms/opensbi/lib/sbi/sbi_ecall_legacy.c
new file mode 100644
index 000000000..1a7fe26e4
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_ecall_legacy.c
@@ -0,0 +1,124 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ * Atish Patra <atish.patra@wdc.com>
+ */
+
+#include <sbi/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>
+#include <sbi/sbi_hsm.h>
+#include <sbi/sbi_ipi.h>
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_system.h>
+#include <sbi/sbi_timer.h>
+#include <sbi/sbi_tlb.h>
+#include <sbi/sbi_trap.h>
+#include <sbi/sbi_unpriv.h>
+#include <sbi/sbi_hart.h>
+
+static int sbi_load_hart_mask_unpriv(ulong *pmask, ulong *hmask,
+ struct sbi_trap_info *uptrap)
+{
+ ulong mask = 0;
+
+ if (pmask) {
+ mask = sbi_load_ulong(pmask, uptrap);
+ if (uptrap->cause)
+ return SBI_ETRAP;
+ } else {
+ sbi_hsm_hart_started_mask(sbi_domain_thishart_ptr(),
+ 0, &mask);
+ }
+ *hmask = mask;
+
+ return 0;
+}
+
+static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
+ const struct sbi_trap_regs *regs,
+ unsigned long *out_val,
+ struct sbi_trap_info *out_trap)
+{
+ int ret = 0;
+ struct sbi_tlb_info tlb_info;
+ u32 source_hart = current_hartid();
+ ulong hmask = 0;
+
+ switch (extid) {
+ case SBI_EXT_0_1_SET_TIMER:
+#if __riscv_xlen == 32
+ sbi_timer_event_start((((u64)regs->a1 << 32) | (u64)regs->a0));
+#else
+ sbi_timer_event_start((u64)regs->a0);
+#endif
+ break;
+ case SBI_EXT_0_1_CONSOLE_PUTCHAR:
+ sbi_putc(regs->a0);
+ break;
+ case SBI_EXT_0_1_CONSOLE_GETCHAR:
+ ret = sbi_getc();
+ break;
+ case SBI_EXT_0_1_CLEAR_IPI:
+ sbi_ipi_clear_smode();
+ break;
+ case SBI_EXT_0_1_SEND_IPI:
+ 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 *)regs->a0,
+ &hmask, out_trap);
+ if (ret != SBI_ETRAP) {
+ SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, 0,
+ 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 *)regs->a0,
+ &hmask, out_trap);
+ if (ret != SBI_ETRAP) {
+ 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 *)regs->a0,
+ &hmask, out_trap);
+ if (ret != SBI_ETRAP) {
+ 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_SRST_RESET_TYPE_SHUTDOWN,
+ SBI_SRST_RESET_REASON_NONE);
+ break;
+ default:
+ ret = SBI_ENOTSUPP;
+ };
+
+ return ret;
+}
+
+struct sbi_ecall_extension ecall_legacy = {
+ .extid_start = SBI_EXT_0_1_SET_TIMER,
+ .extid_end = SBI_EXT_0_1_SHUTDOWN,
+ .handle = sbi_ecall_legacy_handler,
+};
diff --git a/roms/opensbi/lib/sbi/sbi_ecall_replace.c b/roms/opensbi/lib/sbi/sbi_ecall_replace.c
new file mode 100644
index 000000000..a7935d973
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_ecall_replace.c
@@ -0,0 +1,196 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ * Atish Patra <atish.patra@wdc.com>
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/sbi_ecall.h>
+#include <sbi/sbi_ecall_interface.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_ipi.h>
+#include <sbi/sbi_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,
+ 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)regs->a1 << 32) | (u64)regs->a0));
+#else
+ sbi_timer_event_start((u64)regs->a0);
+#endif
+ } else
+ ret = SBI_ENOTSUPP;
+
+ return ret;
+}
+
+struct sbi_ecall_extension ecall_time = {
+ .extid_start = SBI_EXT_TIME,
+ .extid_end = SBI_EXT_TIME,
+ .handle = sbi_ecall_time_handler,
+};
+
+static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
+ const struct sbi_trap_regs *regs,
+ unsigned long *out_val,
+ struct sbi_trap_info *out_trap)
+{
+ int ret = 0;
+ unsigned long vmid;
+ struct sbi_tlb_info tlb_info;
+ u32 source_hart = current_hartid();
+
+ if (funcid >= SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA &&
+ funcid <= SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID)
+ if (!misa_extension('H'))
+ return SBI_ENOTSUPP;
+
+ switch (funcid) {
+ case SBI_EXT_RFENCE_REMOTE_FENCE_I:
+ SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, 0,
+ sbi_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, 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, 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, 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, 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, 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, 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;
+ };
+
+ return ret;
+}
+
+struct sbi_ecall_extension ecall_rfence = {
+ .extid_start = SBI_EXT_RFENCE,
+ .extid_end = SBI_EXT_RFENCE,
+ .handle = sbi_ecall_rfence_handler,
+};
+
+static int sbi_ecall_ipi_handler(unsigned long extid, unsigned long funcid,
+ const struct sbi_trap_regs *regs,
+ unsigned long *out_val,
+ struct sbi_trap_info *out_trap)
+{
+ int ret = 0;
+
+ if (funcid == SBI_EXT_IPI_SEND_IPI)
+ ret = sbi_ipi_send_smode(regs->a0, regs->a1);
+ else
+ ret = SBI_ENOTSUPP;
+
+ return ret;
+}
+
+struct sbi_ecall_extension ecall_ipi = {
+ .extid_start = SBI_EXT_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,
+};
diff --git a/roms/opensbi/lib/sbi/sbi_ecall_vendor.c b/roms/opensbi/lib/sbi/sbi_ecall_vendor.c
new file mode 100644
index 000000000..925282963
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_ecall_vendor.c
@@ -0,0 +1,40 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ * Atish Patra <atish.patra@wdc.com>
+ */
+
+#include <sbi/sbi_ecall.h>
+#include <sbi/sbi_ecall_interface.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_trap.h>
+
+static int sbi_ecall_vendor_probe(unsigned long extid,
+ unsigned long *out_val)
+{
+ *out_val = sbi_platform_vendor_ext_check(sbi_platform_thishart_ptr(),
+ extid);
+ return 0;
+}
+
+static int sbi_ecall_vendor_handler(unsigned long extid, unsigned long funcid,
+ 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, regs,
+ out_val, out_trap);
+}
+
+struct sbi_ecall_extension ecall_vendor = {
+ .extid_start = SBI_EXT_VENDOR_START,
+ .extid_end = SBI_EXT_VENDOR_END,
+ .probe = sbi_ecall_vendor_probe,
+ .handle = sbi_ecall_vendor_handler,
+};
diff --git a/roms/opensbi/lib/sbi/sbi_emulate_csr.c b/roms/opensbi/lib/sbi/sbi_emulate_csr.c
new file mode 100644
index 000000000..bee7761c4
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_emulate_csr.c
@@ -0,0 +1,188 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_bitops.h>
+#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;
+ 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;
+#else
+ bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
+#endif
+
+ switch (csr_num) {
+ case CSR_HTIMEDELTA:
+ if (prev_mode == PRV_S && !virt)
+ *csr_val = sbi_timer_get_delta();
+ else
+ ret = SBI_ENOTSUPP;
+ break;
+ case CSR_CYCLE:
+ if (!hpm_allowed(csr_num - CSR_CYCLE, prev_mode, virt))
+ return SBI_ENOTSUPP;
+ *csr_val = csr_read(CSR_MCYCLE);
+ break;
+ case CSR_TIME:
+ /*
+ * 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 (!hpm_allowed(csr_num - CSR_CYCLE, prev_mode, virt))
+ return SBI_ENOTSUPP;
+ *csr_val = csr_read(CSR_MINSTRET);
+ break;
+
+#if __riscv_xlen == 32
+ case CSR_HTIMEDELTAH:
+ if (prev_mode == PRV_S && !virt)
+ *csr_val = sbi_timer_get_delta() >> 32;
+ else
+ ret = SBI_ENOTSUPP;
+ break;
+ case CSR_CYCLEH:
+ if (!hpm_allowed(csr_num - CSR_CYCLEH, prev_mode, virt))
+ return SBI_ENOTSUPP;
+ *csr_val = csr_read(CSR_MCYCLEH);
+ break;
+ case CSR_TIMEH:
+ /* Refer comments on TIME CSR above. */
+ *csr_val = (virt) ? sbi_timer_virt_value() >> 32:
+ sbi_timer_value() >> 32;
+ break;
+ case CSR_INSTRETH:
+ if (!hpm_allowed(csr_num - CSR_CYCLEH, prev_mode, virt))
+ return SBI_ENOTSUPP;
+ *csr_val = csr_read(CSR_MINSTRETH);
+ break;
+#endif
+
+#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;
+ };
+
+ if (ret)
+ sbi_dprintf("%s: hartid%d: invalid csr_num=0x%x\n",
+ __func__, current_hartid(), csr_num);
+
+ return ret;
+}
+
+int sbi_emulate_csr_write(int csr_num, struct sbi_trap_regs *regs,
+ ulong csr_val)
+{
+ int ret = 0;
+ ulong prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
+#if __riscv_xlen == 32
+ bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
+#else
+ bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
+#endif
+
+ switch (csr_num) {
+ case CSR_HTIMEDELTA:
+ if (prev_mode == PRV_S && !virt)
+ sbi_timer_set_delta(csr_val);
+ else
+ ret = SBI_ENOTSUPP;
+ break;
+#if __riscv_xlen == 32
+ case CSR_HTIMEDELTAH:
+ if (prev_mode == PRV_S && !virt)
+ sbi_timer_set_delta_upper(csr_val);
+ else
+ ret = SBI_ENOTSUPP;
+ break;
+#endif
+ default:
+ ret = SBI_ENOTSUPP;
+ break;
+ };
+
+ if (ret)
+ sbi_dprintf("%s: hartid%d: invalid csr_num=0x%x\n",
+ __func__, current_hartid(), csr_num);
+
+ return ret;
+}
diff --git a/roms/opensbi/lib/sbi/sbi_expected_trap.S b/roms/opensbi/lib/sbi/sbi_expected_trap.S
new file mode 100644
index 000000000..24891c74c
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_expected_trap.S
@@ -0,0 +1,56 @@
+/*
+ * 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_trap.h>
+
+ /*
+ * We assume that faulting instruction is is 4-byte long and blindly
+ * increment SEPC by 4.
+ *
+ * The trap info will be saved as follows:
+ * A3 <- pointer struct sbi_trap_info
+ * A4 <- temporary
+ */
+
+ .align 3
+ .global __sbi_expected_trap
+__sbi_expected_trap:
+ /* Without H-extension so, MTVAL2 and MTINST CSRs not available */
+ csrr a4, CSR_MEPC
+ REG_S a4, SBI_TRAP_INFO_OFFSET(epc)(a3)
+ csrr a4, CSR_MCAUSE
+ REG_S a4, SBI_TRAP_INFO_OFFSET(cause)(a3)
+ csrr a4, CSR_MTVAL
+ REG_S a4, SBI_TRAP_INFO_OFFSET(tval)(a3)
+ REG_S zero, SBI_TRAP_INFO_OFFSET(tval2)(a3)
+ REG_S zero, SBI_TRAP_INFO_OFFSET(tinst)(a3)
+ csrr a4, CSR_MEPC
+ addi a4, a4, 4
+ csrw CSR_MEPC, a4
+ mret
+
+ .align 3
+ .global __sbi_expected_trap_hext
+__sbi_expected_trap_hext:
+ /* With H-extension so, MTVAL2 and MTINST CSRs available */
+ csrr a4, CSR_MEPC
+ REG_S a4, SBI_TRAP_INFO_OFFSET(epc)(a3)
+ csrr a4, CSR_MCAUSE
+ REG_S a4, SBI_TRAP_INFO_OFFSET(cause)(a3)
+ csrr a4, CSR_MTVAL
+ REG_S a4, SBI_TRAP_INFO_OFFSET(tval)(a3)
+ csrr a4, CSR_MTVAL2
+ REG_S a4, SBI_TRAP_INFO_OFFSET(tval2)(a3)
+ csrr a4, CSR_MTINST
+ REG_S a4, SBI_TRAP_INFO_OFFSET(tinst)(a3)
+ csrr a4, CSR_MEPC
+ addi a4, a4, 4
+ csrw CSR_MEPC, a4
+ mret
diff --git a/roms/opensbi/lib/sbi/sbi_fifo.c b/roms/opensbi/lib/sbi/sbi_fifo.c
new file mode 100644
index 000000000..8d1dbf044
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_fifo.c
@@ -0,0 +1,192 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Atish Patra<atish.patra@wdc.com>
+ *
+ */
+#include <sbi/riscv_locks.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_fifo.h>
+#include <sbi/sbi_string.h>
+
+void sbi_fifo_init(struct sbi_fifo *fifo, void *queue_mem, u16 entries,
+ u16 entry_size)
+{
+ fifo->queue = queue_mem;
+ fifo->num_entries = entries;
+ fifo->entry_size = entry_size;
+ SPIN_LOCK_INIT(&fifo->qlock);
+ fifo->avail = fifo->tail = 0;
+ sbi_memset(fifo->queue, 0, (size_t)entries * entry_size);
+}
+
+/* Note: must be called with fifo->qlock held */
+static inline bool __sbi_fifo_is_full(struct sbi_fifo *fifo)
+{
+ return (fifo->avail == fifo->num_entries) ? TRUE : FALSE;
+}
+
+u16 sbi_fifo_avail(struct sbi_fifo *fifo)
+{
+ u16 ret;
+
+ if (!fifo)
+ return 0;
+
+ spin_lock(&fifo->qlock);
+ ret = fifo->avail;
+ spin_unlock(&fifo->qlock);
+
+ return ret;
+}
+
+bool sbi_fifo_is_full(struct sbi_fifo *fifo)
+{
+ bool ret;
+
+ spin_lock(&fifo->qlock);
+ ret = __sbi_fifo_is_full(fifo);
+ spin_unlock(&fifo->qlock);
+
+ return ret;
+}
+
+/* Note: must be called with fifo->qlock held */
+static inline void __sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data)
+{
+ u32 head;
+
+ head = (u32)fifo->tail + fifo->avail;
+ if (head >= fifo->num_entries)
+ head = head - fifo->num_entries;
+
+ sbi_memcpy(fifo->queue + head * fifo->entry_size, data, fifo->entry_size);
+
+ fifo->avail++;
+}
+
+
+/* Note: must be called with fifo->qlock held */
+static inline bool __sbi_fifo_is_empty(struct sbi_fifo *fifo)
+{
+ return (fifo->avail == 0) ? TRUE : FALSE;
+}
+
+bool sbi_fifo_is_empty(struct sbi_fifo *fifo)
+{
+ bool ret;
+
+ spin_lock(&fifo->qlock);
+ ret = __sbi_fifo_is_empty(fifo);
+ spin_unlock(&fifo->qlock);
+
+ return ret;
+}
+
+/* Note: must be called with fifo->qlock held */
+static inline void __sbi_fifo_reset(struct sbi_fifo *fifo)
+{
+ size_t size = (size_t)fifo->num_entries * fifo->entry_size;
+
+ fifo->avail = 0;
+ fifo->tail = 0;
+ sbi_memset(fifo->queue, 0, size);
+}
+
+bool sbi_fifo_reset(struct sbi_fifo *fifo)
+{
+ if (!fifo)
+ return FALSE;
+
+ spin_lock(&fifo->qlock);
+ __sbi_fifo_reset(fifo);
+ spin_unlock(&fifo->qlock);
+
+ return TRUE;
+}
+
+/**
+ * Provide a helper function to do inplace update to the fifo.
+ * Note: The callback function is called with lock being held.
+ *
+ * **Do not** invoke any other fifo function from callback. Otherwise, it will
+ * lead to deadlock.
+ */
+int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
+ int (*fptr)(void *in, void *data))
+{
+ int i, index = 0;
+ int ret = SBI_FIFO_UNCHANGED;
+ void *entry;
+
+ if (!fifo || !in)
+ return ret;
+
+ spin_lock(&fifo->qlock);
+
+ if (__sbi_fifo_is_empty(fifo)) {
+ spin_unlock(&fifo->qlock);
+ return ret;
+ }
+
+ for (i = 0; i < fifo->avail; i++) {
+ index = fifo->tail + i;
+ if (index >= fifo->num_entries)
+ index = index - fifo->num_entries;
+ entry = (void *)fifo->queue + (u32)index * fifo->entry_size;
+ ret = fptr(in, entry);
+
+ if (ret == SBI_FIFO_SKIP || ret == SBI_FIFO_UPDATED) {
+ break;
+ }
+ }
+ spin_unlock(&fifo->qlock);
+
+ return ret;
+}
+
+int sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data)
+{
+ if (!fifo || !data)
+ return SBI_EINVAL;
+
+ spin_lock(&fifo->qlock);
+
+ if (__sbi_fifo_is_full(fifo)) {
+ spin_unlock(&fifo->qlock);
+ return SBI_ENOSPC;
+ }
+ __sbi_fifo_enqueue(fifo, data);
+
+ spin_unlock(&fifo->qlock);
+
+ return 0;
+}
+
+int sbi_fifo_dequeue(struct sbi_fifo *fifo, void *data)
+{
+ if (!fifo || !data)
+ return SBI_EINVAL;
+
+ spin_lock(&fifo->qlock);
+
+ if (__sbi_fifo_is_empty(fifo)) {
+ spin_unlock(&fifo->qlock);
+ return SBI_ENOENT;
+ }
+
+ sbi_memcpy(data, fifo->queue + (u32)fifo->tail * fifo->entry_size,
+ fifo->entry_size);
+
+ fifo->avail--;
+ fifo->tail++;
+ if (fifo->tail >= fifo->num_entries)
+ fifo->tail = 0;
+
+ spin_unlock(&fifo->qlock);
+
+ return 0;
+}
diff --git a/roms/opensbi/lib/sbi/sbi_hart.c b/roms/opensbi/lib/sbi/sbi_hart.c
new file mode 100644
index 000000000..fc86e9f31
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_hart.c
@@ -0,0 +1,536 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_barrier.h>
+#include <sbi/riscv_encoding.h>
+#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);
+
+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)
+{
+ unsigned long mstatus_val = 0;
+
+ /* Enable FPU */
+ if (misa_extension('D') || misa_extension('F'))
+ mstatus_val |= MSTATUS_FS;
+
+ /* Enable Vector context */
+ if (misa_extension('V'))
+ mstatus_val |= MSTATUS_VS;
+
+ csr_write(CSR_MSTATUS, mstatus_val);
+
+ /* Enable user/supervisor use of perf counters */
+ if (misa_extension('S') &&
+ sbi_hart_has_feature(scratch, SBI_HART_HAS_SCOUNTEREN))
+ csr_write(CSR_SCOUNTEREN, -1);
+ if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTEREN))
+ csr_write(CSR_MCOUNTEREN, -1);
+
+ /* Disable all interrupts */
+ csr_write(CSR_MIE, 0);
+
+ /* Disable S-mode paging */
+ if (misa_extension('S'))
+ csr_write(CSR_SATP, 0);
+}
+
+static int fp_init(struct sbi_scratch *scratch)
+{
+#ifdef __riscv_flen
+ int i;
+#endif
+
+ if (!misa_extension('D') && !misa_extension('F'))
+ return 0;
+
+ if (!(csr_read(CSR_MSTATUS) & MSTATUS_FS))
+ return SBI_EINVAL;
+
+#ifdef __riscv_flen
+ for (i = 0; i < 32; i++)
+ init_fp_reg(i);
+ csr_write(CSR_FCSR, 0);
+#endif
+
+ return 0;
+}
+
+static int delegate_traps(struct sbi_scratch *scratch)
+{
+ const struct sbi_platform *plat = sbi_platform_ptr(scratch);
+ unsigned long interrupts, exceptions;
+
+ if (!misa_extension('S'))
+ /* No delegation possible as mideleg does not exist */
+ return 0;
+
+ /* Send M-mode interrupts and most exceptions to S-mode */
+ interrupts = MIP_SSIP | MIP_STIP | MIP_SEIP;
+ exceptions = (1U << CAUSE_MISALIGNED_FETCH) | (1U << CAUSE_BREAKPOINT) |
+ (1U << CAUSE_USER_ECALL);
+ if (sbi_platform_has_mfaults_delegation(plat))
+ exceptions |= (1U << CAUSE_FETCH_PAGE_FAULT) |
+ (1U << CAUSE_LOAD_PAGE_FAULT) |
+ (1U << CAUSE_STORE_PAGE_FAULT);
+
+ /*
+ * If hypervisor extension available then we only handle hypervisor
+ * calls (i.e. ecalls from HS-mode) in M-mode.
+ *
+ * The HS-mode will additionally handle supervisor calls (i.e. ecalls
+ * from VS-mode), Guest page faults and Virtual interrupts.
+ */
+ if (misa_extension('H')) {
+ exceptions |= (1U << CAUSE_VIRTUAL_SUPERVISOR_ECALL);
+ exceptions |= (1U << CAUSE_FETCH_GUEST_PAGE_FAULT);
+ exceptions |= (1U << CAUSE_LOAD_GUEST_PAGE_FAULT);
+ exceptions |= (1U << CAUSE_VIRTUAL_INST_FAULT);
+ exceptions |= (1U << CAUSE_STORE_GUEST_PAGE_FAULT);
+ }
+
+ csr_write(CSR_MIDELEG, interrupts);
+ csr_write(CSR_MEDELEG, exceptions);
+
+ return 0;
+}
+
+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("%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("%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 =
+ sbi_scratch_offset_ptr(scratch, hart_features_offset);
+
+ return hfeatures->pmp_count;
+}
+
+unsigned long sbi_hart_pmp_granularity(struct sbi_scratch *scratch)
+{
+ struct hart_features *hfeatures =
+ sbi_scratch_offset_ptr(scratch, hart_features_offset);
+
+ return hfeatures->pmp_gran;
+}
+
+unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch)
+{
+ struct hart_features *hfeatures =
+ sbi_scratch_offset_ptr(scratch, hart_features_offset);
+
+ return hfeatures->pmp_addr_bits;
+}
+
+int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
+{
+ struct sbi_domain_memregion *reg;
+ struct sbi_domain *dom = sbi_domain_thishart_ptr();
+ unsigned int pmp_idx = 0, pmp_flags, pmp_bits, pmp_gran_log2;
+ unsigned int pmp_count = sbi_hart_pmp_count(scratch);
+ unsigned long pmp_addr = 0, pmp_addr_max = 0;
+
+ if (!pmp_count)
+ return 0;
+
+ 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);
+
+ 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);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Check whether a particular hart feature is available
+ *
+ * @param scratch pointer to the HART scratch space
+ * @param feature the feature to check
+ * @returns true (feature available) or false (feature not available)
+ */
+bool sbi_hart_has_feature(struct sbi_scratch *scratch, unsigned long feature)
+{
+ struct hart_features *hfeatures =
+ sbi_scratch_offset_ptr(scratch, hart_features_offset);
+
+ if (hfeatures->features & feature)
+ return true;
+ else
+ return false;
+}
+
+static unsigned long hart_get_features(struct sbi_scratch *scratch)
+{
+ struct hart_features *hfeatures =
+ sbi_scratch_offset_ptr(scratch, hart_features_offset);
+
+ return hfeatures->features;
+}
+
+static inline char *sbi_hart_feature_id2string(unsigned long feature)
+{
+ char *fstr = NULL;
+
+ if (!feature)
+ return NULL;
+
+ switch (feature) {
+ case SBI_HART_HAS_SCOUNTEREN:
+ fstr = "scounteren";
+ break;
+ case SBI_HART_HAS_MCOUNTEREN:
+ fstr = "mcounteren";
+ break;
+ case SBI_HART_HAS_TIME:
+ fstr = "time";
+ break;
+ default:
+ break;
+ }
+
+ return fstr;
+}
+
+/**
+ * Get the hart features in string format
+ *
+ * @param scratch pointer to the HART scratch space
+ * @param features_str pointer to a char array where the features string will be
+ * updated
+ * @param nfstr length of the features_str. The feature string will be truncated
+ * if nfstr is not long enough.
+ */
+void sbi_hart_get_features_str(struct sbi_scratch *scratch,
+ char *features_str, int nfstr)
+{
+ unsigned long features, feat = 1UL;
+ char *temp;
+ int offset = 0;
+
+ if (!features_str || nfstr <= 0)
+ return;
+ sbi_memset(features_str, 0, nfstr);
+
+ features = hart_get_features(scratch);
+ if (!features)
+ goto done;
+
+ do {
+ if (features & feat) {
+ temp = sbi_hart_feature_id2string(feat);
+ if (temp) {
+ sbi_snprintf(features_str + offset, nfstr,
+ "%s,", temp);
+ offset = offset + sbi_strlen(temp) + 1;
+ }
+ }
+ feat = feat << 1;
+ } while (feat <= SBI_HART_HAS_LAST_FEATURE);
+
+done:
+ if (offset)
+ features_str[offset - 1] = '\0';
+ else
+ 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};
+ struct hart_features *hfeatures;
+ unsigned long val;
+
+ /* Reset hart features */
+ hfeatures = sbi_scratch_offset_ptr(scratch, hart_features_offset);
+ hfeatures->features = 0;
+ hfeatures->pmp_count = 0;
+ hfeatures->mhpm_count = 0;
+
+#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; \
+ }
+#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)
+
+ /**
+ * 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;
+ val = csr_read_allowed(CSR_SCOUNTEREN, (unsigned long)&trap);
+ if (!trap.cause) {
+ csr_write_allowed(CSR_SCOUNTEREN, (unsigned long)&trap, val);
+ if (!trap.cause)
+ hfeatures->features |= SBI_HART_HAS_SCOUNTEREN;
+ }
+
+ /* Detect if hart supports MCOUNTEREN feature */
+ trap.cause = 0;
+ val = csr_read_allowed(CSR_MCOUNTEREN, (unsigned long)&trap);
+ if (!trap.cause) {
+ csr_write_allowed(CSR_MCOUNTEREN, (unsigned long)&trap, val);
+ if (!trap.cause)
+ hfeatures->features |= SBI_HART_HAS_MCOUNTEREN;
+ }
+
+ /* Detect if hart supports time CSR */
+ trap.cause = 0;
+ csr_read_allowed(CSR_TIME, (unsigned long)&trap);
+ if (!trap.cause)
+ hfeatures->features |= SBI_HART_HAS_TIME;
+}
+
+int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot)
+{
+ int rc;
+
+ if (cold_boot) {
+ if (misa_extension('H'))
+ sbi_hart_expected_trap = &__sbi_expected_trap_hext;
+
+ hart_features_offset = sbi_scratch_alloc_offset(
+ sizeof(struct hart_features),
+ "HART_FEATURES");
+ if (!hart_features_offset)
+ return SBI_ENOMEM;
+ }
+
+ hart_detect_features(scratch);
+
+ mstatus_init(scratch);
+
+ rc = fp_init(scratch);
+ if (rc)
+ return rc;
+
+ rc = delegate_traps(scratch);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+void __attribute__((noreturn)) sbi_hart_hang(void)
+{
+ while (1)
+ wfi();
+ __builtin_unreachable();
+}
+
+void __attribute__((noreturn))
+sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
+ unsigned long next_addr, unsigned long next_mode,
+ bool next_virt)
+{
+#if __riscv_xlen == 32
+ unsigned long val, valH;
+#else
+ unsigned long val;
+#endif
+
+ switch (next_mode) {
+ case PRV_M:
+ break;
+ case PRV_S:
+ if (!misa_extension('S'))
+ sbi_hart_hang();
+ break;
+ case PRV_U:
+ if (!misa_extension('U'))
+ sbi_hart_hang();
+ break;
+ default:
+ sbi_hart_hang();
+ }
+
+ val = csr_read(CSR_MSTATUS);
+ val = INSERT_FIELD(val, MSTATUS_MPP, next_mode);
+ val = INSERT_FIELD(val, MSTATUS_MPIE, 0);
+#if __riscv_xlen == 32
+ if (misa_extension('H')) {
+ valH = csr_read(CSR_MSTATUSH);
+ if (next_virt)
+ valH = INSERT_FIELD(valH, MSTATUSH_MPV, 1);
+ else
+ valH = INSERT_FIELD(valH, MSTATUSH_MPV, 0);
+ csr_write(CSR_MSTATUSH, valH);
+ }
+#else
+ if (misa_extension('H')) {
+ if (next_virt)
+ val = INSERT_FIELD(val, MSTATUS_MPV, 1);
+ else
+ val = INSERT_FIELD(val, MSTATUS_MPV, 0);
+ }
+#endif
+ csr_write(CSR_MSTATUS, val);
+ csr_write(CSR_MEPC, next_addr);
+
+ if (next_mode == PRV_S) {
+ csr_write(CSR_STVEC, next_addr);
+ csr_write(CSR_SSCRATCH, 0);
+ csr_write(CSR_SIE, 0);
+ csr_write(CSR_SATP, 0);
+ } else if (next_mode == PRV_U) {
+ 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;
+ register unsigned long a1 asm("a1") = arg1;
+ __asm__ __volatile__("mret" : : "r"(a0), "r"(a1));
+ __builtin_unreachable();
+}
diff --git a/roms/opensbi/lib/sbi/sbi_hfence.S b/roms/opensbi/lib/sbi/sbi_hfence.S
new file mode 100644
index 000000000..d05becbf2
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_hfence.S
@@ -0,0 +1,135 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ * Atish Patra <anup.patel@wdc.com>
+ */
+
+ /*
+ * HFENCE.GVMA rs1, rs2
+ * HFENCE.GVMA zero, rs2
+ * HFENCE.GVMA rs1
+ * HFENCE.GVMA
+ *
+ * rs1!=zero and rs2!=zero ==> HFENCE.GVMA rs1, rs2
+ * rs1==zero and rs2!=zero ==> HFENCE.GVMA zero, rs2
+ * rs1!=zero and rs2==zero ==> HFENCE.GVMA rs1
+ * rs1==zero and rs2==zero ==> HFENCE.GVMA
+ *
+ * Instruction encoding of HFENCE.GVMA is:
+ * 0110001 rs2(5) rs1(5) 000 00000 1110011
+ */
+
+ .align 3
+ .global __sbi_hfence_gvma_vmid_gpa
+__sbi_hfence_gvma_vmid_gpa:
+ /*
+ * rs1 = a0 (GPA)
+ * rs2 = a1 (VMID)
+ * HFENCE.GVMA a0, a1
+ * 0110001 01011 01010 000 00000 1110011
+ */
+ .word 0x62b50073
+ ret
+
+ .align 3
+ .global __sbi_hfence_gvma_vmid
+__sbi_hfence_gvma_vmid:
+ /*
+ * rs1 = zero
+ * rs2 = a0 (VMID)
+ * HFENCE.GVMA zero, a0
+ * 0110001 01010 00000 000 00000 1110011
+ */
+ .word 0x62a00073
+ ret
+
+ .align 3
+ .global __sbi_hfence_gvma_gpa
+__sbi_hfence_gvma_gpa:
+ /*
+ * rs1 = a0 (GPA)
+ * rs2 = zero
+ * HFENCE.GVMA a0
+ * 0110001 00000 01010 000 00000 1110011
+ */
+ .word 0x62050073
+ ret
+
+ .align 3
+ .global __sbi_hfence_gvma_all
+__sbi_hfence_gvma_all:
+ /*
+ * rs1 = zero
+ * rs2 = zero
+ * HFENCE.GVMA
+ * 0110001 00000 00000 000 00000 1110011
+ */
+ .word 0x62000073
+ ret
+
+ /*
+ * HFENCE.VVMA rs1, rs2
+ * HFENCE.VVMA zero, rs2
+ * HFENCE.VVMA rs1
+ * HFENCE.VVMA
+ *
+ * rs1!=zero and rs2!=zero ==> HFENCE.VVMA rs1, rs2
+ * rs1==zero and rs2!=zero ==> HFENCE.VVMA zero, rs2
+ * rs1!=zero and rs2==zero ==> HFENCE.VVMA rs1
+ * rs1==zero and rs2==zero ==> HFENCE.vVMA
+ *
+ * Instruction encoding of HFENCE.VVMA is:
+ * 0010001 rs2(5) rs1(5) 000 00000 1110011
+ */
+
+ .align 3
+ .global __sbi_hfence_vvma_asid_va
+__sbi_hfence_vvma_asid_va:
+ /*
+ * rs1 = a0 (VA)
+ * rs2 = a1 (ASID)
+ * HFENCE.VVMA a0, a1
+ * 0010001 01011 01010 000 00000 1110011
+ */
+ .word 0x22b50073
+ ret
+
+ .align 3
+ .global __sbi_hfence_vvma_asid
+__sbi_hfence_vvma_asid:
+ /*
+ * rs1 = zero
+ * rs2 = a0 (ASID)
+ * HFENCE.VVMA zero, a0
+ * 0010001 01010 00000 000 00000 1110011
+ */
+ .word 0x22a00073
+ ret
+
+ .align 3
+ .global __sbi_hfence_vvma_va
+__sbi_hfence_vvma_va:
+ /*
+ * rs1 = a0 (VA)
+ * rs2 = zero
+ * HFENCE.VVMA zero, a0
+ * 0010001 00000 01010 000 00000 1110011
+ */
+ .word 0x22050073
+ ret
+
+ .align 3
+ .global __sbi_hfence_vvma_all
+__sbi_hfence_vvma_all:
+ /*
+ * rs1 = zero
+ * rs2 = zero
+ * HFENCE.VVMA
+ * 0010001 00000 00000 000 00000 1110011
+ */
+ .word 0x22000073
+ ret
diff --git a/roms/opensbi/lib/sbi/sbi_hsm.c b/roms/opensbi/lib/sbi/sbi_hsm.c
new file mode 100644
index 000000000..e1b2b2c3d
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_hsm.c
@@ -0,0 +1,291 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Atish Patra <atish.patra@wdc.com>
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_barrier.h>
+#include <sbi/riscv_encoding.h>
+#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>
+#include <sbi/sbi_hartmask.h>
+#include <sbi/sbi_hsm.h>
+#include <sbi/sbi_init.h>
+#include <sbi/sbi_ipi.h>
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_system.h>
+#include <sbi/sbi_timer.h>
+#include <sbi/sbi_console.h>
+
+static unsigned long hart_data_offset;
+
+/** Per hart specific data to manage state transition **/
+struct sbi_hsm_data {
+ atomic_t state;
+};
+
+int sbi_hsm_hart_state_to_status(int state)
+{
+ int ret;
+
+ switch (state) {
+ case SBI_HART_STOPPED:
+ ret = SBI_HSM_HART_STATUS_STOPPED;
+ break;
+ case SBI_HART_STOPPING:
+ ret = SBI_HSM_HART_STATUS_STOP_PENDING;
+ break;
+ case SBI_HART_STARTING:
+ ret = SBI_HSM_HART_STATUS_START_PENDING;
+ break;
+ case SBI_HART_STARTED:
+ ret = SBI_HSM_HART_STATUS_STARTED;
+ break;
+ default:
+ ret = SBI_EINVAL;
+ }
+
+ return ret;
+}
+
+static inline int __sbi_hsm_hart_get_state(u32 hartid)
+{
+ struct sbi_hsm_data *hdata;
+ struct sbi_scratch *scratch;
+
+ scratch = sbi_hartid_to_scratch(hartid);
+ if (!scratch)
+ return SBI_HART_UNKNOWN;
+
+ hdata = sbi_scratch_offset_ptr(scratch, hart_data_offset);
+ return atomic_read(&hdata->state);
+}
+
+int sbi_hsm_hart_get_state(const struct sbi_domain *dom, u32 hartid)
+{
+ 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;
+}
+
+/**
+ * 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(const struct sbi_domain *dom,
+ ulong hbase, ulong *out_hmask)
+{
+ ulong i, hmask, dmask;
+ ulong hend = sbi_scratch_last_hartid() + 1;
+
+ *out_hmask = 0;
+ if (hend <= hbase)
+ return SBI_EINVAL;
+ if (BITS_PER_LONG < (hend - hbase))
+ hend = hbase + BITS_PER_LONG;
+
+ 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;
+}
+
+void sbi_hsm_prepare_next_jump(struct sbi_scratch *scratch, u32 hartid)
+{
+ u32 oldstate;
+ struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
+ hart_data_offset);
+
+ oldstate = atomic_cmpxchg(&hdata->state, SBI_HART_STARTING,
+ SBI_HART_STARTED);
+ if (oldstate != SBI_HART_STARTING)
+ sbi_hart_hang();
+}
+
+static void sbi_hsm_hart_wait(struct sbi_scratch *scratch, u32 hartid)
+{
+ unsigned long saved_mie;
+ const struct sbi_platform *plat = sbi_platform_ptr(scratch);
+ struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
+ hart_data_offset);
+ /* Save MIE CSR */
+ saved_mie = csr_read(CSR_MIE);
+
+ /* Set MSIE bit to receive IPI */
+ csr_set(CSR_MIE, MIP_MSIP);
+
+ /* Wait for hart_add call*/
+ while (atomic_read(&hdata->state) != SBI_HART_STARTING) {
+ wfi();
+ };
+
+ /* Restore MIE CSR */
+ csr_write(CSR_MIE, saved_mie);
+
+ /* Clear current HART IPI */
+ sbi_platform_ipi_clear(plat, hartid);
+}
+
+int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
+{
+ u32 i;
+ struct sbi_scratch *rscratch;
+ struct sbi_hsm_data *hdata;
+
+ if (cold_boot) {
+ hart_data_offset = sbi_scratch_alloc_offset(sizeof(*hdata),
+ "HART_DATA");
+ if (!hart_data_offset)
+ return SBI_ENOMEM;
+
+ /* Initialize hart state data for every hart */
+ for (i = 0; i <= sbi_scratch_last_hartid(); i++) {
+ rscratch = sbi_hartid_to_scratch(i);
+ if (!rscratch)
+ continue;
+
+ hdata = sbi_scratch_offset_ptr(rscratch,
+ hart_data_offset);
+ ATOMIC_INIT(&hdata->state,
+ (i == hartid) ? SBI_HART_STARTING : SBI_HART_STOPPED);
+ }
+ } else {
+ sbi_hsm_hart_wait(scratch, hartid);
+ }
+
+ return 0;
+}
+
+void __noreturn sbi_hsm_exit(struct sbi_scratch *scratch)
+{
+ u32 hstate;
+ const struct sbi_platform *plat = sbi_platform_ptr(scratch);
+ struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
+ hart_data_offset);
+ void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr;
+
+ hstate = atomic_cmpxchg(&hdata->state, SBI_HART_STOPPING,
+ SBI_HART_STOPPED);
+ if (hstate != SBI_HART_STOPPING)
+ goto fail_exit;
+
+ if (sbi_platform_has_hart_hotplug(plat)) {
+ sbi_platform_hart_stop(plat);
+ /* It should never reach here */
+ goto fail_exit;
+ }
+
+ /**
+ * As platform is lacking support for hotplug, directly jump to warmboot
+ * and wait for interrupts in warmboot. We do it preemptively in order
+ * preserve the hart states and reuse the code path for hotplug.
+ */
+ jump_warmboot();
+
+fail_exit:
+ /* It should never reach here */
+ sbi_printf("ERR: Failed stop hart [%u]\n", current_hartid());
+ sbi_hart_hang();
+}
+
+int sbi_hsm_hart_start(struct sbi_scratch *scratch,
+ const struct sbi_domain *dom,
+ u32 hartid, ulong saddr, ulong smode, ulong priv)
+{
+ 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;
+ hdata = sbi_scratch_offset_ptr(rscratch, hart_data_offset);
+ hstate = atomic_cmpxchg(&hdata->state, SBI_HART_STOPPED,
+ SBI_HART_STARTING);
+ if (hstate == SBI_HART_STARTED)
+ return SBI_EALREADY;
+
+ /**
+ * if a hart is already transition to start or stop, another start call
+ * is considered as invalid request.
+ */
+ if (hstate != SBI_HART_STOPPED)
+ return SBI_EINVAL;
+
+ init_count = sbi_init_count(hartid);
+ rscratch->next_arg1 = priv;
+ rscratch->next_addr = saddr;
+ rscratch->next_mode = smode;
+
+ if (sbi_platform_has_hart_hotplug(plat) ||
+ (sbi_platform_has_hart_secondary_boot(plat) && !init_count)) {
+ return sbi_platform_hart_start(plat, hartid,
+ scratch->warmboot_addr);
+ } else {
+ sbi_platform_ipi_send(plat, hartid);
+ }
+
+ return 0;
+}
+
+int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow)
+{
+ int oldstate;
+ u32 hartid = current_hartid();
+ struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
+ hart_data_offset);
+
+ if (!sbi_hsm_hart_started(sbi_domain_thishart_ptr(), hartid))
+ return SBI_EINVAL;
+
+ oldstate = atomic_cmpxchg(&hdata->state, SBI_HART_STARTED,
+ SBI_HART_STOPPING);
+ if (oldstate != SBI_HART_STARTED) {
+ sbi_printf("%s: ERR: The hart is in invalid state [%u]\n",
+ __func__, oldstate);
+ return SBI_EDENIED;
+ }
+
+ if (exitnow)
+ sbi_exit(scratch);
+
+ return 0;
+}
diff --git a/roms/opensbi/lib/sbi/sbi_illegal_insn.c b/roms/opensbi/lib/sbi/sbi_illegal_insn.c
new file mode 100644
index 000000000..9af3d24d7
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_illegal_insn.c
@@ -0,0 +1,143 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_bitops.h>
+#include <sbi/sbi_emulate_csr.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_illegal_insn.h>
+#include <sbi/sbi_trap.h>
+#include <sbi/sbi_unpriv.h>
+
+typedef int (*illegal_insn_func)(ulong insn, struct sbi_trap_regs *regs);
+
+static int truly_illegal_insn(ulong insn, struct sbi_trap_regs *regs)
+{
+ struct sbi_trap_info trap;
+
+ trap.epc = regs->mepc;
+ trap.cause = CAUSE_ILLEGAL_INSTRUCTION;
+ trap.tval = insn;
+ trap.tval2 = 0;
+ trap.tinst = 0;
+
+ return sbi_trap_redirect(regs, &trap);
+}
+
+static int system_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
+{
+ int do_write, rs1_num = (insn >> 15) & 0x1f;
+ ulong rs1_val = GET_RS1(insn, regs);
+ int csr_num = (u32)insn >> 20;
+ ulong csr_val, new_csr_val;
+
+ /* TODO: Ensure that we got CSR read/write instruction */
+
+ if (sbi_emulate_csr_read(csr_num, regs, &csr_val))
+ return truly_illegal_insn(insn, regs);
+
+ do_write = rs1_num;
+ switch (GET_RM(insn)) {
+ case 1:
+ new_csr_val = rs1_val;
+ do_write = 1;
+ break;
+ case 2:
+ new_csr_val = csr_val | rs1_val;
+ break;
+ case 3:
+ new_csr_val = csr_val & ~rs1_val;
+ break;
+ case 5:
+ new_csr_val = rs1_num;
+ do_write = 1;
+ break;
+ case 6:
+ new_csr_val = csr_val | rs1_num;
+ break;
+ case 7:
+ new_csr_val = csr_val & ~rs1_num;
+ break;
+ default:
+ return truly_illegal_insn(insn, regs);
+ };
+
+ if (do_write && sbi_emulate_csr_write(csr_num, regs, new_csr_val))
+ return truly_illegal_insn(insn, regs);
+
+ SET_RD(insn, regs, csr_val);
+
+ regs->mepc += 4;
+
+ return 0;
+}
+
+static illegal_insn_func illegal_insn_table[32] = {
+ truly_illegal_insn, /* 0 */
+ truly_illegal_insn, /* 1 */
+ truly_illegal_insn, /* 2 */
+ truly_illegal_insn, /* 3 */
+ truly_illegal_insn, /* 4 */
+ truly_illegal_insn, /* 5 */
+ truly_illegal_insn, /* 6 */
+ truly_illegal_insn, /* 7 */
+ truly_illegal_insn, /* 8 */
+ truly_illegal_insn, /* 9 */
+ truly_illegal_insn, /* 10 */
+ truly_illegal_insn, /* 11 */
+ truly_illegal_insn, /* 12 */
+ truly_illegal_insn, /* 13 */
+ truly_illegal_insn, /* 14 */
+ truly_illegal_insn, /* 15 */
+ truly_illegal_insn, /* 16 */
+ truly_illegal_insn, /* 17 */
+ truly_illegal_insn, /* 18 */
+ truly_illegal_insn, /* 19 */
+ truly_illegal_insn, /* 20 */
+ truly_illegal_insn, /* 21 */
+ truly_illegal_insn, /* 22 */
+ truly_illegal_insn, /* 23 */
+ truly_illegal_insn, /* 24 */
+ truly_illegal_insn, /* 25 */
+ truly_illegal_insn, /* 26 */
+ truly_illegal_insn, /* 27 */
+ system_opcode_insn, /* 28 */
+ truly_illegal_insn, /* 29 */
+ truly_illegal_insn, /* 30 */
+ truly_illegal_insn /* 31 */
+};
+
+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)) {
+ 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);
+ }
+
+ return illegal_insn_table[(insn & 0x7c) >> 2](insn, regs);
+}
diff --git a/roms/opensbi/lib/sbi/sbi_init.c b/roms/opensbi/lib/sbi/sbi_init.c
new file mode 100644
index 000000000..0e824588e
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_init.c
@@ -0,0 +1,475 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/riscv_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>
+#include <sbi/sbi_hsm.h>
+#include <sbi/sbi_ipi.h>
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_system.h>
+#include <sbi/sbi_string.h>
+#include <sbi/sbi_timer.h>
+#include <sbi/sbi_tlb.h>
+#include <sbi/sbi_version.h>
+
+#define BANNER \
+ " ____ _____ ____ _____\n" \
+ " / __ \\ / ____| _ \\_ _|\n" \
+ " | | | |_ __ ___ _ __ | (___ | |_) || |\n" \
+ " | | | | '_ \\ / _ \\ '_ \\ \\___ \\| _ < | |\n" \
+ " | |__| | |_) | __/ | | |____) | |_) || |_\n" \
+ " \\____/| .__/ \\___|_| |_|_____/|____/_____|\n" \
+ " | |\n" \
+ " |_|\n\n"
+
+static void sbi_boot_print_banner(struct sbi_scratch *scratch)
+{
+ if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS)
+ return;
+
+#ifdef OPENSBI_VERSION_GIT
+ sbi_printf("\nOpenSBI %s\n", OPENSBI_VERSION_GIT);
+#else
+ sbi_printf("\nOpenSBI v%d.%d\n", OPENSBI_VERSION_MAJOR,
+ OPENSBI_VERSION_MINOR);
+#endif
+
+ sbi_printf(BANNER);
+}
+
+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();
+ if (xlen < 1) {
+ sbi_printf("Error %d getting MISA XLEN\n", xlen);
+ sbi_hart_hang();
+ }
+
+ /* Boot HART details */
+ 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_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));
+ 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 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;
+ const struct sbi_platform *plat = sbi_platform_ptr(scratch);
+
+ /* Save MIE CSR */
+ saved_mie = csr_read(CSR_MIE);
+
+ /* Set MSIE bit to receive IPI */
+ csr_set(CSR_MIE, MIP_MSIP);
+
+ /* Acquire coldboot lock */
+ spin_lock(&coldboot_lock);
+
+ /* 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 (!__smp_load_acquire(&coldboot_done)) {
+ do {
+ wfi();
+ cmip = csr_read(CSR_MIP);
+ } while (!(cmip & MIP_MSIP));
+ };
+
+ /* Acquire coldboot lock */
+ spin_lock(&coldboot_lock);
+
+ /* Unmark current HART as waiting */
+ sbi_hartmask_clear_hart(hartid, &coldboot_wait_hmask);
+
+ /* Release coldboot lock */
+ spin_unlock(&coldboot_lock);
+
+ /* Restore MIE CSR */
+ csr_write(CSR_MIE, saved_mie);
+
+ /* Clear current HART IPI */
+ sbi_platform_ipi_clear(plat, hartid);
+}
+
+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);
+
+ /* Send an IPI to all HARTs waiting for coldboot */
+ for (int i = 0; i <= sbi_scratch_last_hartid(); i++) {
+ if ((i != hartid) &&
+ sbi_hartmask_test_hart(i, &coldboot_wait_hmask))
+ sbi_platform_ipi_send(plat, i);
+ }
+
+ /* Release coldboot lock */
+ spin_unlock(&coldboot_lock);
+}
+
+static unsigned long init_count_offset;
+
+static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
+{
+ int rc;
+ unsigned long *init_count;
+ const struct sbi_platform *plat = sbi_platform_ptr(scratch);
+
+ /* Note: This has to be first thing in coldboot init sequence */
+ rc = sbi_scratch_init(scratch);
+ 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)
+ sbi_hart_hang();
+
+ rc = sbi_hsm_init(scratch, hartid, TRUE);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_platform_early_init(plat, TRUE);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_hart_init(scratch, TRUE);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_console_init(scratch);
+ if (rc)
+ sbi_hart_hang();
+
+ sbi_boot_print_banner(scratch);
+
+ rc = sbi_platform_irqchip_init(plat, TRUE);
+ 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) {
+ sbi_printf("%s: ipi init failed (error %d)\n", __func__, rc);
+ sbi_hart_hang();
+ }
+
+ rc = sbi_tlb_init(scratch, TRUE);
+ if (rc) {
+ sbi_printf("%s: tlb init failed (error %d)\n", __func__, rc);
+ sbi_hart_hang();
+ }
+
+ rc = sbi_timer_init(scratch, TRUE);
+ if (rc) {
+ sbi_printf("%s: timer init failed (error %d)\n", __func__, rc);
+ sbi_hart_hang();
+ }
+
+ rc = sbi_ecall_init();
+ 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) {
+ sbi_printf("%s: platform final init failed (error %d)\n",
+ __func__, rc);
+ sbi_hart_hang();
+ }
+
+ sbi_boot_print_hart(scratch, hartid);
+
+ wake_coldboot_harts(scratch, hartid);
+
+ init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
+ (*init_count)++;
+
+ sbi_hsm_prepare_next_jump(scratch, hartid);
+ sbi_hart_switch_mode(hartid, scratch->next_arg1, scratch->next_addr,
+ scratch->next_mode, FALSE);
+}
+
+static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
+{
+ int rc;
+ unsigned long *init_count;
+ const struct sbi_platform *plat = sbi_platform_ptr(scratch);
+
+ wait_for_coldboot(scratch, hartid);
+
+ if (!init_count_offset)
+ sbi_hart_hang();
+
+ rc = sbi_hsm_init(scratch, hartid, FALSE);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_platform_early_init(plat, FALSE);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_hart_init(scratch, FALSE);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_platform_irqchip_init(plat, FALSE);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_ipi_init(scratch, FALSE);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_tlb_init(scratch, FALSE);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_timer_init(scratch, FALSE);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_hart_pmp_configure(scratch);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_platform_final_init(plat, FALSE);
+ if (rc)
+ sbi_hart_hang();
+
+ init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
+ (*init_count)++;
+
+ sbi_hsm_prepare_next_jump(scratch, hartid);
+ sbi_hart_switch_mode(hartid, scratch->next_arg1,
+ scratch->next_addr,
+ scratch->next_mode, FALSE);
+}
+
+static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);
+
+/**
+ * Initialize OpenSBI library for current HART and jump to next
+ * booting stage.
+ *
+ * The function expects following:
+ * 1. The 'mscratch' CSR is pointing to sbi_scratch of current HART
+ * 2. Stack pointer (SP) is setup for current HART
+ * 3. Interrupts are disabled in MSTATUS CSR
+ * 4. All interrupts are disabled in MIE CSR
+ *
+ * @param scratch pointer to sbi_scratch of current HART
+ */
+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);
+
+ if ((SBI_HARTMASK_MAX_BITS <= hartid) ||
+ sbi_platform_hart_invalid(plat, hartid))
+ sbi_hart_hang();
+
+ 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)
+ init_coldboot(scratch, hartid);
+ else
+ init_warmboot(scratch, hartid);
+}
+
+unsigned long sbi_init_count(u32 hartid)
+{
+ struct sbi_scratch *scratch;
+ unsigned long *init_count;
+
+ if (!init_count_offset)
+ return 0;
+
+ scratch = sbi_hartid_to_scratch(hartid);
+ if (!scratch)
+ return 0;
+
+ init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
+
+ return *init_count;
+}
+
+/**
+ * Exit OpenSBI library for current HART and stop HART
+ *
+ * The function expects following:
+ * 1. The 'mscratch' CSR is pointing to sbi_scratch of current HART
+ * 2. Stack pointer (SP) is setup for current HART
+ *
+ * @param scratch pointer to sbi_scratch of current HART
+ */
+void __noreturn sbi_exit(struct sbi_scratch *scratch)
+{
+ u32 hartid = current_hartid();
+ const struct sbi_platform *plat = sbi_platform_ptr(scratch);
+
+ if (sbi_platform_hart_invalid(plat, hartid))
+ sbi_hart_hang();
+
+ sbi_platform_early_exit(plat);
+
+ sbi_timer_exit(scratch);
+
+ sbi_ipi_exit(scratch);
+
+ sbi_platform_irqchip_exit(plat);
+
+ sbi_platform_final_exit(plat);
+
+ sbi_hsm_exit(scratch);
+}
diff --git a/roms/opensbi/lib/sbi/sbi_ipi.c b/roms/opensbi/lib/sbi/sbi_ipi.c
new file mode 100644
index 000000000..43478328b
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_ipi.c
@@ -0,0 +1,254 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ * Nick Kossifidis <mick@ics.forth.gr>
+ */
+
+#include <sbi/riscv_asm.h>
+#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>
+#include <sbi/sbi_init.h>
+#include <sbi/sbi_ipi.h>
+#include <sbi/sbi_platform.h>
+
+struct sbi_ipi_data {
+ unsigned long ipi_type;
+};
+
+static unsigned long ipi_data_off;
+
+static const struct sbi_ipi_event_ops *ipi_ops_array[SBI_IPI_EVENT_MAX];
+
+static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid,
+ u32 event, void *data)
+{
+ int ret;
+ struct sbi_scratch *remote_scratch = NULL;
+ const struct sbi_platform *plat = sbi_platform_ptr(scratch);
+ struct sbi_ipi_data *ipi_data;
+ const struct sbi_ipi_event_ops *ipi_ops;
+
+ if ((SBI_IPI_EVENT_MAX <= event) ||
+ !ipi_ops_array[event])
+ return SBI_EINVAL;
+ ipi_ops = ipi_ops_array[event];
+
+ remote_scratch = sbi_hartid_to_scratch(remote_hartid);
+ if (!remote_scratch)
+ return SBI_EINVAL;
+
+ ipi_data = sbi_scratch_offset_ptr(remote_scratch, ipi_data_off);
+
+ if (ipi_ops->update) {
+ ret = ipi_ops->update(scratch, remote_scratch,
+ remote_hartid, data);
+ if (ret < 0)
+ return ret;
+ }
+
+ /*
+ * Set IPI type on remote hart's scratch area and
+ * trigger the interrupt
+ */
+ atomic_raw_set_bit(event, &ipi_data->ipi_type);
+ smp_wmb();
+ sbi_platform_ipi_send(plat, remote_hartid);
+
+ if (ipi_ops->sync)
+ ipi_ops->sync(scratch);
+
+ return 0;
+}
+
+/**
+ * As this this function only handlers scalar values of hart mask, it must be
+ * set to all online harts if the intention is to send IPIs to all the harts.
+ * If hmask is zero, no IPIs will be sent.
+ */
+int sbi_ipi_send_many(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(dom, hbase, &m);
+ if (rc)
+ return rc;
+ m &= hmask;
+
+ /* Send IPIs */
+ for (i = hbase; m; i++, m >>= 1) {
+ if (m & 1UL)
+ sbi_ipi_send(scratch, i, event, data);
+ }
+ } else {
+ hbase = 0;
+ while (!sbi_hsm_hart_started_mask(dom, hbase, &m)) {
+ /* Send IPIs */
+ for (i = hbase; m; i++, m >>= 1) {
+ if (m & 1UL)
+ sbi_ipi_send(scratch, i, event, data);
+ }
+ hbase += BITS_PER_LONG;
+ }
+ }
+
+ return 0;
+}
+
+int sbi_ipi_event_create(const struct sbi_ipi_event_ops *ops)
+{
+ int i, ret = SBI_ENOSPC;
+
+ if (!ops || !ops->process)
+ return SBI_EINVAL;
+
+ for (i = 0; i < SBI_IPI_EVENT_MAX; i++) {
+ if (!ipi_ops_array[i]) {
+ ret = i;
+ ipi_ops_array[i] = ops;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+void sbi_ipi_event_destroy(u32 event)
+{
+ if (SBI_IPI_EVENT_MAX <= event)
+ return;
+
+ ipi_ops_array[event] = NULL;
+}
+
+static void sbi_ipi_process_smode(struct sbi_scratch *scratch)
+{
+ csr_set(CSR_MIP, MIP_SSIP);
+}
+
+static struct sbi_ipi_event_ops ipi_smode_ops = {
+ .name = "IPI_SMODE",
+ .process = sbi_ipi_process_smode,
+};
+
+static u32 ipi_smode_event = SBI_IPI_EVENT_MAX;
+
+int sbi_ipi_send_smode(ulong hmask, ulong hbase)
+{
+ return sbi_ipi_send_many(hmask, hbase, ipi_smode_event, NULL);
+}
+
+void sbi_ipi_clear_smode(void)
+{
+ csr_clear(CSR_MIP, MIP_SSIP);
+}
+
+static void sbi_ipi_process_halt(struct sbi_scratch *scratch)
+{
+ sbi_hsm_hart_stop(scratch, TRUE);
+}
+
+static struct sbi_ipi_event_ops ipi_halt_ops = {
+ .name = "IPI_HALT",
+ .process = sbi_ipi_process_halt,
+};
+
+static u32 ipi_halt_event = SBI_IPI_EVENT_MAX;
+
+int sbi_ipi_send_halt(ulong hmask, ulong hbase)
+{
+ return sbi_ipi_send_many(hmask, hbase, ipi_halt_event, NULL);
+}
+
+void sbi_ipi_process(void)
+{
+ unsigned long ipi_type;
+ unsigned int ipi_event;
+ const struct sbi_ipi_event_ops *ipi_ops;
+ struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
+ const struct sbi_platform *plat = sbi_platform_ptr(scratch);
+ struct sbi_ipi_data *ipi_data =
+ sbi_scratch_offset_ptr(scratch, ipi_data_off);
+
+ u32 hartid = current_hartid();
+ sbi_platform_ipi_clear(plat, hartid);
+
+ ipi_type = atomic_raw_xchg_ulong(&ipi_data->ipi_type, 0);
+ ipi_event = 0;
+ while (ipi_type) {
+ if (!(ipi_type & 1UL))
+ goto skip;
+
+ ipi_ops = ipi_ops_array[ipi_event];
+ if (ipi_ops && ipi_ops->process)
+ ipi_ops->process(scratch);
+
+skip:
+ ipi_type = ipi_type >> 1;
+ ipi_event++;
+ };
+}
+
+int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot)
+{
+ int ret;
+ struct sbi_ipi_data *ipi_data;
+
+ if (cold_boot) {
+ ipi_data_off = sbi_scratch_alloc_offset(sizeof(*ipi_data),
+ "IPI_DATA");
+ if (!ipi_data_off)
+ return SBI_ENOMEM;
+ ret = sbi_ipi_event_create(&ipi_smode_ops);
+ if (ret < 0)
+ return ret;
+ ipi_smode_event = ret;
+ ret = sbi_ipi_event_create(&ipi_halt_ops);
+ if (ret < 0)
+ return ret;
+ ipi_halt_event = ret;
+ } else {
+ if (!ipi_data_off)
+ return SBI_ENOMEM;
+ if (SBI_IPI_EVENT_MAX <= ipi_smode_event ||
+ SBI_IPI_EVENT_MAX <= ipi_halt_event)
+ return SBI_ENOSPC;
+ }
+
+ ipi_data = sbi_scratch_offset_ptr(scratch, ipi_data_off);
+ ipi_data->ipi_type = 0x00;
+
+ /* Platform init */
+ ret = sbi_platform_ipi_init(sbi_platform_ptr(scratch), cold_boot);
+ if (ret)
+ return ret;
+
+ /* Enable software interrupts */
+ csr_set(CSR_MIE, MIP_MSIP);
+
+ return 0;
+}
+
+void sbi_ipi_exit(struct sbi_scratch *scratch)
+{
+ /* Disable software interrupts */
+ csr_clear(CSR_MIE, MIP_MSIP);
+
+ /* Process pending IPIs */
+ sbi_ipi_process();
+
+ /* Platform exit */
+ sbi_platform_ipi_exit(sbi_platform_ptr(scratch));
+}
diff --git a/roms/opensbi/lib/sbi/sbi_math.c b/roms/opensbi/lib/sbi/sbi_math.c
new file mode 100644
index 000000000..8ba0831d8
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_math.c
@@ -0,0 +1,23 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Common helper functions used across OpenSBI project.
+ *
+ * Authors:
+ * Atish Patra <atish.patra@wdc.com>
+ */
+
+unsigned long log2roundup(unsigned long x)
+{
+ unsigned long ret = 0;
+
+ while (ret < __riscv_xlen) {
+ if (x <= (1UL << ret))
+ break;
+ ret++;
+ }
+
+ return ret;
+}
diff --git a/roms/opensbi/lib/sbi/sbi_misaligned_ldst.c b/roms/opensbi/lib/sbi/sbi_misaligned_ldst.c
new file mode 100644
index 000000000..5057cb5ec
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_misaligned_ldst.c
@@ -0,0 +1,243 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/riscv_fp.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_misaligned_ldst.h>
+#include <sbi/sbi_trap.h>
+#include <sbi/sbi_unpriv.h>
+
+union reg_data {
+ u8 data_bytes[8];
+ ulong data_ulong;
+ u64 data_u64;
+};
+
+int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
+ struct sbi_trap_regs *regs)
+{
+ ulong insn, insn_len;
+ union reg_data val;
+ struct sbi_trap_info uptrap;
+ int i, fp = 0, shift = 0, len = 0;
+
+ if (tinst & 0x1) {
+ /*
+ * Bit[0] == 1 implies trapped instruction value is
+ * transformed instruction or custom instruction.
+ */
+ insn = tinst | INSN_16BIT_MASK;
+ insn_len = (tinst & 0x2) ? INSN_LEN(insn) : 2;
+ } else {
+ /*
+ * Bit[0] == 0 implies trapped instruction value is
+ * zero or special value.
+ */
+ insn = sbi_get_insn(regs->mepc, &uptrap);
+ if (uptrap.cause) {
+ uptrap.epc = regs->mepc;
+ return sbi_trap_redirect(regs, &uptrap);
+ }
+ insn_len = INSN_LEN(insn);
+ }
+
+ if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) {
+ len = 4;
+ shift = 8 * (sizeof(ulong) - len);
+#if __riscv_xlen == 64
+ } else if ((insn & INSN_MASK_LD) == INSN_MATCH_LD) {
+ len = 8;
+ shift = 8 * (sizeof(ulong) - len);
+ } else if ((insn & INSN_MASK_LWU) == INSN_MATCH_LWU) {
+ len = 4;
+#endif
+#ifdef __riscv_flen
+ } else if ((insn & INSN_MASK_FLD) == INSN_MATCH_FLD) {
+ fp = 1;
+ len = 8;
+ } else if ((insn & INSN_MASK_FLW) == INSN_MATCH_FLW) {
+ fp = 1;
+ len = 4;
+#endif
+ } else if ((insn & INSN_MASK_LH) == INSN_MATCH_LH) {
+ len = 2;
+ shift = 8 * (sizeof(ulong) - len);
+ } else if ((insn & INSN_MASK_LHU) == INSN_MATCH_LHU) {
+ len = 2;
+#if __riscv_xlen >= 64
+ } else if ((insn & INSN_MASK_C_LD) == INSN_MATCH_C_LD) {
+ len = 8;
+ shift = 8 * (sizeof(ulong) - len);
+ insn = RVC_RS2S(insn) << SH_RD;
+ } else if ((insn & INSN_MASK_C_LDSP) == INSN_MATCH_C_LDSP &&
+ ((insn >> SH_RD) & 0x1f)) {
+ len = 8;
+ shift = 8 * (sizeof(ulong) - len);
+#endif
+ } else if ((insn & INSN_MASK_C_LW) == INSN_MATCH_C_LW) {
+ len = 4;
+ shift = 8 * (sizeof(ulong) - len);
+ insn = RVC_RS2S(insn) << SH_RD;
+ } else if ((insn & INSN_MASK_C_LWSP) == INSN_MATCH_C_LWSP &&
+ ((insn >> SH_RD) & 0x1f)) {
+ len = 4;
+ shift = 8 * (sizeof(ulong) - len);
+#ifdef __riscv_flen
+ } else if ((insn & INSN_MASK_C_FLD) == INSN_MATCH_C_FLD) {
+ fp = 1;
+ len = 8;
+ insn = RVC_RS2S(insn) << SH_RD;
+ } else if ((insn & INSN_MASK_C_FLDSP) == INSN_MATCH_C_FLDSP) {
+ fp = 1;
+ len = 8;
+#if __riscv_xlen == 32
+ } else if ((insn & INSN_MASK_C_FLW) == INSN_MATCH_C_FLW) {
+ fp = 1;
+ len = 4;
+ insn = RVC_RS2S(insn) << SH_RD;
+ } else if ((insn & INSN_MASK_C_FLWSP) == INSN_MATCH_C_FLWSP) {
+ fp = 1;
+ len = 4;
+#endif
+#endif
+ } else {
+ uptrap.epc = regs->mepc;
+ uptrap.cause = CAUSE_MISALIGNED_LOAD;
+ uptrap.tval = addr;
+ uptrap.tval2 = tval2;
+ uptrap.tinst = tinst;
+ return sbi_trap_redirect(regs, &uptrap);
+ }
+
+ val.data_u64 = 0;
+ for (i = 0; i < len; i++) {
+ val.data_bytes[i] = sbi_load_u8((void *)(addr + i),
+ &uptrap);
+ if (uptrap.cause) {
+ uptrap.epc = regs->mepc;
+ return sbi_trap_redirect(regs, &uptrap);
+ }
+ }
+
+ if (!fp)
+ 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);
+ else
+ SET_F32_RD(insn, regs, val.data_ulong);
+#endif
+
+ regs->mepc += insn_len;
+
+ return 0;
+}
+
+int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
+ struct sbi_trap_regs *regs)
+{
+ ulong insn, insn_len;
+ union reg_data val;
+ struct sbi_trap_info uptrap;
+ int i, len = 0;
+
+ if (tinst & 0x1) {
+ /*
+ * Bit[0] == 1 implies trapped instruction value is
+ * transformed instruction or custom instruction.
+ */
+ insn = tinst | INSN_16BIT_MASK;
+ insn_len = (tinst & 0x2) ? INSN_LEN(insn) : 2;
+ } else {
+ /*
+ * Bit[0] == 0 implies trapped instruction value is
+ * zero or special value.
+ */
+ insn = sbi_get_insn(regs->mepc, &uptrap);
+ if (uptrap.cause) {
+ uptrap.epc = regs->mepc;
+ return sbi_trap_redirect(regs, &uptrap);
+ }
+ insn_len = INSN_LEN(insn);
+ }
+
+ val.data_ulong = GET_RS2(insn, regs);
+
+ if ((insn & INSN_MASK_SW) == INSN_MATCH_SW) {
+ len = 4;
+#if __riscv_xlen == 64
+ } else if ((insn & INSN_MASK_SD) == INSN_MATCH_SD) {
+ len = 8;
+#endif
+#ifdef __riscv_flen
+ } else if ((insn & INSN_MASK_FSD) == INSN_MATCH_FSD) {
+ len = 8;
+ val.data_u64 = GET_F64_RS2(insn, regs);
+ } else if ((insn & INSN_MASK_FSW) == INSN_MATCH_FSW) {
+ len = 4;
+ val.data_ulong = GET_F32_RS2(insn, regs);
+#endif
+ } else if ((insn & INSN_MASK_SH) == INSN_MATCH_SH) {
+ len = 2;
+#if __riscv_xlen >= 64
+ } else if ((insn & INSN_MASK_C_SD) == INSN_MATCH_C_SD) {
+ len = 8;
+ val.data_ulong = GET_RS2S(insn, regs);
+ } else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP &&
+ ((insn >> SH_RD) & 0x1f)) {
+ len = 8;
+ val.data_ulong = GET_RS2C(insn, regs);
+#endif
+ } else if ((insn & INSN_MASK_C_SW) == INSN_MATCH_C_SW) {
+ len = 4;
+ val.data_ulong = GET_RS2S(insn, regs);
+ } else if ((insn & INSN_MASK_C_SWSP) == INSN_MATCH_C_SWSP &&
+ ((insn >> SH_RD) & 0x1f)) {
+ len = 4;
+ val.data_ulong = GET_RS2C(insn, regs);
+#ifdef __riscv_flen
+ } else if ((insn & INSN_MASK_C_FSD) == INSN_MATCH_C_FSD) {
+ len = 8;
+ val.data_u64 = GET_F64_RS2S(insn, regs);
+ } else if ((insn & INSN_MASK_C_FSDSP) == INSN_MATCH_C_FSDSP) {
+ len = 8;
+ val.data_u64 = GET_F64_RS2C(insn, regs);
+#if __riscv_xlen == 32
+ } else if ((insn & INSN_MASK_C_FSW) == INSN_MATCH_C_FSW) {
+ len = 4;
+ val.data_ulong = GET_F32_RS2S(insn, regs);
+ } else if ((insn & INSN_MASK_C_FSWSP) == INSN_MATCH_C_FSWSP) {
+ len = 4;
+ val.data_ulong = GET_F32_RS2C(insn, regs);
+#endif
+#endif
+ } else {
+ uptrap.epc = regs->mepc;
+ uptrap.cause = CAUSE_MISALIGNED_STORE;
+ uptrap.tval = addr;
+ uptrap.tval2 = tval2;
+ uptrap.tinst = tinst;
+ return sbi_trap_redirect(regs, &uptrap);
+ }
+
+ for (i = 0; i < len; i++) {
+ sbi_store_u8((void *)(addr + i), val.data_bytes[i],
+ &uptrap);
+ if (uptrap.cause) {
+ uptrap.epc = regs->mepc;
+ return sbi_trap_redirect(regs, &uptrap);
+ }
+ }
+
+ regs->mepc += insn_len;
+
+ return 0;
+}
diff --git a/roms/opensbi/lib/sbi/sbi_platform.c b/roms/opensbi/lib/sbi/sbi_platform.c
new file mode 100644
index 000000000..568d95661
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_platform.c
@@ -0,0 +1,90 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Atish Patra <atish.patra@wdc.com>
+ */
+
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_string.h>
+
+static inline char *sbi_platform_feature_id2string(unsigned long feature)
+{
+ char *fstr = NULL;
+
+ if (!feature)
+ return NULL;
+
+ switch (feature) {
+ case SBI_PLATFORM_HAS_TIMER_VALUE:
+ fstr = "timer";
+ break;
+ case SBI_PLATFORM_HAS_HART_HOTPLUG:
+ fstr = "hotplug";
+ break;
+ case SBI_PLATFORM_HAS_MFAULTS_DELEGATION:
+ fstr = "mfdeleg";
+ break;
+ case SBI_PLATFORM_HAS_HART_SECONDARY_BOOT:
+ fstr = "sec_boot";
+ break;
+ default:
+ break;
+ }
+
+ return fstr;
+}
+
+void sbi_platform_get_features_str(const struct sbi_platform *plat,
+ char *features_str, int nfstr)
+{
+ unsigned long features, feat = 1UL;
+ char *temp;
+ int offset = 0;
+
+ if (!plat || !features_str || !nfstr)
+ return;
+ sbi_memset(features_str, 0, nfstr);
+
+ features = sbi_platform_get_features(plat);
+ if (!features)
+ goto done;
+
+ do {
+ if (features & feat) {
+ temp = sbi_platform_feature_id2string(feat);
+ if (temp) {
+ sbi_snprintf(features_str + offset, nfstr,
+ "%s,", temp);
+ offset = offset + sbi_strlen(temp) + 1;
+ }
+ }
+ feat = feat << 1;
+ } while (feat <= SBI_PLATFORM_HAS_LAST_FEATURE);
+
+done:
+ if (offset)
+ features_str[offset - 1] = '\0';
+ else
+ sbi_strncpy(features_str, "none", nfstr);
+}
+
+u32 sbi_platform_hart_index(const struct sbi_platform *plat, u32 hartid)
+{
+ u32 i;
+
+ if (!plat)
+ return -1U;
+ if (plat->hart_index2id) {
+ for (i = 0; i < plat->hart_count; i++) {
+ if (plat->hart_index2id[i] == hartid)
+ return i;
+ }
+ return -1U;
+ }
+
+ return hartid;
+}
diff --git a/roms/opensbi/lib/sbi/sbi_scratch.c b/roms/opensbi/lib/sbi/sbi_scratch.c
new file mode 100644
index 000000000..96bae5be4
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_scratch.c
@@ -0,0 +1,99 @@
+ /*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/riscv_locks.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_hartmask.h>
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_scratch.h>
+#include <sbi/sbi_string.h>
+
+u32 last_hartid_having_scratch = SBI_HARTMASK_MAX_BITS;
+struct sbi_scratch *hartid_to_scratch_table[SBI_HARTMASK_MAX_BITS] = { 0 };
+
+static spinlock_t extra_lock = SPIN_LOCK_INITIALIZER;
+static unsigned long extra_offset = SBI_SCRATCH_EXTRA_SPACE_OFFSET;
+
+typedef struct sbi_scratch *(*hartid2scratch)(ulong hartid, ulong hartindex);
+
+int sbi_scratch_init(struct sbi_scratch *scratch)
+{
+ u32 i;
+ const struct sbi_platform *plat = sbi_platform_ptr(scratch);
+
+ for (i = 0; i < SBI_HARTMASK_MAX_BITS; i++) {
+ if (sbi_platform_hart_invalid(plat, i))
+ continue;
+ hartid_to_scratch_table[i] =
+ ((hartid2scratch)scratch->hartid_to_scratch)(i,
+ sbi_platform_hart_index(plat, i));
+ if (hartid_to_scratch_table[i])
+ last_hartid_having_scratch = i;
+ }
+
+ return 0;
+}
+
+unsigned long sbi_scratch_alloc_offset(unsigned long size, const char *owner)
+{
+ u32 i;
+ void *ptr;
+ unsigned long ret = 0;
+ struct sbi_scratch *rscratch;
+
+ /*
+ * We have a simple brain-dead allocator which never expects
+ * anything to be free-ed hence it keeps incrementing the
+ * next allocation offset until it runs-out of space.
+ *
+ * In future, we will have more sophisticated allocator which
+ * will allow us to re-claim free-ed space.
+ */
+
+ if (!size)
+ return 0;
+
+ if (size & (__SIZEOF_POINTER__ - 1))
+ size = (size & ~(__SIZEOF_POINTER__ - 1)) + __SIZEOF_POINTER__;
+
+ spin_lock(&extra_lock);
+
+ if (SBI_SCRATCH_SIZE < (extra_offset + size))
+ goto done;
+
+ ret = extra_offset;
+ extra_offset += size;
+
+done:
+ spin_unlock(&extra_lock);
+
+ if (ret) {
+ for (i = 0; i < sbi_scratch_last_hartid(); i++) {
+ rscratch = sbi_hartid_to_scratch(i);
+ if (!rscratch)
+ continue;
+ ptr = sbi_scratch_offset_ptr(rscratch, ret);
+ sbi_memset(ptr, 0, size);
+ }
+ }
+
+ return ret;
+}
+
+void sbi_scratch_free_offset(unsigned long offset)
+{
+ if ((offset < SBI_SCRATCH_EXTRA_SPACE_OFFSET) ||
+ (SBI_SCRATCH_SIZE <= offset))
+ return;
+
+ /*
+ * We don't actually free-up because it's a simple
+ * brain-dead allocator.
+ */
+}
diff --git a/roms/opensbi/lib/sbi/sbi_string.c b/roms/opensbi/lib/sbi/sbi_string.c
new file mode 100644
index 000000000..7805ba4ad
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_string.c
@@ -0,0 +1,188 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Atish Patra <atish.patra@wdc.com>
+ */
+
+/*
+ * Simple libc functions. These are not optimized at all and might have some
+ * bugs as well. Use any optimized routines from newlib or glibc if required.
+ */
+
+#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 */
+ for (; *a == *b && *a != '\0'; a++, 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;
+
+ while (*str != '\0') {
+ ret++;
+ str++;
+ }
+
+ return ret;
+}
+
+size_t sbi_strnlen(const char *str, size_t count)
+{
+ unsigned long ret = 0;
+
+ while (*str != '\0' && ret < count) {
+ ret++;
+ str++;
+ count--;
+ }
+
+ return ret;
+}
+
+char *sbi_strcpy(char *dest, const char *src)
+{
+ char *ret = dest;
+
+ while (*src != '\0') {
+ *dest++ = *src++;
+ }
+
+ return ret;
+}
+
+char *sbi_strncpy(char *dest, const char *src, size_t count)
+{
+ char *ret = dest;
+
+ while (count-- && *src != '\0') {
+ *dest++ = *src++;
+ }
+
+ return ret;
+}
+
+char *sbi_strchr(const char *s, int c)
+{
+ while (*s != '\0' && *s != (char)c)
+ s++;
+
+ if (*s == '\0')
+ return NULL;
+ else
+ return (char *)s;
+}
+
+char *sbi_strrchr(const char *s, int c)
+{
+ const char *last = s + sbi_strlen(s);
+
+ while (last > s && *last != (char)c)
+ last--;
+
+ if (*last != (char)c)
+ return NULL;
+ else
+ return (char *)last;
+}
+void *sbi_memset(void *s, int c, size_t count)
+{
+ char *temp = s;
+
+ while (count > 0) {
+ count--;
+ *temp++ = c;
+ }
+
+ return s;
+}
+
+void *sbi_memcpy(void *dest, const void *src, size_t count)
+{
+ char *temp1 = dest;
+ const char *temp2 = src;
+
+ while (count > 0) {
+ *temp1++ = *temp2++;
+ count--;
+ }
+
+ return dest;
+}
+
+void *sbi_memmove(void *dest, const void *src, size_t count)
+{
+ char *temp1 = (char *)dest;
+ const char *temp2 = (char *)src;
+
+ if (src == dest)
+ return dest;
+
+ if (dest < src) {
+ while (count > 0) {
+ *temp1++ = *temp2++;
+ count--;
+ }
+ } else {
+ temp1 = dest + count - 1;
+ temp2 = src + count - 1;
+
+ while (count > 0) {
+ *temp1-- = *temp2--;
+ count--;
+ }
+ }
+
+ return dest;
+}
+
+int sbi_memcmp(const void *s1, const void *s2, size_t count)
+{
+ const char *temp1 = s1;
+ const char *temp2 = s2;
+
+ for (; count > 0 && (*temp1 == *temp2); count--) {
+ temp1++;
+ temp2++;
+ }
+
+ if (count > 0)
+ return *(unsigned char *)temp1 - *(unsigned char *)temp2;
+ else
+ return 0;
+}
+
+void *sbi_memchr(const void *s, int c, size_t count)
+{
+ const unsigned char *temp = s;
+
+ while (count > 0) {
+ if ((unsigned char)c == *temp++) {
+ return (void *)(temp - 1);
+ }
+ count--;
+ }
+
+ return NULL;
+}
diff --git a/roms/opensbi/lib/sbi/sbi_system.c b/roms/opensbi/lib/sbi/sbi_system.c
new file mode 100644
index 000000000..08a8b47c7
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_system.c
@@ -0,0 +1,56 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ * Nick Kossifidis <mick@ics.forth.gr>
+ */
+
+#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>
+#include <sbi/sbi_system.h>
+#include <sbi/sbi_ipi.h>
+#include <sbi/sbi_init.h>
+
+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(dom, hbase, &hmask)) {
+ if (hbase <= cur_hartid)
+ hmask &= ~(1UL << (cur_hartid - hbase));
+ if (hmask)
+ sbi_ipi_send_halt(hmask, hbase);
+ hbase += BITS_PER_LONG;
+ }
+
+ /* Stop current HART */
+ sbi_hsm_hart_stop(scratch, FALSE);
+
+ /* 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);
+}
diff --git a/roms/opensbi/lib/sbi/sbi_timer.c b/roms/opensbi/lib/sbi/sbi_timer.c
new file mode 100644
index 000000000..b571b1740
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_timer.c
@@ -0,0 +1,136 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_scratch.h>
+#include <sbi/sbi_timer.h>
+
+static unsigned long time_delta_off;
+static u64 (*get_time_val)(const struct sbi_platform *plat);
+
+#if __riscv_xlen == 32
+static u64 get_ticks(const struct sbi_platform *plat)
+{
+ u32 lo, hi, tmp;
+ __asm__ __volatile__("1:\n"
+ "rdtimeh %0\n"
+ "rdtime %1\n"
+ "rdtimeh %2\n"
+ "bne %0, %2, 1b"
+ : "=&r"(hi), "=&r"(lo), "=&r"(tmp));
+ return ((u64)hi << 32) | lo;
+}
+#else
+static u64 get_ticks(const struct sbi_platform *plat)
+{
+ unsigned long n;
+
+ __asm__ __volatile__("rdtime %0" : "=r"(n));
+ return n;
+}
+#endif
+
+u64 sbi_timer_value(void)
+{
+ return get_time_val(sbi_platform_thishart_ptr());
+}
+
+u64 sbi_timer_virt_value(void)
+{
+ u64 *time_delta = sbi_scratch_offset_ptr(sbi_scratch_thishart_ptr(),
+ time_delta_off);
+
+ return sbi_timer_value() + *time_delta;
+}
+
+u64 sbi_timer_get_delta(void)
+{
+ u64 *time_delta = sbi_scratch_offset_ptr(sbi_scratch_thishart_ptr(),
+ time_delta_off);
+
+ return *time_delta;
+}
+
+void sbi_timer_set_delta(ulong delta)
+{
+ u64 *time_delta = sbi_scratch_offset_ptr(sbi_scratch_thishart_ptr(),
+ time_delta_off);
+
+ *time_delta = (u64)delta;
+}
+
+void sbi_timer_set_delta_upper(ulong delta_upper)
+{
+ u64 *time_delta = sbi_scratch_offset_ptr(sbi_scratch_thishart_ptr(),
+ time_delta_off);
+
+ *time_delta &= 0xffffffffULL;
+ *time_delta |= ((u64)delta_upper << 32);
+}
+
+void sbi_timer_event_start(u64 next_event)
+{
+ sbi_platform_timer_event_start(sbi_platform_thishart_ptr(), next_event);
+ csr_clear(CSR_MIP, MIP_STIP);
+ csr_set(CSR_MIE, MIP_MTIP);
+}
+
+void sbi_timer_process(void)
+{
+ csr_clear(CSR_MIE, MIP_MTIP);
+ csr_set(CSR_MIP, MIP_STIP);
+}
+
+int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
+{
+ u64 *time_delta;
+ const struct sbi_platform *plat = sbi_platform_ptr(scratch);
+ int ret;
+
+ if (cold_boot) {
+ time_delta_off = sbi_scratch_alloc_offset(sizeof(*time_delta),
+ "TIME_DELTA");
+ if (!time_delta_off)
+ return SBI_ENOMEM;
+ } else {
+ if (!time_delta_off)
+ return SBI_ENOMEM;
+ }
+
+ time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
+ *time_delta = 0;
+
+ ret = sbi_platform_timer_init(plat, cold_boot);
+ if (ret)
+ return ret;
+
+ if (sbi_hart_has_feature(scratch, SBI_HART_HAS_TIME))
+ get_time_val = get_ticks;
+ else if (sbi_platform_has_timer_value(plat))
+ get_time_val = sbi_platform_timer_value;
+ else
+ /* There is no method to provide timer value */
+ return SBI_ENODEV;
+
+ return 0;
+}
+
+void sbi_timer_exit(struct sbi_scratch *scratch)
+{
+ sbi_platform_timer_event_stop(sbi_platform_ptr(scratch));
+
+ csr_clear(CSR_MIP, MIP_STIP);
+ csr_clear(CSR_MIE, MIP_MTIP);
+
+ sbi_platform_timer_exit(sbi_platform_ptr(scratch));
+}
diff --git a/roms/opensbi/lib/sbi/sbi_tlb.c b/roms/opensbi/lib/sbi/sbi_tlb.c
new file mode 100644
index 000000000..73f59e868
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_tlb.c
@@ -0,0 +1,429 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Atish Patra <atish.patra@wdc.com>
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_atomic.h>
+#include <sbi/riscv_barrier.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_fifo.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_ipi.h>
+#include <sbi/sbi_scratch.h>
+#include <sbi/sbi_tlb.h>
+#include <sbi/sbi_hfence.h>
+#include <sbi/sbi_string.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_platform.h>
+
+static unsigned long tlb_sync_off;
+static unsigned long tlb_fifo_off;
+static unsigned long tlb_fifo_mem_off;
+static unsigned long tlb_range_flush_limit;
+
+static void sbi_tlb_flush_all(void)
+{
+ __asm__ __volatile("sfence.vma");
+}
+
+void sbi_tlb_local_hfence_vvma(struct sbi_tlb_info *tinfo)
+{
+ unsigned long start = tinfo->start;
+ unsigned long size = tinfo->size;
+ unsigned long vmid = tinfo->vmid;
+ unsigned long i, hgatp;
+
+ hgatp = csr_swap(CSR_HGATP,
+ (vmid << HGATP_VMID_SHIFT) & HGATP_VMID_MASK);
+
+ if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
+ __sbi_hfence_vvma_all();
+ goto done;
+ }
+
+ for (i = 0; i < size; i += PAGE_SIZE) {
+ __sbi_hfence_vvma_va(start+i);
+ }
+
+done:
+ csr_write(CSR_HGATP, hgatp);
+}
+
+void sbi_tlb_local_hfence_gvma(struct sbi_tlb_info *tinfo)
+{
+ unsigned long start = tinfo->start;
+ unsigned long size = tinfo->size;
+ unsigned long i;
+
+ if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
+ __sbi_hfence_gvma_all();
+ return;
+ }
+
+ for (i = 0; i < size; i += PAGE_SIZE) {
+ __sbi_hfence_gvma_gpa(start+i);
+ }
+}
+
+void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo)
+{
+ unsigned long start = tinfo->start;
+ unsigned long size = tinfo->size;
+ unsigned long i;
+
+ if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
+ sbi_tlb_flush_all();
+ return;
+ }
+
+ for (i = 0; i < size; i += PAGE_SIZE) {
+ __asm__ __volatile__("sfence.vma %0"
+ :
+ : "r"(start + i)
+ : "memory");
+ }
+}
+
+void sbi_tlb_local_hfence_vvma_asid(struct sbi_tlb_info *tinfo)
+{
+ unsigned long start = tinfo->start;
+ unsigned long size = tinfo->size;
+ unsigned long asid = tinfo->asid;
+ unsigned long vmid = tinfo->vmid;
+ unsigned long i, hgatp;
+
+ hgatp = csr_swap(CSR_HGATP,
+ (vmid << HGATP_VMID_SHIFT) & HGATP_VMID_MASK);
+
+ if (start == 0 && size == 0) {
+ __sbi_hfence_vvma_all();
+ goto done;
+ }
+
+ if (size == SBI_TLB_FLUSH_ALL) {
+ __sbi_hfence_vvma_asid(asid);
+ goto done;
+ }
+
+ for (i = 0; i < size; i += PAGE_SIZE) {
+ __sbi_hfence_vvma_asid_va(start + i, asid);
+ }
+
+done:
+ csr_write(CSR_HGATP, hgatp);
+}
+
+void sbi_tlb_local_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
+{
+ unsigned long start = tinfo->start;
+ unsigned long size = tinfo->size;
+ unsigned long vmid = tinfo->vmid;
+ unsigned long i;
+
+ if (start == 0 && size == 0) {
+ __sbi_hfence_gvma_all();
+ return;
+ }
+
+ if (size == SBI_TLB_FLUSH_ALL) {
+ __sbi_hfence_gvma_vmid(vmid);
+ return;
+ }
+
+ for (i = 0; i < size; i += PAGE_SIZE) {
+ __sbi_hfence_gvma_vmid_gpa(start + i, vmid);
+ }
+}
+
+void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo)
+{
+ unsigned long start = tinfo->start;
+ unsigned long size = tinfo->size;
+ unsigned long asid = tinfo->asid;
+ unsigned long i;
+
+ if (start == 0 && size == 0) {
+ sbi_tlb_flush_all();
+ return;
+ }
+
+ /* Flush entire MM context for a given ASID */
+ if (size == SBI_TLB_FLUSH_ALL) {
+ __asm__ __volatile__("sfence.vma x0, %0"
+ :
+ : "r"(asid)
+ : "memory");
+ return;
+ }
+
+ for (i = 0; i < size; i += PAGE_SIZE) {
+ __asm__ __volatile__("sfence.vma %0, %1"
+ :
+ : "r"(start + i), "r"(asid)
+ : "memory");
+ }
+}
+
+void sbi_tlb_local_fence_i(struct sbi_tlb_info *tinfo)
+{
+ __asm__ __volatile("fence.i");
+}
+
+static void sbi_tlb_entry_process(struct sbi_tlb_info *tinfo)
+{
+ u32 rhartid;
+ struct sbi_scratch *rscratch = NULL;
+ unsigned long *rtlb_sync = NULL;
+
+ tinfo->local_fn(tinfo);
+
+ sbi_hartmask_for_each_hart(rhartid, &tinfo->smask) {
+ rscratch = sbi_hartid_to_scratch(rhartid);
+ if (!rscratch)
+ continue;
+
+ rtlb_sync = sbi_scratch_offset_ptr(rscratch, tlb_sync_off);
+ while (atomic_raw_xchg_ulong(rtlb_sync, 1)) ;
+ }
+}
+
+static void sbi_tlb_process_count(struct sbi_scratch *scratch, int count)
+{
+ struct sbi_tlb_info tinfo;
+ u32 deq_count = 0;
+ struct sbi_fifo *tlb_fifo =
+ sbi_scratch_offset_ptr(scratch, tlb_fifo_off);
+
+ while (!sbi_fifo_dequeue(tlb_fifo, &tinfo)) {
+ sbi_tlb_entry_process(&tinfo);
+ deq_count++;
+ if (deq_count > count)
+ break;
+
+ }
+}
+
+static void sbi_tlb_process(struct sbi_scratch *scratch)
+{
+ struct sbi_tlb_info tinfo;
+ struct sbi_fifo *tlb_fifo =
+ sbi_scratch_offset_ptr(scratch, tlb_fifo_off);
+
+ while (!sbi_fifo_dequeue(tlb_fifo, &tinfo))
+ sbi_tlb_entry_process(&tinfo);
+}
+
+static void sbi_tlb_sync(struct sbi_scratch *scratch)
+{
+ unsigned long *tlb_sync =
+ sbi_scratch_offset_ptr(scratch, tlb_sync_off);
+
+ while (!atomic_raw_xchg_ulong(tlb_sync, 0)) {
+ /*
+ * While we are waiting for remote hart to set the sync,
+ * consume fifo requests to avoid deadlock.
+ */
+ sbi_tlb_process_count(scratch, 1);
+ }
+
+ return;
+}
+
+static inline int __sbi_tlb_range_check(struct sbi_tlb_info *curr,
+ struct sbi_tlb_info *next)
+{
+ unsigned long curr_end;
+ unsigned long next_end;
+ int ret = SBI_FIFO_UNCHANGED;
+
+ if (!curr || !next)
+ return ret;
+
+ next_end = next->start + next->size;
+ curr_end = curr->start + curr->size;
+ if (next->start <= curr->start && next_end > curr_end) {
+ curr->start = next->start;
+ curr->size = next->size;
+ sbi_hartmask_or(&curr->smask, &curr->smask, &next->smask);
+ ret = SBI_FIFO_UPDATED;
+ } else if (next->start >= curr->start && next_end <= curr_end) {
+ sbi_hartmask_or(&curr->smask, &curr->smask, &next->smask);
+ ret = SBI_FIFO_SKIP;
+ }
+
+ return ret;
+}
+
+/**
+ * Call back to decide if an inplace fifo update is required or next entry can
+ * can be skipped. Here are the different cases that are being handled.
+ *
+ * Case1:
+ * if next flush request range lies within one of the existing entry, skip
+ * the next entry.
+ * Case2:
+ * if flush request range in current fifo entry lies within next flush
+ * request, update the current entry.
+ *
+ * Note:
+ * We can not issue a fifo reset anymore if a complete vma flush is requested.
+ * This is because we are queueing FENCE.I requests as well now.
+ * To ease up the pressure in enqueue/fifo sync path, try to dequeue 1 element
+ * before continuing the while loop. This method is preferred over wfi/ipi because
+ * of MMIO cost involved in later method.
+ */
+static int sbi_tlb_update_cb(void *in, void *data)
+{
+ struct sbi_tlb_info *curr;
+ struct sbi_tlb_info *next;
+ int ret = SBI_FIFO_UNCHANGED;
+
+ if (!in || !data)
+ return ret;
+
+ curr = (struct sbi_tlb_info *)data;
+ next = (struct sbi_tlb_info *)in;
+
+ if (next->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->local_fn == sbi_tlb_local_sfence_vma &&
+ curr->local_fn == sbi_tlb_local_sfence_vma) {
+ ret = __sbi_tlb_range_check(curr, next);
+ }
+
+ return ret;
+}
+
+static int sbi_tlb_update(struct sbi_scratch *scratch,
+ struct sbi_scratch *remote_scratch,
+ u32 remote_hartid, void *data)
+{
+ int ret;
+ struct sbi_fifo *tlb_fifo_r;
+ struct sbi_tlb_info *tinfo = data;
+ u32 curr_hartid = current_hartid();
+
+ /*
+ * If address range to flush is too big then simply
+ * upgrade it to flush all because we can only flush
+ * 4KB at a time.
+ */
+ if (tinfo->size > tlb_range_flush_limit) {
+ tinfo->start = 0;
+ tinfo->size = SBI_TLB_FLUSH_ALL;
+ }
+
+ /*
+ * If the request is to queue a tlb flush entry for itself
+ * then just do a local flush and return;
+ */
+ if (remote_hartid == curr_hartid) {
+ tinfo->local_fn(tinfo);
+ return -1;
+ }
+
+ tlb_fifo_r = sbi_scratch_offset_ptr(remote_scratch, tlb_fifo_off);
+
+ ret = sbi_fifo_inplace_update(tlb_fifo_r, data, sbi_tlb_update_cb);
+ if (ret != SBI_FIFO_UNCHANGED) {
+ return 1;
+ }
+
+ while (sbi_fifo_enqueue(tlb_fifo_r, data) < 0) {
+ /**
+ * For now, Busy loop until there is space in the fifo.
+ * There may be case where target hart is also
+ * enqueue in source hart's fifo. Both hart may busy
+ * loop leading to a deadlock.
+ * TODO: Introduce a wait/wakeup event mechanism to handle
+ * this properly.
+ */
+ sbi_tlb_process_count(scratch, 1);
+ sbi_dprintf("hart%d: hart%d tlb fifo full\n",
+ curr_hartid, remote_hartid);
+ }
+
+ return 0;
+}
+
+static struct sbi_ipi_event_ops tlb_ops = {
+ .name = "IPI_TLB",
+ .update = sbi_tlb_update,
+ .sync = sbi_tlb_sync,
+ .process = sbi_tlb_process,
+};
+
+static u32 tlb_event = SBI_IPI_EVENT_MAX;
+
+int sbi_tlb_request(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);
+}
+
+int sbi_tlb_init(struct sbi_scratch *scratch, bool cold_boot)
+{
+ int ret;
+ void *tlb_mem;
+ unsigned long *tlb_sync;
+ struct sbi_fifo *tlb_q;
+ const struct sbi_platform *plat = sbi_platform_ptr(scratch);
+
+ if (cold_boot) {
+ tlb_sync_off = sbi_scratch_alloc_offset(sizeof(*tlb_sync),
+ "IPI_TLB_SYNC");
+ if (!tlb_sync_off)
+ return SBI_ENOMEM;
+ tlb_fifo_off = sbi_scratch_alloc_offset(sizeof(*tlb_q),
+ "IPI_TLB_FIFO");
+ if (!tlb_fifo_off) {
+ sbi_scratch_free_offset(tlb_sync_off);
+ return SBI_ENOMEM;
+ }
+ tlb_fifo_mem_off = sbi_scratch_alloc_offset(
+ SBI_TLB_FIFO_NUM_ENTRIES * SBI_TLB_INFO_SIZE,
+ "IPI_TLB_FIFO_MEM");
+ if (!tlb_fifo_mem_off) {
+ sbi_scratch_free_offset(tlb_fifo_off);
+ sbi_scratch_free_offset(tlb_sync_off);
+ return SBI_ENOMEM;
+ }
+ ret = sbi_ipi_event_create(&tlb_ops);
+ if (ret < 0) {
+ sbi_scratch_free_offset(tlb_fifo_mem_off);
+ sbi_scratch_free_offset(tlb_fifo_off);
+ sbi_scratch_free_offset(tlb_sync_off);
+ return ret;
+ }
+ tlb_event = ret;
+ tlb_range_flush_limit = sbi_platform_tlbr_flush_limit(plat);
+ } else {
+ if (!tlb_sync_off ||
+ !tlb_fifo_off ||
+ !tlb_fifo_mem_off)
+ return SBI_ENOMEM;
+ if (SBI_IPI_EVENT_MAX <= tlb_event)
+ return SBI_ENOSPC;
+ }
+
+ tlb_sync = sbi_scratch_offset_ptr(scratch, tlb_sync_off);
+ tlb_q = sbi_scratch_offset_ptr(scratch, tlb_fifo_off);
+ tlb_mem = sbi_scratch_offset_ptr(scratch, tlb_fifo_mem_off);
+
+ *tlb_sync = 0;
+
+ sbi_fifo_init(tlb_q, tlb_mem,
+ SBI_TLB_FIFO_NUM_ENTRIES, SBI_TLB_INFO_SIZE);
+
+ return 0;
+}
diff --git a/roms/opensbi/lib/sbi/sbi_trap.c b/roms/opensbi/lib/sbi/sbi_trap.c
new file mode 100644
index 000000000..b7349d2c9
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_trap.c
@@ -0,0 +1,293 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_ecall.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_hart.h>
+#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>
+
+static void __noreturn sbi_trap_error(const char *msg, int rc,
+ ulong mcause, ulong mtval, ulong mtval2,
+ ulong mtinst, struct sbi_trap_regs *regs)
+{
+ u32 hartid = current_hartid();
+
+ sbi_printf("%s: hart%d: %s (error %d)\n", __func__, hartid, msg, rc);
+ sbi_printf("%s: hart%d: mcause=0x%" PRILX " mtval=0x%" PRILX "\n",
+ __func__, hartid, mcause, mtval);
+ if (misa_extension('H')) {
+ sbi_printf("%s: hart%d: mtval2=0x%" PRILX
+ " mtinst=0x%" PRILX "\n",
+ __func__, hartid, mtval2, mtinst);
+ }
+ sbi_printf("%s: hart%d: mepc=0x%" PRILX " mstatus=0x%" PRILX "\n",
+ __func__, hartid, regs->mepc, regs->mstatus);
+ sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
+ hartid, "ra", regs->ra, "sp", regs->sp);
+ sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
+ hartid, "gp", regs->gp, "tp", regs->tp);
+ sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
+ hartid, "s0", regs->s0, "s1", regs->s1);
+ sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
+ hartid, "a0", regs->a0, "a1", regs->a1);
+ sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
+ hartid, "a2", regs->a2, "a3", regs->a3);
+ sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
+ hartid, "a4", regs->a4, "a5", regs->a5);
+ sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
+ hartid, "a6", regs->a6, "a7", regs->a7);
+ sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
+ hartid, "s2", regs->s2, "s3", regs->s3);
+ sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
+ hartid, "s4", regs->s4, "s5", regs->s5);
+ sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
+ hartid, "s6", regs->s6, "s7", regs->s7);
+ sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
+ hartid, "s8", regs->s8, "s9", regs->s9);
+ sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
+ hartid, "s10", regs->s10, "s11", regs->s11);
+ sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
+ hartid, "t0", regs->t0, "t1", regs->t1);
+ sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
+ hartid, "t2", regs->t2, "t3", regs->t3);
+ sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
+ hartid, "t4", regs->t4, "t5", regs->t5);
+ sbi_printf("%s: hart%d: %s=0x%" PRILX "\n", __func__, hartid, "t6",
+ regs->t6);
+
+ sbi_hart_hang();
+}
+
+/**
+ * Redirect trap to lower privledge mode (S-mode or U-mode)
+ *
+ * @param regs pointer to register state
+ * @param trap pointer to trap details
+ *
+ * @return 0 on success and negative error code on failure
+ */
+int sbi_trap_redirect(struct sbi_trap_regs *regs,
+ struct sbi_trap_info *trap)
+{
+ ulong hstatus, vsstatus, prev_mode;
+#if __riscv_xlen == 32
+ bool prev_virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
+#else
+ bool prev_virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
+#endif
+ /* By default, we redirect to HS-mode */
+ bool next_virt = FALSE;
+
+ /* Sanity check on previous mode */
+ prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
+ if (prev_mode != PRV_S && prev_mode != PRV_U)
+ return SBI_ENOTSUPP;
+
+ /* For certain exceptions from VS/VU-mode we redirect to VS-mode */
+ if (misa_extension('H') && prev_virt) {
+ switch (trap->cause) {
+ case CAUSE_FETCH_PAGE_FAULT:
+ case CAUSE_LOAD_PAGE_FAULT:
+ case CAUSE_STORE_PAGE_FAULT:
+ next_virt = TRUE;
+ break;
+ default:
+ break;
+ };
+ }
+
+ /* Update MSTATUS MPV bits */
+#if __riscv_xlen == 32
+ regs->mstatusH &= ~MSTATUSH_MPV;
+ regs->mstatusH |= (next_virt) ? MSTATUSH_MPV : 0UL;
+#else
+ regs->mstatus &= ~MSTATUS_MPV;
+ regs->mstatus |= (next_virt) ? MSTATUS_MPV : 0UL;
+#endif
+
+ /* Update HSTATUS for VS/VU-mode to HS-mode transition */
+ if (misa_extension('H') && prev_virt && !next_virt) {
+ /* Update HSTATUS SPVP and SPV bits */
+ hstatus = csr_read(CSR_HSTATUS);
+ hstatus &= ~HSTATUS_SPVP;
+ hstatus |= (prev_mode == PRV_S) ? HSTATUS_SPVP : 0;
+ hstatus &= ~HSTATUS_SPV;
+ hstatus |= (prev_virt) ? HSTATUS_SPV : 0;
+ csr_write(CSR_HSTATUS, hstatus);
+ csr_write(CSR_HTVAL, trap->tval2);
+ csr_write(CSR_HTINST, trap->tinst);
+ }
+
+ /* Update exception related CSRs */
+ if (next_virt) {
+ /* Update VS-mode exception info */
+ csr_write(CSR_VSTVAL, trap->tval);
+ csr_write(CSR_VSEPC, trap->epc);
+ csr_write(CSR_VSCAUSE, trap->cause);
+
+ /* Set MEPC to VS-mode exception vector base */
+ regs->mepc = csr_read(CSR_VSTVEC);
+
+ /* Set MPP to VS-mode */
+ regs->mstatus &= ~MSTATUS_MPP;
+ regs->mstatus |= (PRV_S << MSTATUS_MPP_SHIFT);
+
+ /* Get VS-mode SSTATUS CSR */
+ vsstatus = csr_read(CSR_VSSTATUS);
+
+ /* Set SPP for VS-mode */
+ vsstatus &= ~SSTATUS_SPP;
+ if (prev_mode == PRV_S)
+ vsstatus |= (1UL << SSTATUS_SPP_SHIFT);
+
+ /* Set SPIE for VS-mode */
+ vsstatus &= ~SSTATUS_SPIE;
+ if (vsstatus & SSTATUS_SIE)
+ vsstatus |= (1UL << SSTATUS_SPIE_SHIFT);
+
+ /* Clear SIE for VS-mode */
+ vsstatus &= ~SSTATUS_SIE;
+
+ /* Update VS-mode SSTATUS CSR */
+ csr_write(CSR_VSSTATUS, vsstatus);
+ } else {
+ /* Update S-mode exception info */
+ csr_write(CSR_STVAL, trap->tval);
+ csr_write(CSR_SEPC, trap->epc);
+ csr_write(CSR_SCAUSE, trap->cause);
+
+ /* Set MEPC to S-mode exception vector base */
+ regs->mepc = csr_read(CSR_STVEC);
+
+ /* Set MPP to S-mode */
+ regs->mstatus &= ~MSTATUS_MPP;
+ regs->mstatus |= (PRV_S << MSTATUS_MPP_SHIFT);
+
+ /* Set SPP for S-mode */
+ regs->mstatus &= ~MSTATUS_SPP;
+ if (prev_mode == PRV_S)
+ regs->mstatus |= (1UL << MSTATUS_SPP_SHIFT);
+
+ /* Set SPIE for S-mode */
+ regs->mstatus &= ~MSTATUS_SPIE;
+ if (regs->mstatus & MSTATUS_SIE)
+ regs->mstatus |= (1UL << MSTATUS_SPIE_SHIFT);
+
+ /* Clear SIE for S-mode */
+ regs->mstatus &= ~MSTATUS_SIE;
+ }
+
+ return 0;
+}
+
+/**
+ * Handle trap/interrupt
+ *
+ * This function is called by firmware linked to OpenSBI
+ * library for handling trap/interrupt. It expects the
+ * following:
+ * 1. The 'mscratch' CSR is pointing to sbi_scratch of current HART
+ * 2. The 'mcause' CSR is having exception/interrupt cause
+ * 3. The 'mtval' CSR is having additional trap information
+ * 4. The 'mtval2' CSR is having additional trap information
+ * 5. The 'mtinst' CSR is having decoded trap instruction
+ * 6. Stack pointer (SP) is setup for current HART
+ * 7. Interrupts are disabled in MSTATUS CSR
+ *
+ * @param regs pointer to register state
+ */
+void sbi_trap_handler(struct sbi_trap_regs *regs)
+{
+ int rc = SBI_ENOTSUPP;
+ const char *msg = "trap handler failed";
+ ulong mcause = csr_read(CSR_MCAUSE);
+ ulong mtval = csr_read(CSR_MTVAL), mtval2 = 0, mtinst = 0;
+ struct sbi_trap_info trap;
+
+ if (misa_extension('H')) {
+ mtval2 = csr_read(CSR_MTVAL2);
+ mtinst = csr_read(CSR_MTINST);
+ }
+
+ if (mcause & (1UL << (__riscv_xlen - 1))) {
+ mcause &= ~(1UL << (__riscv_xlen - 1));
+ switch (mcause) {
+ case IRQ_M_TIMER:
+ sbi_timer_process();
+ break;
+ case IRQ_M_SOFT:
+ sbi_ipi_process();
+ break;
+ default:
+ msg = "unhandled external interrupt";
+ goto trap_error;
+ };
+ return;
+ }
+
+ switch (mcause) {
+ case CAUSE_ILLEGAL_INSTRUCTION:
+ rc = sbi_illegal_insn_handler(mtval, regs);
+ msg = "illegal instruction handler failed";
+ break;
+ case CAUSE_MISALIGNED_LOAD:
+ rc = sbi_misaligned_load_handler(mtval, mtval2, mtinst, regs);
+ msg = "misaligned load handler failed";
+ break;
+ case CAUSE_MISALIGNED_STORE:
+ rc = sbi_misaligned_store_handler(mtval, mtval2, mtinst, regs);
+ msg = "misaligned store handler failed";
+ break;
+ case CAUSE_SUPERVISOR_ECALL:
+ case CAUSE_MACHINE_ECALL:
+ rc = sbi_ecall_handler(regs);
+ msg = "ecall handler failed";
+ break;
+ default:
+ /* If the trap came from S or U mode, redirect it there */
+ trap.epc = regs->mepc;
+ trap.cause = mcause;
+ trap.tval = mtval;
+ trap.tval2 = mtval2;
+ trap.tinst = mtinst;
+ rc = sbi_trap_redirect(regs, &trap);
+ break;
+ };
+
+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();
+}
diff --git a/roms/opensbi/lib/sbi/sbi_unpriv.c b/roms/opensbi/lib/sbi/sbi_unpriv.c
new file mode 100644
index 000000000..42461241f
--- /dev/null
+++ b/roms/opensbi/lib/sbi/sbi_unpriv.c
@@ -0,0 +1,165 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_bitops.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_scratch.h>
+#include <sbi/sbi_trap.h>
+#include <sbi/sbi_unpriv.h>
+
+/**
+ * a3 must a pointer to the sbi_trap_info and a4 is used as a temporary
+ * register in the trap handler. Make sure that compiler doesn't use a3 & a4.
+ */
+#define DEFINE_UNPRIVILEGED_LOAD_FUNCTION(type, insn) \
+ type sbi_load_##type(const type *addr, \
+ struct sbi_trap_info *trap) \
+ { \
+ register ulong tinfo asm("a3"); \
+ register ulong mstatus = 0; \
+ register ulong mtvec = sbi_hart_expected_trap_addr(); \
+ type ret = 0; \
+ trap->cause = 0; \
+ asm volatile( \
+ "add %[tinfo], %[taddr], zero\n" \
+ "csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
+ "csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n" \
+ ".option push\n" \
+ ".option norvc\n" \
+ #insn " %[ret], %[addr]\n" \
+ ".option pop\n" \
+ "csrw " STR(CSR_MSTATUS) ", %[mstatus]\n" \
+ "csrw " STR(CSR_MTVEC) ", %[mtvec]" \
+ : [mstatus] "+&r"(mstatus), [mtvec] "+&r"(mtvec), \
+ [tinfo] "+&r"(tinfo), [ret] "=&r"(ret) \
+ : [addr] "m"(*addr), [mprv] "r"(MSTATUS_MPRV), \
+ [taddr] "r"((ulong)trap) \
+ : "a4", "memory"); \
+ return ret; \
+ }
+
+#define DEFINE_UNPRIVILEGED_STORE_FUNCTION(type, insn) \
+ void sbi_store_##type(type *addr, type val, \
+ struct sbi_trap_info *trap) \
+ { \
+ register ulong tinfo asm("a3") = (ulong)trap; \
+ register ulong mstatus = 0; \
+ register ulong mtvec = sbi_hart_expected_trap_addr(); \
+ trap->cause = 0; \
+ asm volatile( \
+ "add %[tinfo], %[taddr], zero\n" \
+ "csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
+ "csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n" \
+ ".option push\n" \
+ ".option norvc\n" \
+ #insn " %[val], %[addr]\n" \
+ ".option pop\n" \
+ "csrw " STR(CSR_MSTATUS) ", %[mstatus]\n" \
+ "csrw " STR(CSR_MTVEC) ", %[mtvec]" \
+ : [mstatus] "+&r"(mstatus), [mtvec] "+&r"(mtvec), \
+ [tinfo] "+&r"(tinfo) \
+ : [addr] "m"(*addr), [mprv] "r"(MSTATUS_MPRV), \
+ [val] "r"(val), [taddr] "r"((ulong)trap) \
+ : "a4", "memory"); \
+ }
+
+DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu)
+DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u16, lhu)
+DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s8, lb)
+DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s16, lh)
+DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s32, lw)
+DEFINE_UNPRIVILEGED_STORE_FUNCTION(u8, sb)
+DEFINE_UNPRIVILEGED_STORE_FUNCTION(u16, sh)
+DEFINE_UNPRIVILEGED_STORE_FUNCTION(u32, sw)
+#if __riscv_xlen == 64
+DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu)
+DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld)
+DEFINE_UNPRIVILEGED_STORE_FUNCTION(u64, sd)
+DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld)
+#else
+DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw)
+DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw)
+
+u64 sbi_load_u64(const u64 *addr,
+ struct sbi_trap_info *trap)
+{
+ u64 ret = sbi_load_u32((u32 *)addr, trap);
+
+ if (trap->cause)
+ return 0;
+ ret |= ((u64)sbi_load_u32((u32 *)addr + 1, trap) << 32);
+ if (trap->cause)
+ return 0;
+
+ return ret;
+}
+
+void sbi_store_u64(u64 *addr, u64 val,
+ struct sbi_trap_info *trap)
+{
+ sbi_store_u32((u32 *)addr, val, trap);
+ if (trap->cause)
+ return;
+
+ sbi_store_u32((u32 *)addr + 1, val >> 32, trap);
+ if (trap->cause)
+ return;
+}
+#endif
+
+ulong sbi_get_insn(ulong mepc, struct sbi_trap_info *trap)
+{
+ register ulong tinfo asm("a3");
+ register ulong ttmp asm("a4");
+ register ulong mstatus = 0;
+ register ulong mtvec = sbi_hart_expected_trap_addr();
+ ulong insn = 0;
+
+ trap->cause = 0;
+
+ asm volatile(
+ "add %[tinfo], %[taddr], zero\n"
+ "csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n"
+ "csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n"
+ "lhu %[insn], (%[addr])\n"
+ "andi %[ttmp], %[insn], 3\n"
+ "addi %[ttmp], %[ttmp], -3\n"
+ "bne %[ttmp], zero, 2f\n"
+ "lhu %[ttmp], 2(%[addr])\n"
+ "sll %[ttmp], %[ttmp], 16\n"
+ "add %[insn], %[insn], %[ttmp]\n"
+ "2: csrw " STR(CSR_MSTATUS) ", %[mstatus]\n"
+ "csrw " STR(CSR_MTVEC) ", %[mtvec]"
+ : [mstatus] "+&r"(mstatus), [mtvec] "+&r"(mtvec),
+ [tinfo] "+&r"(tinfo), [ttmp] "+&r"(ttmp),
+ [insn] "=&r"(insn)
+ : [mprv] "r"(MSTATUS_MPRV | MSTATUS_MXR),
+ [taddr] "r"((ulong)trap), [addr] "r"(mepc)
+ : "memory");
+
+ switch (trap->cause) {
+ case CAUSE_LOAD_ACCESS:
+ trap->cause = CAUSE_FETCH_ACCESS;
+ trap->tval = mepc;
+ break;
+ case CAUSE_LOAD_PAGE_FAULT:
+ trap->cause = CAUSE_FETCH_PAGE_FAULT;
+ trap->tval = mepc;
+ break;
+ case CAUSE_LOAD_GUEST_PAGE_FAULT:
+ trap->cause = CAUSE_FETCH_GUEST_PAGE_FAULT;
+ trap->tval = mepc;
+ break;
+ default:
+ break;
+ };
+
+ return insn;
+}
diff --git a/roms/opensbi/lib/utils/fdt/fdt_domain.c b/roms/opensbi/lib/utils/fdt/fdt_domain.c
new file mode 100644
index 000000000..09615e53e
--- /dev/null
+++ b/roms/opensbi/lib/utils/fdt/fdt_domain.c
@@ -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(&regions[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);
+}
diff --git a/roms/opensbi/lib/utils/fdt/fdt_fixup.c b/roms/opensbi/lib/utils/fdt/fdt_fixup.c
new file mode 100644
index 000000000..eea450d80
--- /dev/null
+++ b/roms/opensbi/lib/utils/fdt/fdt_fixup.c
@@ -0,0 +1,265 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * fdt_fixup.c - Flat Device Tree parsing helper routines
+ * Implement helper routines to parse FDT nodes on top of
+ * libfdt for OpenSBI usage
+ *
+ * Copyright (C) 2020 Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#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_scratch.h>
+#include <sbi/sbi_string.h>
+#include <sbi_utils/fdt/fdt_fixup.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+
+void fdt_cpu_fixup(void *fdt)
+{
+ 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);
+ if (err < 0)
+ return;
+
+ cpus_offset = fdt_path_offset(fdt, "/cpus");
+ if (cpus_offset < 0)
+ return;
+
+ fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
+ err = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
+ if (err)
+ continue;
+
+ /*
+ * 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");
+ }
+}
+
+void fdt_plic_fixup(void *fdt, const char *compat)
+{
+ u32 *cells;
+ int i, cells_count;
+ int plic_off;
+
+ plic_off = fdt_node_offset_by_compatible(fdt, 0, compat);
+ if (plic_off < 0)
+ return;
+
+ cells = (u32 *)fdt_getprop(fdt, plic_off,
+ "interrupts-extended", &cells_count);
+ if (!cells)
+ return;
+
+ cells_count = cells_count / sizeof(u32);
+ if (!cells_count)
+ return;
+
+ for (i = 0; i < (cells_count / 2); i++) {
+ if (fdt32_to_cpu(cells[2 * i + 1]) == IRQ_M_EXT)
+ cells[2 * i + 1] = cpu_to_fdt32(0xffffffff);
+ }
+}
+
+static int fdt_resv_memory_update_node(void *fdt, unsigned long addr,
+ unsigned long size, int index,
+ int parent, bool no_map)
+{
+ int na = fdt_address_cells(fdt, 0);
+ int ns = fdt_size_cells(fdt, 0);
+ fdt32_t addr_high, addr_low;
+ fdt32_t size_high, size_low;
+ int subnode, err;
+ fdt32_t reg[4];
+ fdt32_t *val;
+ char name[32];
+
+ addr_high = (u64)addr >> 32;
+ addr_low = addr;
+ size_high = (u64)size >> 32;
+ size_low = size;
+
+ if (na > 1 && addr_high)
+ sbi_snprintf(name, sizeof(name),
+ "mmode_resv%d@%x,%x", index,
+ addr_high, addr_low);
+ else
+ sbi_snprintf(name, sizeof(name),
+ "mmode_resv%d@%x", index,
+ addr_low);
+
+ subnode = fdt_add_subnode(fdt, parent, name);
+ if (subnode < 0)
+ return subnode;
+
+ if (no_map) {
+ /*
+ * Tell operating system not to create a virtual
+ * mapping of the region as part of its standard
+ * mapping of system memory.
+ */
+ err = fdt_setprop_empty(fdt, subnode, "no-map");
+ if (err < 0)
+ return err;
+ }
+
+ /* encode the <reg> property value */
+ val = reg;
+ if (na > 1)
+ *val++ = cpu_to_fdt32(addr_high);
+ *val++ = cpu_to_fdt32(addr_low);
+ if (ns > 1)
+ *val++ = cpu_to_fdt32(size_high);
+ *val++ = cpu_to_fdt32(size_low);
+
+ err = fdt_setprop(fdt, subnode, "reg", reg,
+ (na + ns) * sizeof(fdt32_t));
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+/**
+ * We use PMP to protect OpenSBI firmware to safe-guard it from buggy S-mode
+ * software, see pmp_init() in lib/sbi/sbi_hart.c. The protected memory region
+ * information needs to be conveyed to S-mode software (e.g.: operating system)
+ * via some well-known method.
+ *
+ * With device tree, this can be done by inserting a child node of the reserved
+ * memory node which is used to specify one or more regions of reserved memory.
+ *
+ * For the reserved memory node bindings, see Linux kernel documentation at
+ * Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt
+ *
+ * Some additional memory spaces may be protected by platform codes via PMP as
+ * well, and corresponding child nodes will be inserted.
+ */
+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 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
+ * 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;
+
+ /* try to locate the reserved memory node */
+ parent = fdt_path_offset(fdt, "/reserved-memory");
+ if (parent < 0) {
+ /* if such node does not exist, create one */
+ parent = fdt_add_subnode(fdt, 0, "reserved-memory");
+ if (parent < 0)
+ return parent;
+
+ /*
+ * reserved-memory node has 3 required properties:
+ * - #address-cells: the same value as the root node
+ * - #size-cells: the same value as the root node
+ * - ranges: should be empty
+ */
+
+ err = fdt_setprop_empty(fdt, parent, "ranges");
+ if (err < 0)
+ return err;
+
+ err = fdt_setprop_u32(fdt, parent, "#size-cells", ns);
+ if (err < 0)
+ return err;
+
+ err = fdt_setprop_u32(fdt, parent, "#address-cells", na);
+ if (err < 0)
+ return err;
+ }
+
+ /*
+ * 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 domain memory
+ * regions.
+ *
+ * With above assumption, we create child nodes directly.
+ */
+
+ 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 (reg->flags & SBI_DOMAIN_MEMREGION_READABLE)
+ continue;
+ if (reg->flags & SBI_DOMAIN_MEMREGION_WRITEABLE)
+ continue;
+ if (reg->flags & SBI_DOMAIN_MEMREGION_EXECUTABLE)
+ continue;
+
+ 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;
+}
+
+int fdt_reserved_memory_nomap_fixup(void *fdt)
+{
+ int parent, subnode;
+ int err;
+
+ /* Locate the reserved memory node */
+ parent = fdt_path_offset(fdt, "/reserved-memory");
+ if (parent < 0)
+ return parent;
+
+ fdt_for_each_subnode(subnode, fdt, parent) {
+ /*
+ * Tell operating system not to create a virtual
+ * mapping of the region as part of its standard
+ * mapping of system memory.
+ */
+ err = fdt_setprop_empty(fdt, subnode, "no-map");
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+void fdt_fixups(void *fdt)
+{
+ fdt_plic_fixup(fdt, "riscv,plic0");
+
+ fdt_reserved_memory_fixup(fdt);
+}
+
+
diff --git a/roms/opensbi/lib/utils/fdt/fdt_helper.c b/roms/opensbi/lib/utils/fdt/fdt_helper.c
new file mode 100644
index 000000000..bf19ff92d
--- /dev/null
+++ b/roms/opensbi/lib/utils/fdt/fdt_helper.c
@@ -0,0 +1,465 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * fdt_helper.c - Flat Device Tree manipulation helper routines
+ * Implement helper routines on top of libfdt for OpenSBI usage
+ *
+ * Copyright (C) 2020 Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <libfdt.h>
+#include <sbi/riscv_asm.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_hartmask.h>
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_scratch.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/irqchip/plic.h>
+#include <sbi_utils/sys/clint.h>
+
+#define DEFAULT_UART_FREQ 0
+#define DEFAULT_UART_BAUD 115200
+#define DEFAULT_UART_REG_SHIFT 0
+#define DEFAULT_UART_REG_IO_WIDTH 1
+
+#define DEFAULT_SIFIVE_UART_FREQ 0
+#define DEFAULT_SIFIVE_UART_BAUD 115200
+#define DEFAULT_SIFIVE_UART_REG_SHIFT 0
+#define DEFAULT_SIFIVE_UART_REG_IO_WIDTH 4
+
+#define DEFAULT_SHAKTI_UART_FREQ 50000000
+#define DEFAULT_SHAKTI_UART_BAUD 115200
+
+const struct fdt_match *fdt_match_node(void *fdt, int nodeoff,
+ const struct fdt_match *match_table)
+{
+ int ret;
+
+ if (!fdt || nodeoff < 0 || !match_table)
+ return NULL;
+
+ while (match_table->compatible) {
+ ret = fdt_node_check_compatible(fdt, nodeoff,
+ match_table->compatible);
+ if (!ret)
+ return match_table;
+ match_table++;
+ }
+
+ return NULL;
+}
+
+int fdt_find_match(void *fdt, int startoff,
+ const struct fdt_match *match_table,
+ const struct fdt_match **out_match)
+{
+ int nodeoff;
+
+ if (!fdt || !match_table)
+ return SBI_ENODEV;
+
+ while (match_table->compatible) {
+ nodeoff = fdt_node_offset_by_compatible(fdt, startoff,
+ match_table->compatible);
+ if (nodeoff >= 0) {
+ if (out_match)
+ *out_match = match_table;
+ return nodeoff;
+ }
+ match_table++;
+ }
+
+ 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, rc;
+ int cell_addr, cell_size;
+ const fdt32_t *prop_addr, *prop_size;
+ uint64_t temp = 0;
+
+ parent = fdt_parent_offset(fdt, node);
+ if (parent < 0)
+ return parent;
+ 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;
+
+ prop_addr = fdt_getprop(fdt, node, "reg", &len);
+ if (!prop_addr)
+ return SBI_ENODEV;
+ prop_size = prop_addr + cell_addr;
+
+ if (addr) {
+ for (i = 0; i < cell_addr; i++)
+ temp = (temp << 32) | fdt32_to_cpu(*prop_addr++);
+ 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;
+
+ if (size) {
+ for (i = 0; i < cell_size; i++)
+ temp = (temp << 32) | fdt32_to_cpu(*prop_size++);
+ *size = temp;
+ }
+
+ return 0;
+}
+
+int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid)
+{
+ int len;
+ const void *prop;
+ const fdt32_t *val;
+
+ if (!fdt || cpu_offset < 0)
+ return SBI_EINVAL;
+
+ prop = fdt_getprop(fdt, cpu_offset, "device_type", &len);
+ if (!prop || !len)
+ return SBI_EINVAL;
+ if (strncmp (prop, "cpu", strlen ("cpu")))
+ return SBI_EINVAL;
+
+ val = fdt_getprop(fdt, cpu_offset, "reg", &len);
+ if (!val || len < sizeof(fdt32_t))
+ return SBI_EINVAL;
+
+ if (len > sizeof(fdt32_t))
+ val++;
+
+ if (hartid)
+ *hartid = fdt32_to_cpu(*val);
+
+ return 0;
+}
+
+int fdt_parse_max_hart_id(void *fdt, u32 *max_hartid)
+{
+ u32 hartid;
+ int err, cpu_offset, cpus_offset;
+
+ if (!fdt)
+ return SBI_EINVAL;
+ if (!max_hartid)
+ return 0;
+
+ *max_hartid = 0;
+
+ cpus_offset = fdt_path_offset(fdt, "/cpus");
+ if (cpus_offset < 0)
+ return cpus_offset;
+
+ fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
+ err = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
+ if (err)
+ continue;
+
+ if (hartid > *max_hartid)
+ *max_hartid = hartid;
+ }
+
+ return 0;
+}
+
+int fdt_parse_shakti_uart_node(void *fdt, int nodeoffset,
+ struct platform_uart_data *uart)
+{
+ int len, rc;
+ const fdt32_t *val;
+ unsigned long reg_addr, reg_size;
+
+ if (nodeoffset < 0 || !uart || !fdt)
+ return SBI_ENODEV;
+
+ rc = fdt_get_node_addr_size(fdt, nodeoffset, &reg_addr, &reg_size);
+ if (rc < 0 || !reg_addr || !reg_size)
+ return SBI_ENODEV;
+ uart->addr = reg_addr;
+
+ /**
+ * UART address is mandaotry. clock-frequency and current-speed
+ * may not be present. Don't return error.
+ */
+ val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "clock-frequency", &len);
+ if (len > 0 && val)
+ uart->freq = fdt32_to_cpu(*val);
+ else
+ uart->freq = DEFAULT_SHAKTI_UART_FREQ;
+
+ val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "current-speed", &len);
+ if (len > 0 && val)
+ uart->baud = fdt32_to_cpu(*val);
+ else
+ uart->baud = DEFAULT_SHAKTI_UART_BAUD;
+
+ return 0;
+}
+
+int fdt_parse_sifive_uart_node(void *fdt, int nodeoffset,
+ struct platform_uart_data *uart)
+{
+ int len, rc;
+ const fdt32_t *val;
+ unsigned long reg_addr, reg_size;
+
+ if (nodeoffset < 0 || !uart || !fdt)
+ return SBI_ENODEV;
+
+ rc = fdt_get_node_addr_size(fdt, nodeoffset, &reg_addr, &reg_size);
+ if (rc < 0 || !reg_addr || !reg_size)
+ return SBI_ENODEV;
+ uart->addr = reg_addr;
+
+ /**
+ * UART address is mandaotry. clock-frequency and current-speed
+ * may not be present. Don't return error.
+ */
+ val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "clock-frequency", &len);
+ if (len > 0 && val)
+ uart->freq = fdt32_to_cpu(*val);
+ else
+ uart->freq = DEFAULT_SIFIVE_UART_FREQ;
+
+ val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "current-speed", &len);
+ if (len > 0 && val)
+ uart->baud = fdt32_to_cpu(*val);
+ else
+ uart->baud = DEFAULT_SIFIVE_UART_BAUD;
+
+ /* For SiFive UART, the reg-shift and reg-io-width are fixed .*/
+ uart->reg_shift = DEFAULT_SIFIVE_UART_REG_SHIFT;
+ uart->reg_io_width = DEFAULT_SIFIVE_UART_REG_IO_WIDTH;
+
+ return 0;
+}
+
+int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
+ struct platform_uart_data *uart)
+{
+ int len, rc;
+ const fdt32_t *val;
+ unsigned long reg_addr, reg_size;
+
+ if (nodeoffset < 0 || !uart || !fdt)
+ return SBI_ENODEV;
+
+ rc = fdt_get_node_addr_size(fdt, nodeoffset, &reg_addr, &reg_size);
+ if (rc < 0 || !reg_addr || !reg_size)
+ return SBI_ENODEV;
+ uart->addr = reg_addr;
+
+ /**
+ * UART address is mandaotry. clock-frequency and current-speed
+ * may not be present. Don't return error.
+ */
+ val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "clock-frequency", &len);
+ if (len > 0 && val)
+ uart->freq = fdt32_to_cpu(*val);
+ else
+ uart->freq = DEFAULT_UART_FREQ;
+
+ val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "current-speed", &len);
+ if (len > 0 && val)
+ uart->baud = fdt32_to_cpu(*val);
+ else
+ uart->baud = DEFAULT_UART_BAUD;
+
+ val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "reg-shift", &len);
+ if (len > 0 && val)
+ uart->reg_shift = fdt32_to_cpu(*val);
+ else
+ uart->reg_shift = DEFAULT_UART_REG_SHIFT;
+
+ val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "reg-io-width", &len);
+ if (len > 0 && val)
+ uart->reg_io_width = fdt32_to_cpu(*val);
+ else
+ uart->reg_io_width = DEFAULT_UART_REG_IO_WIDTH;
+
+ return 0;
+}
+
+int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
+ const char *compatible)
+{
+ int nodeoffset;
+
+ if (!compatible || !uart || !fdt)
+ return SBI_ENODEV;
+
+ nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compatible);
+ if (nodeoffset < 0)
+ return nodeoffset;
+
+ return fdt_parse_uart8250_node(fdt, nodeoffset, uart);
+}
+
+int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic)
+{
+ int len, rc;
+ const fdt32_t *val;
+ unsigned long reg_addr, reg_size;
+
+ if (nodeoffset < 0 || !plic || !fdt)
+ return SBI_ENODEV;
+
+ rc = fdt_get_node_addr_size(fdt, nodeoffset, &reg_addr, &reg_size);
+ if (rc < 0 || !reg_addr || !reg_size)
+ return SBI_ENODEV;
+ plic->addr = reg_addr;
+
+ val = fdt_getprop(fdt, nodeoffset, "riscv,ndev", &len);
+ if (len > 0)
+ plic->num_src = fdt32_to_cpu(*val);
+
+ return 0;
+}
+
+int fdt_parse_plic(void *fdt, struct plic_data *plic, const char *compat)
+{
+ int nodeoffset;
+
+ if (!compat || !plic || !fdt)
+ return SBI_ENODEV;
+
+ nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compat);
+ if (nodeoffset < 0)
+ return nodeoffset;
+
+ return fdt_parse_plic_node(fdt, nodeoffset, plic);
+}
+
+int fdt_parse_clint_node(void *fdt, int nodeoffset, bool for_timer,
+ struct clint_data *clint)
+{
+ const fdt32_t *val;
+ unsigned long reg_addr, reg_size;
+ int i, rc, count, cpu_offset, cpu_intc_offset;
+ u32 phandle, hwirq, hartid, first_hartid, last_hartid;
+ u32 match_hwirq = (for_timer) ? IRQ_M_TIMER : IRQ_M_SOFT;
+
+ if (nodeoffset < 0 || !clint || !fdt)
+ return SBI_ENODEV;
+
+ rc = fdt_get_node_addr_size(fdt, nodeoffset, &reg_addr, &reg_size);
+ if (rc < 0 || !reg_addr || !reg_size)
+ return SBI_ENODEV;
+ clint->addr = reg_addr;
+
+ val = fdt_getprop(fdt, nodeoffset, "interrupts-extended", &count);
+ if (!val || count < sizeof(fdt32_t))
+ return SBI_EINVAL;
+ count = count / sizeof(fdt32_t);
+
+ first_hartid = -1U;
+ last_hartid = 0;
+ clint->hart_count = 0;
+ for (i = 0; i < count; i += 2) {
+ phandle = fdt32_to_cpu(val[i]);
+ hwirq = fdt32_to_cpu(val[i + 1]);
+
+ cpu_intc_offset = fdt_node_offset_by_phandle(fdt, phandle);
+ if (cpu_intc_offset < 0)
+ continue;
+
+ cpu_offset = fdt_parent_offset(fdt, cpu_intc_offset);
+ if (cpu_intc_offset < 0)
+ continue;
+
+ rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
+ if (rc)
+ continue;
+
+ if (SBI_HARTMASK_MAX_BITS <= hartid)
+ continue;
+
+ if (match_hwirq == hwirq) {
+ if (hartid < first_hartid)
+ first_hartid = hartid;
+ if (hartid > last_hartid)
+ last_hartid = hartid;
+ clint->hart_count++;
+ }
+ }
+
+ if ((last_hartid < first_hartid) || first_hartid == -1U)
+ return SBI_ENODEV;
+
+ clint->first_hartid = first_hartid;
+ count = last_hartid - first_hartid + 1;
+ if (clint->hart_count < count)
+ clint->hart_count = count;
+
+ /* TODO: We should figure-out CLINT has_64bit_mmio from DT node */
+ clint->has_64bit_mmio = TRUE;
+
+ return 0;
+}
+
+int fdt_parse_compat_addr(void *fdt, unsigned long *addr,
+ const char *compatible)
+{
+ int nodeoffset, rc;
+
+ nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compatible);
+ if (nodeoffset < 0)
+ return nodeoffset;
+
+ rc = fdt_get_node_addr_size(fdt, nodeoffset, addr, NULL);
+ if (rc < 0 || !addr)
+ return SBI_ENODEV;
+
+ return 0;
+}
diff --git a/roms/opensbi/lib/utils/fdt/objects.mk b/roms/opensbi/lib/utils/fdt/objects.mk
new file mode 100644
index 000000000..d9f1eae19
--- /dev/null
+++ b/roms/opensbi/lib/utils/fdt/objects.mk
@@ -0,0 +1,9 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# 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
diff --git a/roms/opensbi/lib/utils/ipi/fdt_ipi.c b/roms/opensbi/lib/utils/ipi/fdt_ipi.c
new file mode 100644
index 000000000..6562469da
--- /dev/null
+++ b/roms/opensbi/lib/utils/ipi/fdt_ipi.c
@@ -0,0 +1,101 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/sbi_scratch.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/ipi/fdt_ipi.h>
+
+extern struct fdt_ipi fdt_ipi_clint;
+
+static struct fdt_ipi *ipi_drivers[] = {
+ &fdt_ipi_clint
+};
+
+static void dummy_send(u32 target_hart)
+{
+}
+
+static void dummy_clear(u32 target_hart)
+{
+}
+
+static struct fdt_ipi dummy = {
+ .match_table = NULL,
+ .cold_init = NULL,
+ .warm_init = NULL,
+ .exit = NULL,
+ .send = dummy_send,
+ .clear = dummy_clear
+};
+
+static struct fdt_ipi *current_driver = &dummy;
+
+void fdt_ipi_send(u32 target_hart)
+{
+ current_driver->send(target_hart);
+}
+
+void fdt_ipi_clear(u32 target_hart)
+{
+ current_driver->clear(target_hart);
+}
+
+void fdt_ipi_exit(void)
+{
+ if (current_driver->exit)
+ current_driver->exit();
+}
+
+static int fdt_ipi_warm_init(void)
+{
+ if (current_driver->warm_init)
+ return current_driver->warm_init();
+ return 0;
+}
+
+static int fdt_ipi_cold_init(void)
+{
+ int pos, noff, rc;
+ struct fdt_ipi *drv;
+ const struct fdt_match *match;
+ void *fdt = sbi_scratch_thishart_arg1_ptr();
+
+ for (pos = 0; pos < array_size(ipi_drivers); pos++) {
+ drv = ipi_drivers[pos];
+
+ noff = -1;
+ while ((noff = fdt_find_match(fdt, noff,
+ drv->match_table, &match)) >= 0) {
+ if (drv->cold_init) {
+ rc = drv->cold_init(fdt, noff, match);
+ if (rc)
+ return rc;
+ }
+ current_driver = drv;
+ }
+
+ if (current_driver != &dummy)
+ break;
+ }
+
+ return 0;
+}
+
+int fdt_ipi_init(bool cold_boot)
+{
+ int rc;
+
+ if (cold_boot) {
+ rc = fdt_ipi_cold_init();
+ if (rc)
+ return rc;
+ }
+
+ return fdt_ipi_warm_init();
+}
diff --git a/roms/opensbi/lib/utils/ipi/fdt_ipi_clint.c b/roms/opensbi/lib/utils/ipi/fdt_ipi_clint.c
new file mode 100644
index 000000000..e99244064
--- /dev/null
+++ b/roms/opensbi/lib/utils/ipi/fdt_ipi_clint.c
@@ -0,0 +1,49 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/sbi_error.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/ipi/fdt_ipi.h>
+#include <sbi_utils/sys/clint.h>
+
+#define CLINT_IPI_MAX_NR 16
+
+static unsigned long clint_ipi_count = 0;
+static struct clint_data clint_ipi[CLINT_IPI_MAX_NR];
+
+static int ipi_clint_cold_init(void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ int rc;
+ struct clint_data *ci;
+
+ if (CLINT_IPI_MAX_NR <= clint_ipi_count)
+ return SBI_ENOSPC;
+ ci = &clint_ipi[clint_ipi_count++];
+
+ rc = fdt_parse_clint_node(fdt, nodeoff, FALSE, ci);
+ if (rc)
+ return rc;
+
+ return clint_cold_ipi_init(ci);
+}
+
+static const struct fdt_match ipi_clint_match[] = {
+ { .compatible = "riscv,clint0" },
+ { },
+};
+
+struct fdt_ipi fdt_ipi_clint = {
+ .match_table = ipi_clint_match,
+ .cold_init = ipi_clint_cold_init,
+ .warm_init = clint_warm_ipi_init,
+ .exit = NULL,
+ .send = clint_ipi_send,
+ .clear = clint_ipi_clear,
+};
diff --git a/roms/opensbi/lib/utils/ipi/objects.mk b/roms/opensbi/lib/utils/ipi/objects.mk
new file mode 100644
index 000000000..00719579d
--- /dev/null
+++ b/roms/opensbi/lib/utils/ipi/objects.mk
@@ -0,0 +1,11 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2020 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+
+libsbiutils-objs-y += ipi/fdt_ipi.o
+libsbiutils-objs-y += ipi/fdt_ipi_clint.o
diff --git a/roms/opensbi/lib/utils/irqchip/fdt_irqchip.c b/roms/opensbi/lib/utils/irqchip/fdt_irqchip.c
new file mode 100644
index 000000000..3630be657
--- /dev/null
+++ b/roms/opensbi/lib/utils/irqchip/fdt_irqchip.c
@@ -0,0 +1,74 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/sbi_scratch.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/irqchip/fdt_irqchip.h>
+
+extern struct fdt_irqchip fdt_irqchip_plic;
+
+static struct fdt_irqchip *irqchip_drivers[] = {
+ &fdt_irqchip_plic
+};
+
+static struct fdt_irqchip *current_driver = NULL;
+
+void fdt_irqchip_exit(void)
+{
+ if (current_driver && current_driver->exit)
+ current_driver->exit();
+}
+
+static int fdt_irqchip_warm_init(void)
+{
+ if (current_driver && current_driver->warm_init)
+ return current_driver->warm_init();
+ return 0;
+}
+
+static int fdt_irqchip_cold_init(void)
+{
+ int pos, noff, rc;
+ struct fdt_irqchip *drv;
+ const struct fdt_match *match;
+ void *fdt = sbi_scratch_thishart_arg1_ptr();
+
+ for (pos = 0; pos < array_size(irqchip_drivers); pos++) {
+ drv = irqchip_drivers[pos];
+
+ noff = -1;
+ while ((noff = fdt_find_match(fdt, noff,
+ drv->match_table, &match)) >= 0) {
+ if (drv->cold_init) {
+ rc = drv->cold_init(fdt, noff, match);
+ if (rc)
+ return rc;
+ }
+ current_driver = drv;
+ }
+
+ if (current_driver)
+ break;
+ }
+
+ return 0;
+}
+
+int fdt_irqchip_init(bool cold_boot)
+{
+ int rc;
+
+ if (cold_boot) {
+ rc = fdt_irqchip_cold_init();
+ if (rc)
+ return rc;
+ }
+
+ return fdt_irqchip_warm_init();
+}
diff --git a/roms/opensbi/lib/utils/irqchip/fdt_irqchip_plic.c b/roms/opensbi/lib/utils/irqchip/fdt_irqchip_plic.c
new file mode 100644
index 000000000..18d2797c9
--- /dev/null
+++ b/roms/opensbi/lib/utils/irqchip/fdt_irqchip_plic.c
@@ -0,0 +1,120 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <libfdt.h>
+#include <sbi/riscv_asm.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_hartmask.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/irqchip/fdt_irqchip.h>
+#include <sbi_utils/irqchip/plic.h>
+
+#define PLIC_MAX_NR 16
+
+static unsigned long plic_count = 0;
+static struct plic_data plic[PLIC_MAX_NR];
+
+static struct plic_data *plic_hartid2data[SBI_HARTMASK_MAX_BITS];
+static int plic_hartid2context[SBI_HARTMASK_MAX_BITS][2];
+
+static int irqchip_plic_warm_init(void)
+{
+ u32 hartid = current_hartid();
+
+ return plic_warm_irqchip_init(plic_hartid2data[hartid],
+ plic_hartid2context[hartid][0],
+ plic_hartid2context[hartid][1]);
+}
+
+static int irqchip_plic_update_hartid_table(void *fdt, int nodeoff,
+ struct plic_data *pd)
+{
+ const fdt32_t *val;
+ u32 phandle, hwirq, hartid;
+ int i, err, count, cpu_offset, cpu_intc_offset;
+
+ val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &count);
+ if (!val || count < sizeof(fdt32_t))
+ return SBI_EINVAL;
+ count = count / sizeof(fdt32_t);
+
+ for (i = 0; i < count; i += 2) {
+ phandle = fdt32_to_cpu(val[i]);
+ hwirq = fdt32_to_cpu(val[i + 1]);
+
+ cpu_intc_offset = fdt_node_offset_by_phandle(fdt, phandle);
+ if (cpu_intc_offset < 0)
+ continue;
+
+ cpu_offset = fdt_parent_offset(fdt, cpu_intc_offset);
+ if (cpu_intc_offset < 0)
+ continue;
+
+ err = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
+ if (err)
+ continue;
+
+ if (SBI_HARTMASK_MAX_BITS <= hartid)
+ continue;
+
+ plic_hartid2data[hartid] = pd;
+ switch (hwirq) {
+ case IRQ_M_EXT:
+ plic_hartid2context[hartid][0] = i / 2;
+ break;
+ case IRQ_S_EXT:
+ plic_hartid2context[hartid][1] = i / 2;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int irqchip_plic_cold_init(void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ int i, rc;
+ struct plic_data *pd;
+
+ if (PLIC_MAX_NR <= plic_count)
+ return SBI_ENOSPC;
+ pd = &plic[plic_count++];
+
+ rc = fdt_parse_plic_node(fdt, nodeoff, pd);
+ if (rc)
+ return rc;
+
+ rc = plic_cold_irqchip_init(pd);
+ if (rc)
+ return rc;
+
+ if (plic_count == 1) {
+ for (i = 0; i < SBI_HARTMASK_MAX_BITS; i++) {
+ plic_hartid2data[i] = NULL;
+ plic_hartid2context[i][0] = -1;
+ plic_hartid2context[i][1] = -1;
+ }
+ }
+
+ return irqchip_plic_update_hartid_table(fdt, nodeoff, pd);
+}
+
+static const struct fdt_match irqchip_plic_match[] = {
+ { .compatible = "riscv,plic0" },
+ { .compatible = "sifive,plic-1.0.0" },
+ { },
+};
+
+struct fdt_irqchip fdt_irqchip_plic = {
+ .match_table = irqchip_plic_match,
+ .cold_init = irqchip_plic_cold_init,
+ .warm_init = irqchip_plic_warm_init,
+ .exit = NULL,
+};
diff --git a/roms/opensbi/lib/utils/irqchip/objects.mk b/roms/opensbi/lib/utils/irqchip/objects.mk
new file mode 100644
index 000000000..934f706b6
--- /dev/null
+++ b/roms/opensbi/lib/utils/irqchip/objects.mk
@@ -0,0 +1,12 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2019 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+
+libsbiutils-objs-y += irqchip/fdt_irqchip.o
+libsbiutils-objs-y += irqchip/fdt_irqchip_plic.o
+libsbiutils-objs-y += irqchip/plic.o
diff --git a/roms/opensbi/lib/utils/irqchip/plic.c b/roms/opensbi/lib/utils/irqchip/plic.c
new file mode 100644
index 000000000..7665c62ee
--- /dev/null
+++ b/roms/opensbi/lib/utils/irqchip/plic.c
@@ -0,0 +1,100 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/riscv_io.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_string.h>
+#include <sbi_utils/irqchip/plic.h>
+
+#define PLIC_PRIORITY_BASE 0x0
+#define PLIC_PENDING_BASE 0x1000
+#define PLIC_ENABLE_BASE 0x2000
+#define PLIC_ENABLE_STRIDE 0x80
+#define PLIC_CONTEXT_BASE 0x200000
+#define PLIC_CONTEXT_STRIDE 0x1000
+
+static void plic_set_priority(struct plic_data *plic, u32 source, u32 val)
+{
+ volatile void *plic_priority = (void *)plic->addr +
+ PLIC_PRIORITY_BASE + 4 * source;
+ writel(val, plic_priority);
+}
+
+void plic_set_thresh(struct plic_data *plic, u32 cntxid, u32 val)
+{
+ volatile void *plic_thresh;
+
+ if (!plic)
+ return;
+
+ plic_thresh = (void *)plic->addr +
+ PLIC_CONTEXT_BASE + PLIC_CONTEXT_STRIDE * cntxid;
+ writel(val, plic_thresh);
+}
+
+void plic_set_ie(struct plic_data *plic, u32 cntxid, u32 word_index, u32 val)
+{
+ volatile void *plic_ie;
+
+ if (!plic)
+ return;
+
+ plic_ie = (void *)plic->addr +
+ PLIC_ENABLE_BASE + PLIC_ENABLE_STRIDE * cntxid;
+ writel(val, plic_ie + word_index * 4);
+}
+
+int plic_warm_irqchip_init(struct plic_data *plic,
+ int m_cntx_id, int s_cntx_id)
+{
+ size_t i, ie_words;
+
+ if (!plic)
+ return SBI_EINVAL;
+
+ ie_words = plic->num_src / 32 + 1;
+
+ /* By default, disable all IRQs for M-mode of target HART */
+ if (m_cntx_id > -1) {
+ for (i = 0; i < ie_words; i++)
+ plic_set_ie(plic, m_cntx_id, i, 0);
+ }
+
+ /* By default, disable all IRQs for S-mode of target HART */
+ if (s_cntx_id > -1) {
+ for (i = 0; i < ie_words; i++)
+ plic_set_ie(plic, s_cntx_id, i, 0);
+ }
+
+ /* By default, disable M-mode threshold */
+ if (m_cntx_id > -1)
+ plic_set_thresh(plic, m_cntx_id, 0x7);
+
+ /* By default, disable S-mode threshold */
+ if (s_cntx_id > -1)
+ plic_set_thresh(plic, s_cntx_id, 0x7);
+
+ return 0;
+}
+
+int plic_cold_irqchip_init(struct plic_data *plic)
+{
+ int i;
+
+ if (!plic)
+ return SBI_EINVAL;
+
+ /* Configure default priorities of all IRQs */
+ for (i = 1; i <= plic->num_src; i++)
+ plic_set_priority(plic, i, 0);
+
+ return 0;
+}
diff --git a/roms/opensbi/lib/utils/libfdt/.clang-format b/roms/opensbi/lib/utils/libfdt/.clang-format
new file mode 100644
index 000000000..e3845288a
--- /dev/null
+++ b/roms/opensbi/lib/utils/libfdt/.clang-format
@@ -0,0 +1 @@
+DisableFormat: true
diff --git a/roms/opensbi/lib/utils/libfdt/Makefile.libfdt b/roms/opensbi/lib/utils/libfdt/Makefile.libfdt
new file mode 100644
index 000000000..b6d8fc02d
--- /dev/null
+++ b/roms/opensbi/lib/utils/libfdt/Makefile.libfdt
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+# Makefile.libfdt
+#
+# This is not a complete Makefile of itself. Instead, it is designed to
+# be easily embeddable into other systems of Makefiles.
+#
+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_check.c
+LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
+LIBFDT_LIB = libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT)
+
+libfdt_clean:
+ @$(VECHO) CLEAN "(libfdt)"
+ rm -f $(STD_CLEANFILES:%=$(LIBFDT_dir)/%)
+ rm -f $(LIBFDT_dir)/$(LIBFDT_soname)
diff --git a/roms/opensbi/lib/utils/libfdt/TODO b/roms/opensbi/lib/utils/libfdt/TODO
new file mode 100644
index 000000000..288437e39
--- /dev/null
+++ b/roms/opensbi/lib/utils/libfdt/TODO
@@ -0,0 +1,3 @@
+- Tree traversal functions
+- Graft function
+- Complete libfdt.h documenting comments
diff --git a/roms/opensbi/lib/utils/libfdt/fdt.c b/roms/opensbi/lib/utils/libfdt/fdt.c
new file mode 100644
index 000000000..c28fcc115
--- /dev/null
+++ b/roms/opensbi/lib/utils/libfdt/fdt.c
@@ -0,0 +1,316 @@
+// 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"
+
+/*
+ * Minimal sanity check for a read-only tree. fdt_ro_probe_() checks
+ * that the given buffer contains what appears to be a flattened
+ * device tree with sane information in its header.
+ */
+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 (!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 (!can_assume(VALID_INPUT) && fdt_size_dt_struct(fdt) == 0)
+ return -FDT_ERR_BADSTATE;
+ } else {
+ return -FDT_ERR_BADMAGIC;
+ }
+
+ if (totalsize < INT32_MAX)
+ return totalsize;
+ else
+ return -FDT_ERR_TRUNCATED;
+}
+
+static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off)
+{
+ return (off >= hdrsize) && (off <= totalsize);
+}
+
+static int check_block_(uint32_t hdrsize, uint32_t totalsize,
+ uint32_t base, uint32_t size)
+{
+ if (!check_off_(hdrsize, totalsize, base))
+ return 0; /* block start out of bounds */
+ if ((base + size) < base)
+ return 0; /* overflow */
+ if (!check_off_(hdrsize, totalsize, base + size))
+ return 0; /* block end out of bounds */
+ return 1;
+}
+
+size_t fdt_header_size_(uint32_t version)
+{
+ if (version <= 1)
+ return FDT_V1_SIZE;
+ else if (version <= 2)
+ return FDT_V2_SIZE;
+ else if (version <= 3)
+ return FDT_V3_SIZE;
+ else if (version <= 16)
+ return FDT_V16_SIZE;
+ else
+ 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 (!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;
+ }
+
+ 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;
+}
+
+const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
+{
+ unsigned absoffset = offset + fdt_off_dt_struct(fdt);
+
+ if (!can_assume(VALID_INPUT))
+ if ((absoffset < offset)
+ || ((absoffset + len) < absoffset)
+ || (absoffset + len) > fdt_totalsize(fdt))
+ return NULL;
+
+ if (can_assume(LATEST) || fdt_version(fdt) >= 0x11)
+ if (((offset + len) < offset)
+ || ((offset + len) > fdt_size_dt_struct(fdt)))
+ return NULL;
+
+ return fdt_offset_ptr_(fdt, offset);
+}
+
+uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
+{
+ const fdt32_t *tagp, *lenp;
+ uint32_t tag;
+ int offset = startoffset;
+ const char *p;
+
+ *nextoffset = -FDT_ERR_TRUNCATED;
+ tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
+ if (!can_assume(VALID_DTB) && !tagp)
+ return FDT_END; /* premature end */
+ tag = fdt32_to_cpu(*tagp);
+ offset += FDT_TAGSIZE;
+
+ *nextoffset = -FDT_ERR_BADSTRUCTURE;
+ switch (tag) {
+ case FDT_BEGIN_NODE:
+ /* skip name */
+ do {
+ p = fdt_offset_ptr(fdt, offset++, 1);
+ } while (p && (*p != '\0'));
+ if (!can_assume(VALID_DTB) && !p)
+ return FDT_END; /* premature end */
+ break;
+
+ case FDT_PROP:
+ lenp = fdt_offset_ptr(fdt, offset, sizeof(*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 (!can_assume(LATEST) &&
+ fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
+ ((offset - fdt32_to_cpu(*lenp)) % 8) != 0)
+ offset += 4;
+ break;
+
+ case FDT_END:
+ case FDT_END_NODE:
+ case FDT_NOP:
+ break;
+
+ default:
+ return FDT_END;
+ }
+
+ if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
+ return FDT_END; /* premature end */
+
+ *nextoffset = FDT_TAGALIGN(offset);
+ return tag;
+}
+
+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;
+
+ return offset;
+}
+
+int fdt_check_prop_offset_(const void *fdt, int offset)
+{
+ if ((offset < 0) || (offset % FDT_TAGSIZE)
+ || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
+ return -FDT_ERR_BADOFFSET;
+
+ return offset;
+}
+
+int fdt_next_node(const void *fdt, int offset, int *depth)
+{
+ int nextoffset = 0;
+ uint32_t tag;
+
+ if (offset >= 0)
+ if ((nextoffset = fdt_check_node_offset_(fdt, offset)) < 0)
+ return nextoffset;
+
+ do {
+ offset = nextoffset;
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+ switch (tag) {
+ case FDT_PROP:
+ case FDT_NOP:
+ break;
+
+ case FDT_BEGIN_NODE:
+ if (depth)
+ (*depth)++;
+ break;
+
+ case FDT_END_NODE:
+ if (depth && ((--(*depth)) < 0))
+ return nextoffset;
+ break;
+
+ case FDT_END:
+ if ((nextoffset >= 0)
+ || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth))
+ return -FDT_ERR_NOTFOUND;
+ else
+ return nextoffset;
+ }
+ } while (tag != FDT_BEGIN_NODE);
+
+ return offset;
+}
+
+int fdt_first_subnode(const void *fdt, int offset)
+{
+ int depth = 0;
+
+ offset = fdt_next_node(fdt, offset, &depth);
+ if (offset < 0 || depth != 1)
+ return -FDT_ERR_NOTFOUND;
+
+ return offset;
+}
+
+int fdt_next_subnode(const void *fdt, int offset)
+{
+ int depth = 1;
+
+ /*
+ * With respect to the parent, the depth of the next subnode will be
+ * the same as the last.
+ */
+ do {
+ offset = fdt_next_node(fdt, offset, &depth);
+ if (offset < 0 || depth < 1)
+ return -FDT_ERR_NOTFOUND;
+ } while (depth > 1);
+
+ return offset;
+}
+
+const char *fdt_find_string_(const char *strtab, int tabsize, const char *s)
+{
+ int len = strlen(s) + 1;
+ const char *last = strtab + tabsize - len;
+ const char *p;
+
+ for (p = strtab; p <= last; p++)
+ if (memcmp(p, s, len) == 0)
+ return p;
+ return NULL;
+}
+
+int fdt_move(const void *fdt, void *buf, int bufsize)
+{
+ FDT_RO_PROBE(fdt);
+
+ if (fdt_totalsize(fdt) > bufsize)
+ return -FDT_ERR_NOSPACE;
+
+ memmove(buf, fdt, fdt_totalsize(fdt));
+ return 0;
+}
diff --git a/roms/opensbi/lib/utils/libfdt/fdt.h b/roms/opensbi/lib/utils/libfdt/fdt.h
new file mode 100644
index 000000000..f2e68807f
--- /dev/null
+++ b/roms/opensbi/lib/utils/libfdt/fdt.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
+#ifndef FDT_H
+#define FDT_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ * Copyright 2012 Kim Phillips, Freescale Semiconductor.
+ */
+
+#ifndef __ASSEMBLY__
+
+struct fdt_header {
+ fdt32_t magic; /* magic word FDT_MAGIC */
+ fdt32_t totalsize; /* total size of DT block */
+ fdt32_t off_dt_struct; /* offset to structure */
+ fdt32_t off_dt_strings; /* offset to strings */
+ fdt32_t off_mem_rsvmap; /* offset to memory reserve map */
+ fdt32_t version; /* format version */
+ fdt32_t last_comp_version; /* last compatible version */
+
+ /* version 2 fields below */
+ fdt32_t boot_cpuid_phys; /* Which physical CPU id we're
+ booting on */
+ /* version 3 fields below */
+ fdt32_t size_dt_strings; /* size of the strings block */
+
+ /* version 17 fields below */
+ fdt32_t size_dt_struct; /* size of the structure block */
+};
+
+struct fdt_reserve_entry {
+ fdt64_t address;
+ fdt64_t size;
+};
+
+struct fdt_node_header {
+ fdt32_t tag;
+ char name[0];
+};
+
+struct fdt_property {
+ fdt32_t tag;
+ fdt32_t len;
+ fdt32_t nameoff;
+ char data[0];
+};
+
+#endif /* !__ASSEMBLY */
+
+#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
+#define FDT_TAGSIZE sizeof(fdt32_t)
+
+#define FDT_BEGIN_NODE 0x1 /* Start node: full name */
+#define FDT_END_NODE 0x2 /* End node */
+#define FDT_PROP 0x3 /* Property: name off,
+ size, content */
+#define FDT_NOP 0x4 /* nop */
+#define FDT_END 0x9
+
+#define FDT_V1_SIZE (7*sizeof(fdt32_t))
+#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t))
+#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t))
+#define FDT_V16_SIZE FDT_V3_SIZE
+#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t))
+
+#endif /* FDT_H */
diff --git a/roms/opensbi/lib/utils/libfdt/fdt_addresses.c b/roms/opensbi/lib/utils/libfdt/fdt_addresses.c
new file mode 100644
index 000000000..9a82cd0ba
--- /dev/null
+++ b/roms/opensbi/lib/utils/libfdt/fdt_addresses.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
+ * Copyright (C) 2018 embedded brains GmbH
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int fdt_cells(const void *fdt, int nodeoffset, const char *name)
+{
+ const fdt32_t *c;
+ uint32_t val;
+ int len;
+
+ c = fdt_getprop(fdt, nodeoffset, name, &len);
+ if (!c)
+ return len;
+
+ if (len != sizeof(*c))
+ return -FDT_ERR_BADNCELLS;
+
+ val = fdt32_to_cpu(*c);
+ if (val > FDT_MAX_NCELLS)
+ return -FDT_ERR_BADNCELLS;
+
+ return (int)val;
+}
+
+int fdt_address_cells(const void *fdt, int nodeoffset)
+{
+ int val;
+
+ val = fdt_cells(fdt, nodeoffset, "#address-cells");
+ if (val == 0)
+ return -FDT_ERR_BADNCELLS;
+ if (val == -FDT_ERR_NOTFOUND)
+ return 2;
+ return val;
+}
+
+int fdt_size_cells(const void *fdt, int nodeoffset)
+{
+ int val;
+
+ val = fdt_cells(fdt, nodeoffset, "#size-cells");
+ if (val == -FDT_ERR_NOTFOUND)
+ return 1;
+ return val;
+}
+
+/* This function assumes that [address|size]_cells is 1 or 2 */
+int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
+ const char *name, uint64_t addr, uint64_t size)
+{
+ int addr_cells, size_cells, ret;
+ uint8_t data[sizeof(fdt64_t) * 2], *prop;
+
+ ret = fdt_address_cells(fdt, parent);
+ if (ret < 0)
+ return ret;
+ addr_cells = ret;
+
+ ret = fdt_size_cells(fdt, parent);
+ if (ret < 0)
+ return ret;
+ size_cells = ret;
+
+ /* check validity of address */
+ prop = data;
+ if (addr_cells == 1) {
+ if ((addr > UINT32_MAX) || ((UINT32_MAX + 1 - addr) < size))
+ return -FDT_ERR_BADVALUE;
+
+ fdt32_st(prop, (uint32_t)addr);
+ } else if (addr_cells == 2) {
+ fdt64_st(prop, addr);
+ } else {
+ return -FDT_ERR_BADNCELLS;
+ }
+
+ /* check validity of size */
+ prop += addr_cells * sizeof(fdt32_t);
+ if (size_cells == 1) {
+ if (size > UINT32_MAX)
+ return -FDT_ERR_BADVALUE;
+
+ fdt32_st(prop, (uint32_t)size);
+ } else if (size_cells == 2) {
+ fdt64_st(prop, size);
+ } else {
+ return -FDT_ERR_BADNCELLS;
+ }
+
+ return fdt_appendprop(fdt, nodeoffset, name, data,
+ (addr_cells + size_cells) * sizeof(fdt32_t));
+}
diff --git a/roms/opensbi/lib/utils/libfdt/fdt_check.c b/roms/opensbi/lib/utils/libfdt/fdt_check.c
new file mode 100644
index 000000000..7f6a96c6b
--- /dev/null
+++ b/roms/opensbi/lib/utils/libfdt/fdt_check.c
@@ -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;
+ }
+ }
+}
diff --git a/roms/opensbi/lib/utils/libfdt/fdt_empty_tree.c b/roms/opensbi/lib/utils/libfdt/fdt_empty_tree.c
new file mode 100644
index 000000000..49d54d44b
--- /dev/null
+++ b/roms/opensbi/lib/utils/libfdt/fdt_empty_tree.c
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2012 David Gibson, IBM Corporation.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+int fdt_create_empty_tree(void *buf, int bufsize)
+{
+ int err;
+
+ err = fdt_create(buf, bufsize);
+ if (err)
+ return err;
+
+ err = fdt_finish_reservemap(buf);
+ if (err)
+ return err;
+
+ err = fdt_begin_node(buf, "");
+ if (err)
+ return err;
+
+ err = fdt_end_node(buf);
+ if (err)
+ return err;
+
+ err = fdt_finish(buf);
+ if (err)
+ return err;
+
+ return fdt_open_into(buf, buf, bufsize);
+}
diff --git a/roms/opensbi/lib/utils/libfdt/fdt_overlay.c b/roms/opensbi/lib/utils/libfdt/fdt_overlay.c
new file mode 100644
index 000000000..b310e49a6
--- /dev/null
+++ b/roms/opensbi/lib/utils/libfdt/fdt_overlay.c
@@ -0,0 +1,881 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2016 Free Electrons
+ * Copyright (C) 2016 NextThing Co.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+/**
+ * overlay_get_target_phandle - retrieves the target phandle of a fragment
+ * @fdto: pointer to the device tree overlay blob
+ * @fragment: node offset of the fragment in the overlay
+ *
+ * overlay_get_target_phandle() retrieves the target phandle of an
+ * overlay fragment when that fragment uses a phandle (target
+ * property) instead of a path (target-path property).
+ *
+ * returns:
+ * the phandle pointed by the target property
+ * 0, if the phandle was not found
+ * -1, if the phandle was malformed
+ */
+static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
+{
+ const fdt32_t *val;
+ int len;
+
+ val = fdt_getprop(fdto, fragment, "target", &len);
+ if (!val)
+ return 0;
+
+ if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1))
+ return (uint32_t)-1;
+
+ return fdt32_to_cpu(*val);
+}
+
+/**
+ * overlay_get_target - retrieves the offset of a fragment's target
+ * @fdt: Base device tree blob
+ * @fdto: Device tree overlay blob
+ * @fragment: node offset of the fragment in the overlay
+ * @pathp: pointer which receives the path of the target (or NULL)
+ *
+ * overlay_get_target() retrieves the target offset in the base
+ * device tree of a fragment, no matter how the actual targeting is
+ * done (through a phandle or a path)
+ *
+ * returns:
+ * the targeted node offset in the base device tree
+ * Negative error code on error
+ */
+static int overlay_get_target(const void *fdt, const void *fdto,
+ int fragment, char const **pathp)
+{
+ uint32_t phandle;
+ const char *path = NULL;
+ int path_len = 0, ret;
+
+ /* Try first to do a phandle based lookup */
+ phandle = overlay_get_target_phandle(fdto, fragment);
+ if (phandle == (uint32_t)-1)
+ return -FDT_ERR_BADPHANDLE;
+
+ /* no phandle, try path */
+ if (!phandle) {
+ /* And then a path based lookup */
+ path = fdt_getprop(fdto, fragment, "target-path", &path_len);
+ if (path)
+ ret = fdt_path_offset(fdt, path);
+ else
+ ret = path_len;
+ } else
+ ret = fdt_node_offset_by_phandle(fdt, phandle);
+
+ /*
+ * If we haven't found either a target or a
+ * target-path property in a node that contains a
+ * __overlay__ subnode (we wouldn't be called
+ * otherwise), consider it a improperly written
+ * overlay
+ */
+ if (ret < 0 && path_len == -FDT_ERR_NOTFOUND)
+ ret = -FDT_ERR_BADOVERLAY;
+
+ /* return on error */
+ if (ret < 0)
+ return ret;
+
+ /* return pointer to path (if available) */
+ if (pathp)
+ *pathp = path ? path : NULL;
+
+ return ret;
+}
+
+/**
+ * overlay_phandle_add_offset - Increases a phandle by an offset
+ * @fdt: Base device tree blob
+ * @node: Device tree overlay blob
+ * @name: Name of the property to modify (phandle or linux,phandle)
+ * @delta: offset to apply
+ *
+ * overlay_phandle_add_offset() increments a node phandle by a given
+ * offset.
+ *
+ * returns:
+ * 0 on success.
+ * Negative error code on error
+ */
+static int overlay_phandle_add_offset(void *fdt, int node,
+ const char *name, uint32_t delta)
+{
+ const fdt32_t *val;
+ uint32_t adj_val;
+ int len;
+
+ val = fdt_getprop(fdt, node, name, &len);
+ if (!val)
+ return len;
+
+ if (len != sizeof(*val))
+ return -FDT_ERR_BADPHANDLE;
+
+ adj_val = fdt32_to_cpu(*val);
+ if ((adj_val + delta) < adj_val)
+ return -FDT_ERR_NOPHANDLES;
+
+ adj_val += delta;
+ if (adj_val == (uint32_t)-1)
+ return -FDT_ERR_NOPHANDLES;
+
+ return fdt_setprop_inplace_u32(fdt, node, name, adj_val);
+}
+
+/**
+ * overlay_adjust_node_phandles - Offsets the phandles of a node
+ * @fdto: Device tree overlay blob
+ * @node: Offset of the node we want to adjust
+ * @delta: Offset to shift the phandles of
+ *
+ * overlay_adjust_node_phandles() adds a constant to all the phandles
+ * of a given node. This is mainly use as part of the overlay
+ * application process, when we want to update all the overlay
+ * phandles to not conflict with the overlays of the base device tree.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int overlay_adjust_node_phandles(void *fdto, int node,
+ uint32_t delta)
+{
+ int child;
+ int ret;
+
+ ret = overlay_phandle_add_offset(fdto, node, "phandle", delta);
+ if (ret && ret != -FDT_ERR_NOTFOUND)
+ return ret;
+
+ ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta);
+ if (ret && ret != -FDT_ERR_NOTFOUND)
+ return ret;
+
+ fdt_for_each_subnode(child, fdto, node) {
+ ret = overlay_adjust_node_phandles(fdto, child, delta);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay
+ * @fdto: Device tree overlay blob
+ * @delta: Offset to shift the phandles of
+ *
+ * overlay_adjust_local_phandles() adds a constant to all the
+ * phandles of an overlay. This is mainly use as part of the overlay
+ * application process, when we want to update all the overlay
+ * phandles to not conflict with the overlays of the base device tree.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int overlay_adjust_local_phandles(void *fdto, uint32_t delta)
+{
+ /*
+ * Start adjusting the phandles from the overlay root
+ */
+ return overlay_adjust_node_phandles(fdto, 0, delta);
+}
+
+/**
+ * overlay_update_local_node_references - Adjust the overlay references
+ * @fdto: Device tree overlay blob
+ * @tree_node: Node offset of the node to operate on
+ * @fixup_node: Node offset of the matching local fixups node
+ * @delta: Offset to shift the phandles of
+ *
+ * overlay_update_local_nodes_references() update the phandles
+ * pointing to a node within the device tree overlay by adding a
+ * constant delta.
+ *
+ * This is mainly used as part of a device tree application process,
+ * where you want the device tree overlays phandles to not conflict
+ * with the ones from the base device tree before merging them.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int overlay_update_local_node_references(void *fdto,
+ int tree_node,
+ int fixup_node,
+ uint32_t delta)
+{
+ int fixup_prop;
+ int fixup_child;
+ int ret;
+
+ fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) {
+ const fdt32_t *fixup_val;
+ const char *tree_val;
+ const char *name;
+ int fixup_len;
+ int tree_len;
+ int i;
+
+ fixup_val = fdt_getprop_by_offset(fdto, fixup_prop,
+ &name, &fixup_len);
+ if (!fixup_val)
+ return fixup_len;
+
+ if (fixup_len % sizeof(uint32_t))
+ return -FDT_ERR_BADOVERLAY;
+
+ tree_val = fdt_getprop(fdto, tree_node, name, &tree_len);
+ if (!tree_val) {
+ if (tree_len == -FDT_ERR_NOTFOUND)
+ return -FDT_ERR_BADOVERLAY;
+
+ return tree_len;
+ }
+
+ for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) {
+ fdt32_t adj_val;
+ uint32_t poffset;
+
+ poffset = fdt32_to_cpu(fixup_val[i]);
+
+ /*
+ * phandles to fixup can be unaligned.
+ *
+ * Use a memcpy for the architectures that do
+ * not support unaligned accesses.
+ */
+ memcpy(&adj_val, tree_val + poffset, sizeof(adj_val));
+
+ adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta);
+
+ ret = fdt_setprop_inplace_namelen_partial(fdto,
+ tree_node,
+ name,
+ strlen(name),
+ poffset,
+ &adj_val,
+ sizeof(adj_val));
+ if (ret == -FDT_ERR_NOSPACE)
+ return -FDT_ERR_BADOVERLAY;
+
+ if (ret)
+ return ret;
+ }
+ }
+
+ fdt_for_each_subnode(fixup_child, fdto, fixup_node) {
+ const char *fixup_child_name = fdt_get_name(fdto, fixup_child,
+ NULL);
+ int tree_child;
+
+ tree_child = fdt_subnode_offset(fdto, tree_node,
+ fixup_child_name);
+ if (tree_child == -FDT_ERR_NOTFOUND)
+ return -FDT_ERR_BADOVERLAY;
+ if (tree_child < 0)
+ return tree_child;
+
+ ret = overlay_update_local_node_references(fdto,
+ tree_child,
+ fixup_child,
+ delta);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * overlay_update_local_references - Adjust the overlay references
+ * @fdto: Device tree overlay blob
+ * @delta: Offset to shift the phandles of
+ *
+ * overlay_update_local_references() update all the phandles pointing
+ * to a node within the device tree overlay by adding a constant
+ * delta to not conflict with the base overlay.
+ *
+ * This is mainly used as part of a device tree application process,
+ * where you want the device tree overlays phandles to not conflict
+ * with the ones from the base device tree before merging them.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int overlay_update_local_references(void *fdto, uint32_t delta)
+{
+ int fixups;
+
+ fixups = fdt_path_offset(fdto, "/__local_fixups__");
+ if (fixups < 0) {
+ /* There's no local phandles to adjust, bail out */
+ if (fixups == -FDT_ERR_NOTFOUND)
+ return 0;
+
+ return fixups;
+ }
+
+ /*
+ * Update our local references from the root of the tree
+ */
+ return overlay_update_local_node_references(fdto, 0, fixups,
+ delta);
+}
+
+/**
+ * overlay_fixup_one_phandle - Set an overlay phandle to the base one
+ * @fdt: Base Device Tree blob
+ * @fdto: Device tree overlay blob
+ * @symbols_off: Node offset of the symbols node in the base device tree
+ * @path: Path to a node holding a phandle in the overlay
+ * @path_len: number of path characters to consider
+ * @name: Name of the property holding the phandle reference in the overlay
+ * @name_len: number of name characters to consider
+ * @poffset: Offset within the overlay property where the phandle is stored
+ * @label: Label of the node referenced by the phandle
+ *
+ * overlay_fixup_one_phandle() resolves an overlay phandle pointing to
+ * a node in the base device tree.
+ *
+ * This is part of the device tree overlay application process, when
+ * you want all the phandles in the overlay to point to the actual
+ * base dt nodes.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int overlay_fixup_one_phandle(void *fdt, void *fdto,
+ int symbols_off,
+ const char *path, uint32_t path_len,
+ const char *name, uint32_t name_len,
+ int poffset, const char *label)
+{
+ const char *symbol_path;
+ uint32_t phandle;
+ fdt32_t phandle_prop;
+ int symbol_off, fixup_off;
+ int prop_len;
+
+ if (symbols_off < 0)
+ return symbols_off;
+
+ symbol_path = fdt_getprop(fdt, symbols_off, label,
+ &prop_len);
+ if (!symbol_path)
+ return prop_len;
+
+ symbol_off = fdt_path_offset(fdt, symbol_path);
+ if (symbol_off < 0)
+ return symbol_off;
+
+ phandle = fdt_get_phandle(fdt, symbol_off);
+ if (!phandle)
+ return -FDT_ERR_NOTFOUND;
+
+ fixup_off = fdt_path_offset_namelen(fdto, path, path_len);
+ if (fixup_off == -FDT_ERR_NOTFOUND)
+ return -FDT_ERR_BADOVERLAY;
+ if (fixup_off < 0)
+ return fixup_off;
+
+ phandle_prop = cpu_to_fdt32(phandle);
+ return fdt_setprop_inplace_namelen_partial(fdto, fixup_off,
+ name, name_len, poffset,
+ &phandle_prop,
+ sizeof(phandle_prop));
+};
+
+/**
+ * overlay_fixup_phandle - Set an overlay phandle to the base one
+ * @fdt: Base Device Tree blob
+ * @fdto: Device tree overlay blob
+ * @symbols_off: Node offset of the symbols node in the base device tree
+ * @property: Property offset in the overlay holding the list of fixups
+ *
+ * overlay_fixup_phandle() resolves all the overlay phandles pointed
+ * to in a __fixups__ property, and updates them to match the phandles
+ * in use in the base device tree.
+ *
+ * This is part of the device tree overlay application process, when
+ * you want all the phandles in the overlay to point to the actual
+ * base dt nodes.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
+ int property)
+{
+ const char *value;
+ const char *label;
+ int len;
+
+ value = fdt_getprop_by_offset(fdto, property,
+ &label, &len);
+ if (!value) {
+ if (len == -FDT_ERR_NOTFOUND)
+ return -FDT_ERR_INTERNAL;
+
+ return len;
+ }
+
+ do {
+ const char *path, *name, *fixup_end;
+ const char *fixup_str = value;
+ uint32_t path_len, name_len;
+ uint32_t fixup_len;
+ char *sep, *endptr;
+ int poffset, ret;
+
+ fixup_end = memchr(value, '\0', len);
+ if (!fixup_end)
+ return -FDT_ERR_BADOVERLAY;
+ fixup_len = fixup_end - fixup_str;
+
+ len -= fixup_len + 1;
+ value += fixup_len + 1;
+
+ path = fixup_str;
+ sep = memchr(fixup_str, ':', fixup_len);
+ if (!sep || *sep != ':')
+ return -FDT_ERR_BADOVERLAY;
+
+ path_len = sep - path;
+ if (path_len == (fixup_len - 1))
+ return -FDT_ERR_BADOVERLAY;
+
+ fixup_len -= path_len + 1;
+ name = sep + 1;
+ sep = memchr(name, ':', fixup_len);
+ if (!sep || *sep != ':')
+ return -FDT_ERR_BADOVERLAY;
+
+ name_len = sep - name;
+ if (!name_len)
+ return -FDT_ERR_BADOVERLAY;
+
+ poffset = strtoul(sep + 1, &endptr, 10);
+ if ((*endptr != '\0') || (endptr <= (sep + 1)))
+ return -FDT_ERR_BADOVERLAY;
+
+ ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off,
+ path, path_len, name, name_len,
+ poffset, label);
+ if (ret)
+ return ret;
+ } while (len > 0);
+
+ return 0;
+}
+
+/**
+ * overlay_fixup_phandles - Resolve the overlay phandles to the base
+ * device tree
+ * @fdt: Base Device Tree blob
+ * @fdto: Device tree overlay blob
+ *
+ * overlay_fixup_phandles() resolves all the overlay phandles pointing
+ * to nodes in the base device tree.
+ *
+ * This is one of the steps of the device tree overlay application
+ * process, when you want all the phandles in the overlay to point to
+ * the actual base dt nodes.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int overlay_fixup_phandles(void *fdt, void *fdto)
+{
+ int fixups_off, symbols_off;
+ int property;
+
+ /* We can have overlays without any fixups */
+ fixups_off = fdt_path_offset(fdto, "/__fixups__");
+ if (fixups_off == -FDT_ERR_NOTFOUND)
+ return 0; /* nothing to do */
+ if (fixups_off < 0)
+ return fixups_off;
+
+ /* And base DTs without symbols */
+ symbols_off = fdt_path_offset(fdt, "/__symbols__");
+ if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND)))
+ return symbols_off;
+
+ fdt_for_each_property_offset(property, fdto, fixups_off) {
+ int ret;
+
+ ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * overlay_apply_node - Merges a node into the base device tree
+ * @fdt: Base Device Tree blob
+ * @target: Node offset in the base device tree to apply the fragment to
+ * @fdto: Device tree overlay blob
+ * @node: Node offset in the overlay holding the changes to merge
+ *
+ * overlay_apply_node() merges a node into a target base device tree
+ * node pointed.
+ *
+ * This is part of the final step in the device tree overlay
+ * application process, when all the phandles have been adjusted and
+ * resolved and you just have to merge overlay into the base device
+ * tree.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int overlay_apply_node(void *fdt, int target,
+ void *fdto, int node)
+{
+ int property;
+ int subnode;
+
+ fdt_for_each_property_offset(property, fdto, node) {
+ const char *name;
+ const void *prop;
+ int prop_len;
+ int ret;
+
+ prop = fdt_getprop_by_offset(fdto, property, &name,
+ &prop_len);
+ if (prop_len == -FDT_ERR_NOTFOUND)
+ return -FDT_ERR_INTERNAL;
+ if (prop_len < 0)
+ return prop_len;
+
+ ret = fdt_setprop(fdt, target, name, prop, prop_len);
+ if (ret)
+ return ret;
+ }
+
+ fdt_for_each_subnode(subnode, fdto, node) {
+ const char *name = fdt_get_name(fdto, subnode, NULL);
+ int nnode;
+ int ret;
+
+ nnode = fdt_add_subnode(fdt, target, name);
+ if (nnode == -FDT_ERR_EXISTS) {
+ nnode = fdt_subnode_offset(fdt, target, name);
+ if (nnode == -FDT_ERR_NOTFOUND)
+ return -FDT_ERR_INTERNAL;
+ }
+
+ if (nnode < 0)
+ return nnode;
+
+ ret = overlay_apply_node(fdt, nnode, fdto, subnode);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * overlay_merge - Merge an overlay into its base device tree
+ * @fdt: Base Device Tree blob
+ * @fdto: Device tree overlay blob
+ *
+ * overlay_merge() merges an overlay into its base device tree.
+ *
+ * This is the next to last step in the device tree overlay application
+ * process, when all the phandles have been adjusted and resolved and
+ * you just have to merge overlay into the base device tree.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int overlay_merge(void *fdt, void *fdto)
+{
+ int fragment;
+
+ fdt_for_each_subnode(fragment, fdto, 0) {
+ int overlay;
+ int target;
+ int ret;
+
+ /*
+ * Each fragments will have an __overlay__ node. If
+ * they don't, it's not supposed to be merged
+ */
+ overlay = fdt_subnode_offset(fdto, fragment, "__overlay__");
+ if (overlay == -FDT_ERR_NOTFOUND)
+ continue;
+
+ if (overlay < 0)
+ return overlay;
+
+ target = overlay_get_target(fdt, fdto, fragment, NULL);
+ if (target < 0)
+ return target;
+
+ ret = overlay_apply_node(fdt, target, fdto, overlay);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int get_path_len(const void *fdt, int nodeoffset)
+{
+ int len = 0, namelen;
+ const char *name;
+
+ FDT_RO_PROBE(fdt);
+
+ for (;;) {
+ name = fdt_get_name(fdt, nodeoffset, &namelen);
+ if (!name)
+ return namelen;
+
+ /* root? we're done */
+ if (namelen == 0)
+ break;
+
+ nodeoffset = fdt_parent_offset(fdt, nodeoffset);
+ if (nodeoffset < 0)
+ return nodeoffset;
+ len += namelen + 1;
+ }
+
+ /* in case of root pretend it's "/" */
+ if (len == 0)
+ len++;
+ return len;
+}
+
+/**
+ * overlay_symbol_update - Update the symbols of base tree after a merge
+ * @fdt: Base Device Tree blob
+ * @fdto: Device tree overlay blob
+ *
+ * overlay_symbol_update() updates the symbols of the base tree with the
+ * symbols of the applied overlay
+ *
+ * This is the last step in the device tree overlay application
+ * process, allowing the reference of overlay symbols by subsequent
+ * overlay operations.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int overlay_symbol_update(void *fdt, void *fdto)
+{
+ int root_sym, ov_sym, prop, path_len, fragment, target;
+ int len, frag_name_len, ret, rel_path_len;
+ const char *s, *e;
+ const char *path;
+ const char *name;
+ const char *frag_name;
+ const char *rel_path;
+ const char *target_path;
+ char *buf;
+ void *p;
+
+ ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__");
+
+ /* if no overlay symbols exist no problem */
+ if (ov_sym < 0)
+ return 0;
+
+ root_sym = fdt_subnode_offset(fdt, 0, "__symbols__");
+
+ /* it no root symbols exist we should create them */
+ if (root_sym == -FDT_ERR_NOTFOUND)
+ root_sym = fdt_add_subnode(fdt, 0, "__symbols__");
+
+ /* any error is fatal now */
+ if (root_sym < 0)
+ return root_sym;
+
+ /* iterate over each overlay symbol */
+ fdt_for_each_property_offset(prop, fdto, ov_sym) {
+ path = fdt_getprop_by_offset(fdto, prop, &name, &path_len);
+ if (!path)
+ return path_len;
+
+ /* verify it's a string property (terminated by a single \0) */
+ if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1])
+ return -FDT_ERR_BADVALUE;
+
+ /* keep end marker to avoid strlen() */
+ e = path + path_len;
+
+ if (*path != '/')
+ return -FDT_ERR_BADVALUE;
+
+ /* get fragment name first */
+ s = strchr(path + 1, '/');
+ if (!s) {
+ /* Symbol refers to something that won't end
+ * up in the target tree */
+ continue;
+ }
+
+ frag_name = path + 1;
+ frag_name_len = s - path - 1;
+
+ /* verify format; safe since "s" lies in \0 terminated prop */
+ len = sizeof("/__overlay__/") - 1;
+ 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 - 1;
+ } else if ((e - s) == len
+ && (memcmp(s, "/__overlay__", len - 1) == 0)) {
+ /* /<fragment-name>/__overlay__ */
+ rel_path = "";
+ rel_path_len = 0;
+ } else {
+ /* Symbol refers to something that won't end
+ * up in the target tree */
+ continue;
+ }
+
+ /* find the fragment index in which the symbol lies */
+ ret = fdt_subnode_offset_namelen(fdto, 0, frag_name,
+ frag_name_len);
+ /* not found? */
+ if (ret < 0)
+ return -FDT_ERR_BADOVERLAY;
+ fragment = ret;
+
+ /* an __overlay__ subnode must exist */
+ ret = fdt_subnode_offset(fdto, fragment, "__overlay__");
+ if (ret < 0)
+ return -FDT_ERR_BADOVERLAY;
+
+ /* get the target of the fragment */
+ ret = overlay_get_target(fdt, fdto, fragment, &target_path);
+ if (ret < 0)
+ return ret;
+ target = ret;
+
+ /* if we have a target path use */
+ if (!target_path) {
+ ret = get_path_len(fdt, target);
+ if (ret < 0)
+ return ret;
+ len = ret;
+ } else {
+ len = strlen(target_path);
+ }
+
+ ret = fdt_setprop_placeholder(fdt, root_sym, name,
+ len + (len > 1) + rel_path_len + 1, &p);
+ if (ret < 0)
+ return ret;
+
+ if (!target_path) {
+ /* again in case setprop_placeholder changed it */
+ ret = overlay_get_target(fdt, fdto, fragment, &target_path);
+ if (ret < 0)
+ return ret;
+ target = ret;
+ }
+
+ buf = p;
+ if (len > 1) { /* target is not root */
+ if (!target_path) {
+ ret = fdt_get_path(fdt, target, buf, len + 1);
+ if (ret < 0)
+ return ret;
+ } else
+ memcpy(buf, target_path, len + 1);
+
+ } else
+ len--;
+
+ buf[len] = '/';
+ memcpy(buf + len + 1, rel_path, rel_path_len);
+ buf[len + 1 + rel_path_len] = '\0';
+ }
+
+ return 0;
+}
+
+int fdt_overlay_apply(void *fdt, void *fdto)
+{
+ uint32_t delta;
+ int ret;
+
+ FDT_RO_PROBE(fdt);
+ FDT_RO_PROBE(fdto);
+
+ ret = fdt_find_max_phandle(fdt, &delta);
+ if (ret)
+ goto err;
+
+ ret = overlay_adjust_local_phandles(fdto, delta);
+ if (ret)
+ goto err;
+
+ ret = overlay_update_local_references(fdto, delta);
+ if (ret)
+ goto err;
+
+ ret = overlay_fixup_phandles(fdt, fdto);
+ if (ret)
+ goto err;
+
+ ret = overlay_merge(fdt, fdto);
+ if (ret)
+ goto err;
+
+ ret = overlay_symbol_update(fdt, fdto);
+ if (ret)
+ goto err;
+
+ /*
+ * The overlay has been damaged, erase its magic.
+ */
+ fdt_set_magic(fdto, ~0);
+
+ return 0;
+
+err:
+ /*
+ * The overlay might have been damaged, erase its magic.
+ */
+ fdt_set_magic(fdto, ~0);
+
+ /*
+ * The base device tree might have been damaged, erase its
+ * magic.
+ */
+ fdt_set_magic(fdt, ~0);
+
+ return ret;
+}
diff --git a/roms/opensbi/lib/utils/libfdt/fdt_ro.c b/roms/opensbi/lib/utils/libfdt/fdt_ro.c
new file mode 100644
index 000000000..e03570a56
--- /dev/null
+++ b/roms/opensbi/lib/utils/libfdt/fdt_ro.c
@@ -0,0 +1,857 @@
+// 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"
+
+static int fdt_nodename_eq_(const void *fdt, int offset,
+ const char *s, int len)
+{
+ int olen;
+ const char *p = fdt_get_name(fdt, offset, &olen);
+
+ if (!p || olen < len)
+ /* short match */
+ return 0;
+
+ if (memcmp(p, s, len) != 0)
+ return 0;
+
+ if (p[len] == '\0')
+ return 1;
+ else if (!memchr(s, '@', len) && (p[len] == '@'))
+ return 1;
+ else
+ return 0;
+}
+
+const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
+{
+ 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;
+
+ if (fdt_magic(fdt) == FDT_MAGIC) {
+ if (stroffset < 0)
+ goto fail;
+ 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)
+ len = fdt_size_dt_strings(fdt) - stroffset;
+ }
+ } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
+ if ((stroffset >= 0)
+ || (stroffset < -fdt_size_dt_strings(fdt)))
+ goto fail;
+ if ((-stroffset) < len)
+ len = -stroffset;
+ } else {
+ err = -FDT_ERR_INTERNAL;
+ goto fail;
+ }
+
+ s = (const char *)fdt + absoffset;
+ n = memchr(s, '\0', len);
+ if (!n) {
+ /* missing terminating NULL */
+ err = -FDT_ERR_TRUNCATED;
+ goto fail;
+ }
+
+ if (lenp)
+ *lenp = n - s;
+ return s;
+
+fail:
+ if (lenp)
+ *lenp = err;
+ return NULL;
+}
+
+const char *fdt_string(const void *fdt, int stroffset)
+{
+ return fdt_get_string(fdt, stroffset, NULL);
+}
+
+static int fdt_string_eq_(const void *fdt, int stroffset,
+ const char *s, int len)
+{
+ int slen;
+ const char *p = fdt_get_string(fdt, stroffset, &slen);
+
+ return p && (slen == len) && (memcmp(p, s, len) == 0);
+}
+
+int fdt_find_max_phandle(const void *fdt, uint32_t *phandle)
+{
+ uint32_t max = 0;
+ int offset = -1;
+
+ while (true) {
+ uint32_t value;
+
+ offset = fdt_next_node(fdt, offset, NULL);
+ if (offset < 0) {
+ if (offset == -FDT_ERR_NOTFOUND)
+ break;
+
+ return offset;
+ }
+
+ value = fdt_get_phandle(fdt, offset);
+
+ if (value > max)
+ max = value;
+ }
+
+ if (phandle)
+ *phandle = max;
+
+ return 0;
+}
+
+int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
+{
+ uint32_t max;
+ int err;
+
+ err = fdt_find_max_phandle(fdt, &max);
+ if (err < 0)
+ return err;
+
+ if (max == FDT_MAX_PHANDLE)
+ return -FDT_ERR_NOPHANDLES;
+
+ if (phandle)
+ *phandle = max + 1;
+
+ return 0;
+}
+
+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 (!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);
+}
+
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
+{
+ const struct fdt_reserve_entry *re;
+
+ FDT_RO_PROBE(fdt);
+ re = fdt_mem_rsv(fdt, n);
+ if (!can_assume(VALID_INPUT) && !re)
+ return -FDT_ERR_BADOFFSET;
+
+ *address = fdt64_ld(&re->address);
+ *size = fdt64_ld(&re->size);
+ return 0;
+}
+
+int fdt_num_mem_rsv(const void *fdt)
+{
+ int i;
+ const struct fdt_reserve_entry *re;
+
+ for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
+ if (fdt64_ld(&re->size) == 0)
+ return i;
+ }
+ return -FDT_ERR_TRUNCATED;
+}
+
+static int nextprop_(const void *fdt, int offset)
+{
+ uint32_t tag;
+ int nextoffset;
+
+ do {
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+ switch (tag) {
+ case FDT_END:
+ if (nextoffset >= 0)
+ return -FDT_ERR_BADSTRUCTURE;
+ else
+ return nextoffset;
+
+ case FDT_PROP:
+ return offset;
+ }
+ offset = nextoffset;
+ } while (tag == FDT_NOP);
+
+ return -FDT_ERR_NOTFOUND;
+}
+
+int fdt_subnode_offset_namelen(const void *fdt, int offset,
+ const char *name, int namelen)
+{
+ int depth;
+
+ FDT_RO_PROBE(fdt);
+
+ for (depth = 0;
+ (offset >= 0) && (depth >= 0);
+ offset = fdt_next_node(fdt, offset, &depth))
+ if ((depth == 1)
+ && fdt_nodename_eq_(fdt, offset, name, namelen))
+ return offset;
+
+ if (depth < 0)
+ return -FDT_ERR_NOTFOUND;
+ return offset; /* error */
+}
+
+int fdt_subnode_offset(const void *fdt, int parentoffset,
+ const char *name)
+{
+ return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
+{
+ const char *end = path + namelen;
+ const char *p = path;
+ int offset = 0;
+
+ FDT_RO_PROBE(fdt);
+
+ /* see if we have an alias */
+ if (*path != '/') {
+ const char *q = memchr(path, '/', end - p);
+
+ if (!q)
+ q = end;
+
+ p = fdt_get_alias_namelen(fdt, p, q - p);
+ if (!p)
+ return -FDT_ERR_BADPATH;
+ offset = fdt_path_offset(fdt, p);
+
+ p = q;
+ }
+
+ while (p < end) {
+ const char *q;
+
+ while (*p == '/') {
+ p++;
+ if (p == end)
+ return offset;
+ }
+ q = memchr(p, '/', end - p);
+ if (! q)
+ q = end;
+
+ offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
+ if (offset < 0)
+ return offset;
+
+ p = q;
+ }
+
+ return offset;
+}
+
+int fdt_path_offset(const void *fdt, const char *path)
+{
+ return fdt_path_offset_namelen(fdt, path, strlen(path));
+}
+
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
+{
+ const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset);
+ const char *nameptr;
+ int err;
+
+ if (((err = fdt_ro_probe_(fdt)) < 0)
+ || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
+ goto fail;
+
+ nameptr = nh->name;
+
+ 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
+ * contents are loosely checked.
+ */
+ const char *leaf;
+ leaf = strrchr(nameptr, '/');
+ if (leaf == NULL) {
+ err = -FDT_ERR_BADSTRUCTURE;
+ goto fail;
+ }
+ nameptr = leaf+1;
+ }
+
+ if (len)
+ *len = strlen(nameptr);
+
+ return nameptr;
+
+ fail:
+ if (len)
+ *len = err;
+ return NULL;
+}
+
+int fdt_first_property_offset(const void *fdt, int nodeoffset)
+{
+ int offset;
+
+ if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
+ return offset;
+
+ return nextprop_(fdt, offset);
+}
+
+int fdt_next_property_offset(const void *fdt, int offset)
+{
+ if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0)
+ return offset;
+
+ return nextprop_(fdt, offset);
+}
+
+static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
+ int offset,
+ int *lenp)
+{
+ int err;
+ const struct fdt_property *prop;
+
+ if (!can_assume(VALID_INPUT) &&
+ (err = fdt_check_prop_offset_(fdt, offset)) < 0) {
+ if (lenp)
+ *lenp = err;
+ return NULL;
+ }
+
+ prop = fdt_offset_ptr_(fdt, offset);
+
+ if (lenp)
+ *lenp = fdt32_ld(&prop->len);
+
+ return prop;
+}
+
+const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
+ int offset,
+ int *lenp)
+{
+ /* Prior to version 16, properties may need realignment
+ * and this API does not work. fdt_getprop_*() will, however. */
+
+ if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
+ if (lenp)
+ *lenp = -FDT_ERR_BADVERSION;
+ return NULL;
+ }
+
+ return fdt_get_property_by_offset_(fdt, offset, lenp);
+}
+
+static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
+ int offset,
+ const char *name,
+ int namelen,
+ int *lenp,
+ int *poffset)
+{
+ for (offset = fdt_first_property_offset(fdt, offset);
+ (offset >= 0);
+ (offset = fdt_next_property_offset(fdt, offset))) {
+ const struct fdt_property *prop;
+
+ prop = fdt_get_property_by_offset_(fdt, offset, lenp);
+ if (!can_assume(LIBFDT_FLAWLESS) && !prop) {
+ offset = -FDT_ERR_INTERNAL;
+ break;
+ }
+ if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff),
+ name, namelen)) {
+ if (poffset)
+ *poffset = offset;
+ return prop;
+ }
+ }
+
+ if (lenp)
+ *lenp = offset;
+ return NULL;
+}
+
+
+const struct fdt_property *fdt_get_property_namelen(const void *fdt,
+ int offset,
+ const char *name,
+ int namelen, int *lenp)
+{
+ /* Prior to version 16, properties may need realignment
+ * and this API does not work. fdt_getprop_*() will, however. */
+ if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
+ if (lenp)
+ *lenp = -FDT_ERR_BADVERSION;
+ return NULL;
+ }
+
+ return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp,
+ NULL);
+}
+
+
+const struct fdt_property *fdt_get_property(const void *fdt,
+ int nodeoffset,
+ const char *name, int *lenp)
+{
+ return fdt_get_property_namelen(fdt, nodeoffset, name,
+ strlen(name), lenp);
+}
+
+const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
+ const char *name, int namelen, int *lenp)
+{
+ int poffset;
+ const struct fdt_property *prop;
+
+ prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp,
+ &poffset);
+ if (!prop)
+ return NULL;
+
+ /* Handle realignment */
+ if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
+ (poffset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
+ return prop->data + 4;
+ return prop->data;
+}
+
+const void *fdt_getprop_by_offset(const void *fdt, int offset,
+ const char **namep, int *lenp)
+{
+ const struct fdt_property *prop;
+
+ prop = fdt_get_property_by_offset_(fdt, offset, lenp);
+ if (!prop)
+ return NULL;
+ if (namep) {
+ const char *name;
+ int namelen;
+
+ 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));
+ }
+ }
+
+ /* Handle realignment */
+ if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
+ (offset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
+ return prop->data + 4;
+ return prop->data;
+}
+
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+ const char *name, int *lenp)
+{
+ return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
+}
+
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
+{
+ const fdt32_t *php;
+ int len;
+
+ /* FIXME: This is a bit sub-optimal, since we potentially scan
+ * over all the properties twice. */
+ php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
+ if (!php || (len != sizeof(*php))) {
+ php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
+ if (!php || (len != sizeof(*php)))
+ return 0;
+ }
+
+ return fdt32_ld(php);
+}
+
+const char *fdt_get_alias_namelen(const void *fdt,
+ const char *name, int namelen)
+{
+ int aliasoffset;
+
+ aliasoffset = fdt_path_offset(fdt, "/aliases");
+ if (aliasoffset < 0)
+ return NULL;
+
+ return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
+}
+
+const char *fdt_get_alias(const void *fdt, const char *name)
+{
+ return fdt_get_alias_namelen(fdt, name, strlen(name));
+}
+
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
+{
+ int pdepth = 0, p = 0;
+ int offset, depth, namelen;
+ const char *name;
+
+ FDT_RO_PROBE(fdt);
+
+ if (buflen < 2)
+ return -FDT_ERR_NOSPACE;
+
+ for (offset = 0, depth = 0;
+ (offset >= 0) && (offset <= nodeoffset);
+ offset = fdt_next_node(fdt, offset, &depth)) {
+ while (pdepth > depth) {
+ do {
+ p--;
+ } while (buf[p-1] != '/');
+ pdepth--;
+ }
+
+ if (pdepth >= depth) {
+ name = fdt_get_name(fdt, offset, &namelen);
+ if (!name)
+ return namelen;
+ if ((p + namelen + 1) <= buflen) {
+ memcpy(buf + p, name, namelen);
+ p += namelen;
+ buf[p++] = '/';
+ pdepth++;
+ }
+ }
+
+ if (offset == nodeoffset) {
+ if (pdepth < (depth + 1))
+ return -FDT_ERR_NOSPACE;
+
+ if (p > 1) /* special case so that root path is "/", not "" */
+ p--;
+ buf[p] = '\0';
+ return 0;
+ }
+ }
+
+ 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() */
+}
+
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+ int supernodedepth, int *nodedepth)
+{
+ int offset, depth;
+ int supernodeoffset = -FDT_ERR_INTERNAL;
+
+ FDT_RO_PROBE(fdt);
+
+ if (supernodedepth < 0)
+ return -FDT_ERR_NOTFOUND;
+
+ for (offset = 0, depth = 0;
+ (offset >= 0) && (offset <= nodeoffset);
+ offset = fdt_next_node(fdt, offset, &depth)) {
+ if (depth == supernodedepth)
+ supernodeoffset = offset;
+
+ if (offset == nodeoffset) {
+ if (nodedepth)
+ *nodedepth = depth;
+
+ if (supernodedepth > depth)
+ return -FDT_ERR_NOTFOUND;
+ else
+ return supernodeoffset;
+ }
+ }
+
+ 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() */
+}
+
+int fdt_node_depth(const void *fdt, int nodeoffset)
+{
+ int nodedepth;
+ int err;
+
+ err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
+ if (err)
+ return (can_assume(LIBFDT_FLAWLESS) || err < 0) ? err :
+ -FDT_ERR_INTERNAL;
+ return nodedepth;
+}
+
+int fdt_parent_offset(const void *fdt, int nodeoffset)
+{
+ int nodedepth = fdt_node_depth(fdt, nodeoffset);
+
+ if (nodedepth < 0)
+ return nodedepth;
+ return fdt_supernode_atdepth_offset(fdt, nodeoffset,
+ nodedepth - 1, NULL);
+}
+
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+ const char *propname,
+ const void *propval, int proplen)
+{
+ int offset;
+ const void *val;
+ int len;
+
+ FDT_RO_PROBE(fdt);
+
+ /* FIXME: The algorithm here is pretty horrible: we scan each
+ * property of a node in fdt_getprop(), then if that didn't
+ * find what we want, we scan over them again making our way
+ * to the next node. Still it's the easiest to implement
+ * approach; performance can come later. */
+ for (offset = fdt_next_node(fdt, startoffset, NULL);
+ offset >= 0;
+ offset = fdt_next_node(fdt, offset, NULL)) {
+ val = fdt_getprop(fdt, offset, propname, &len);
+ if (val && (len == proplen)
+ && (memcmp(val, propval, len) == 0))
+ return offset;
+ }
+
+ return offset; /* error from fdt_next_node() */
+}
+
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
+{
+ int offset;
+
+ if ((phandle == 0) || (phandle == -1))
+ return -FDT_ERR_BADPHANDLE;
+
+ FDT_RO_PROBE(fdt);
+
+ /* FIXME: The algorithm here is pretty horrible: we
+ * potentially scan each property of a node in
+ * fdt_get_phandle(), then if that didn't find what
+ * we want, we scan over them again making our way to the next
+ * node. Still it's the easiest to implement approach;
+ * performance can come later. */
+ for (offset = fdt_next_node(fdt, -1, NULL);
+ offset >= 0;
+ offset = fdt_next_node(fdt, offset, NULL)) {
+ if (fdt_get_phandle(fdt, offset) == phandle)
+ return offset;
+ }
+
+ return offset; /* error from fdt_next_node() */
+}
+
+int fdt_stringlist_contains(const char *strlist, int listlen, const char *str)
+{
+ int len = strlen(str);
+ const char *p;
+
+ while (listlen >= len) {
+ if (memcmp(str, strlist, len+1) == 0)
+ return 1;
+ p = memchr(strlist, '\0', listlen);
+ if (!p)
+ return 0; /* malformed strlist.. */
+ listlen -= (p-strlist) + 1;
+ strlist = p + 1;
+ }
+ return 0;
+}
+
+int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
+{
+ const char *list, *end;
+ int length, count = 0;
+
+ list = fdt_getprop(fdt, nodeoffset, property, &length);
+ if (!list)
+ return length;
+
+ end = list + length;
+
+ while (list < end) {
+ length = strnlen(list, end - list) + 1;
+
+ /* Abort if the last string isn't properly NUL-terminated. */
+ if (list + length > end)
+ return -FDT_ERR_BADVALUE;
+
+ list += length;
+ count++;
+ }
+
+ return count;
+}
+
+int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
+ const char *string)
+{
+ int length, len, idx = 0;
+ const char *list, *end;
+
+ list = fdt_getprop(fdt, nodeoffset, property, &length);
+ if (!list)
+ return length;
+
+ len = strlen(string) + 1;
+ end = list + length;
+
+ while (list < end) {
+ length = strnlen(list, end - list) + 1;
+
+ /* Abort if the last string isn't properly NUL-terminated. */
+ if (list + length > end)
+ return -FDT_ERR_BADVALUE;
+
+ if (length == len && memcmp(list, string, length) == 0)
+ return idx;
+
+ list += length;
+ idx++;
+ }
+
+ return -FDT_ERR_NOTFOUND;
+}
+
+const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
+ const char *property, int idx,
+ int *lenp)
+{
+ const char *list, *end;
+ int length;
+
+ list = fdt_getprop(fdt, nodeoffset, property, &length);
+ if (!list) {
+ if (lenp)
+ *lenp = length;
+
+ return NULL;
+ }
+
+ end = list + length;
+
+ while (list < end) {
+ length = strnlen(list, end - list) + 1;
+
+ /* Abort if the last string isn't properly NUL-terminated. */
+ if (list + length > end) {
+ if (lenp)
+ *lenp = -FDT_ERR_BADVALUE;
+
+ return NULL;
+ }
+
+ if (idx == 0) {
+ if (lenp)
+ *lenp = length - 1;
+
+ return list;
+ }
+
+ list += length;
+ idx--;
+ }
+
+ if (lenp)
+ *lenp = -FDT_ERR_NOTFOUND;
+
+ return NULL;
+}
+
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+ const char *compatible)
+{
+ const void *prop;
+ int len;
+
+ prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
+ if (!prop)
+ return len;
+
+ return !fdt_stringlist_contains(prop, len, compatible);
+}
+
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+ const char *compatible)
+{
+ int offset, err;
+
+ FDT_RO_PROBE(fdt);
+
+ /* FIXME: The algorithm here is pretty horrible: we scan each
+ * property of a node in fdt_node_check_compatible(), then if
+ * that didn't find what we want, we scan over them again
+ * making our way to the next node. Still it's the easiest to
+ * implement approach; performance can come later. */
+ for (offset = fdt_next_node(fdt, startoffset, NULL);
+ offset >= 0;
+ offset = fdt_next_node(fdt, offset, NULL)) {
+ err = fdt_node_check_compatible(fdt, offset, compatible);
+ if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
+ return err;
+ else if (err == 0)
+ return offset;
+ }
+
+ return offset; /* error from fdt_next_node() */
+}
diff --git a/roms/opensbi/lib/utils/libfdt/fdt_rw.c b/roms/opensbi/lib/utils/libfdt/fdt_rw.c
new file mode 100644
index 000000000..13854253f
--- /dev/null
+++ b/roms/opensbi/lib/utils/libfdt/fdt_rw.c
@@ -0,0 +1,491 @@
+// 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"
+
+static int fdt_blocks_misordered_(const void *fdt,
+ int mem_rsv_size, int struct_size)
+{
+ return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
+ || (fdt_off_dt_struct(fdt) <
+ (fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
+ || (fdt_off_dt_strings(fdt) <
+ (fdt_off_dt_struct(fdt) + struct_size))
+ || (fdt_totalsize(fdt) <
+ (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
+}
+
+static int fdt_rw_probe_(void *fdt)
+{
+ if (can_assume(VALID_DTB))
+ return 0;
+ FDT_RO_PROBE(fdt);
+
+ 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 (!can_assume(LATEST) && fdt_version(fdt) > 17)
+ fdt_set_version(fdt, 17);
+
+ return 0;
+}
+
+#define FDT_RW_PROBE(fdt) \
+ { \
+ int err_; \
+ if ((err_ = fdt_rw_probe_(fdt)) != 0) \
+ return err_; \
+ }
+
+static inline int fdt_data_size_(void *fdt)
+{
+ return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+}
+
+static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen)
+{
+ char *p = splicepoint;
+ char *end = (char *)fdt + fdt_data_size_(fdt);
+
+ if (((p + oldlen) < p) || ((p + oldlen) > end))
+ return -FDT_ERR_BADOFFSET;
+ if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt))
+ return -FDT_ERR_BADOFFSET;
+ if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
+ return -FDT_ERR_NOSPACE;
+ memmove(p + newlen, p + oldlen, end - p - oldlen);
+ return 0;
+}
+
+static int fdt_splice_mem_rsv_(void *fdt, struct fdt_reserve_entry *p,
+ int oldn, int newn)
+{
+ int delta = (newn - oldn) * sizeof(*p);
+ int err;
+ err = fdt_splice_(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
+ if (err)
+ return err;
+ fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
+ fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+ return 0;
+}
+
+static int fdt_splice_struct_(void *fdt, void *p,
+ int oldlen, int newlen)
+{
+ int delta = newlen - oldlen;
+ int err;
+
+ if ((err = fdt_splice_(fdt, p, oldlen, newlen)))
+ return err;
+
+ fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
+ fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+ return 0;
+}
+
+/* Must only be used to roll back in case of error */
+static void fdt_del_last_string_(void *fdt, const char *s)
+{
+ int newlen = strlen(s) + 1;
+
+ fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) - newlen);
+}
+
+static int fdt_splice_string_(void *fdt, int newlen)
+{
+ void *p = (char *)fdt
+ + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+ int err;
+
+ if ((err = fdt_splice_(fdt, p, 0, newlen)))
+ return err;
+
+ fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + 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);
+ const char *p;
+ char *new;
+ int len = strlen(s) + 1;
+ int err;
+
+ if (!can_assume(NO_ROLLBACK))
+ *allocated = 0;
+
+ p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s);
+ if (p)
+ /* found it */
+ return (p - strtab);
+
+ new = strtab + fdt_size_dt_strings(fdt);
+ err = fdt_splice_string_(fdt, len);
+ if (err)
+ return err;
+
+ if (!can_assume(NO_ROLLBACK))
+ *allocated = 1;
+
+ memcpy(new, s, len);
+ return (new - strtab);
+}
+
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
+{
+ struct fdt_reserve_entry *re;
+ int err;
+
+ FDT_RW_PROBE(fdt);
+
+ re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt));
+ err = fdt_splice_mem_rsv_(fdt, re, 0, 1);
+ if (err)
+ return err;
+
+ re->address = cpu_to_fdt64(address);
+ re->size = cpu_to_fdt64(size);
+ return 0;
+}
+
+int fdt_del_mem_rsv(void *fdt, int n)
+{
+ struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n);
+
+ FDT_RW_PROBE(fdt);
+
+ if (n >= fdt_num_mem_rsv(fdt))
+ return -FDT_ERR_NOTFOUND;
+
+ return fdt_splice_mem_rsv_(fdt, re, 1, 0);
+}
+
+static int fdt_resize_property_(void *fdt, int nodeoffset, const char *name,
+ int len, struct fdt_property **prop)
+{
+ int oldlen;
+ int err;
+
+ *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
+ if (!*prop)
+ return oldlen;
+
+ if ((err = fdt_splice_struct_(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
+ FDT_TAGALIGN(len))))
+ return err;
+
+ (*prop)->len = cpu_to_fdt32(len);
+ return 0;
+}
+
+static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
+ int len, struct fdt_property **prop)
+{
+ int proplen;
+ int nextoffset;
+ int namestroff;
+ int err;
+ int allocated;
+
+ if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
+ return nextoffset;
+
+ namestroff = fdt_find_add_string_(fdt, name, &allocated);
+ if (namestroff < 0)
+ return namestroff;
+
+ *prop = fdt_offset_ptr_w_(fdt, nextoffset);
+ proplen = sizeof(**prop) + FDT_TAGALIGN(len);
+
+ err = fdt_splice_struct_(fdt, *prop, 0, proplen);
+ if (err) {
+ /* Delete the string if we failed to add it */
+ if (!can_assume(NO_ROLLBACK) && allocated)
+ fdt_del_last_string_(fdt, name);
+ return err;
+ }
+
+ (*prop)->tag = cpu_to_fdt32(FDT_PROP);
+ (*prop)->nameoff = cpu_to_fdt32(namestroff);
+ (*prop)->len = cpu_to_fdt32(len);
+ return 0;
+}
+
+int fdt_set_name(void *fdt, int nodeoffset, const char *name)
+{
+ char *namep;
+ int oldlen, newlen;
+ int err;
+
+ FDT_RW_PROBE(fdt);
+
+ namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
+ if (!namep)
+ return oldlen;
+
+ newlen = strlen(name);
+
+ err = fdt_splice_struct_(fdt, namep, FDT_TAGALIGN(oldlen+1),
+ FDT_TAGALIGN(newlen+1));
+ if (err)
+ return err;
+
+ memcpy(namep, name, newlen+1);
+ return 0;
+}
+
+int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
+ int len, void **prop_data)
+{
+ struct fdt_property *prop;
+ int err;
+
+ FDT_RW_PROBE(fdt);
+
+ err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop);
+ if (err == -FDT_ERR_NOTFOUND)
+ err = fdt_add_property_(fdt, nodeoffset, name, len, &prop);
+ if (err)
+ return err;
+
+ *prop_data = prop->data;
+ return 0;
+}
+
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len)
+{
+ void *prop_data;
+ int err;
+
+ err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data);
+ if (err)
+ return err;
+
+ if (len)
+ memcpy(prop_data, val, len);
+ return 0;
+}
+
+int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len)
+{
+ struct fdt_property *prop;
+ int err, oldlen, newlen;
+
+ FDT_RW_PROBE(fdt);
+
+ prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
+ if (prop) {
+ newlen = len + oldlen;
+ err = fdt_splice_struct_(fdt, prop->data,
+ FDT_TAGALIGN(oldlen),
+ FDT_TAGALIGN(newlen));
+ if (err)
+ return err;
+ prop->len = cpu_to_fdt32(newlen);
+ memcpy(prop->data + oldlen, val, len);
+ } else {
+ err = fdt_add_property_(fdt, nodeoffset, name, len, &prop);
+ if (err)
+ return err;
+ memcpy(prop->data, val, len);
+ }
+ return 0;
+}
+
+int fdt_delprop(void *fdt, int nodeoffset, const char *name)
+{
+ struct fdt_property *prop;
+ int len, proplen;
+
+ FDT_RW_PROBE(fdt);
+
+ prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
+ if (!prop)
+ return len;
+
+ proplen = sizeof(*prop) + FDT_TAGALIGN(len);
+ return fdt_splice_struct_(fdt, prop, proplen, 0);
+}
+
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+ const char *name, int namelen)
+{
+ struct fdt_node_header *nh;
+ int offset, nextoffset;
+ int nodelen;
+ int err;
+ uint32_t tag;
+ fdt32_t *endtag;
+
+ FDT_RW_PROBE(fdt);
+
+ offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
+ if (offset >= 0)
+ return -FDT_ERR_EXISTS;
+ else if (offset != -FDT_ERR_NOTFOUND)
+ return offset;
+
+ /* Try to place the new node after the parent's properties */
+ fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
+ do {
+ offset = nextoffset;
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+ } while ((tag == FDT_PROP) || (tag == FDT_NOP));
+
+ nh = fdt_offset_ptr_w_(fdt, offset);
+ nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
+
+ err = fdt_splice_struct_(fdt, nh, 0, nodelen);
+ if (err)
+ return err;
+
+ nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+ memset(nh->name, 0, FDT_TAGALIGN(namelen+1));
+ memcpy(nh->name, name, namelen);
+ endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE);
+ *endtag = cpu_to_fdt32(FDT_END_NODE);
+
+ return offset;
+}
+
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
+{
+ return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_del_node(void *fdt, int nodeoffset)
+{
+ int endoffset;
+
+ FDT_RW_PROBE(fdt);
+
+ endoffset = fdt_node_end_offset_(fdt, nodeoffset);
+ if (endoffset < 0)
+ return endoffset;
+
+ return fdt_splice_struct_(fdt, fdt_offset_ptr_w_(fdt, nodeoffset),
+ endoffset - nodeoffset, 0);
+}
+
+static void fdt_packblocks_(const char *old, char *new,
+ int mem_rsv_size, int struct_size)
+{
+ int mem_rsv_off, struct_off, strings_off;
+
+ mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
+ struct_off = mem_rsv_off + mem_rsv_size;
+ strings_off = struct_off + struct_size;
+
+ memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size);
+ fdt_set_off_mem_rsvmap(new, mem_rsv_off);
+
+ memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size);
+ fdt_set_off_dt_struct(new, struct_off);
+ fdt_set_size_dt_struct(new, struct_size);
+
+ memmove(new + strings_off, old + fdt_off_dt_strings(old),
+ fdt_size_dt_strings(old));
+ fdt_set_off_dt_strings(new, strings_off);
+ fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
+}
+
+int fdt_open_into(const void *fdt, void *buf, int bufsize)
+{
+ int err;
+ int mem_rsv_size, struct_size;
+ int newsize;
+ const char *fdtstart = fdt;
+ const char *fdtend = fdtstart + fdt_totalsize(fdt);
+ char *tmp;
+
+ FDT_RO_PROBE(fdt);
+
+ mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+ * sizeof(struct fdt_reserve_entry);
+
+ if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
+ struct_size = fdt_size_dt_struct(fdt);
+ } else {
+ struct_size = 0;
+ while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
+ ;
+ if (struct_size < 0)
+ return 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)
+ return err;
+ fdt_set_version(buf, 17);
+ fdt_set_size_dt_struct(buf, struct_size);
+ fdt_set_totalsize(buf, bufsize);
+ return 0;
+ }
+
+ /* Need to reorder */
+ newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
+ + struct_size + fdt_size_dt_strings(fdt);
+
+ if (bufsize < newsize)
+ return -FDT_ERR_NOSPACE;
+
+ /* First attempt to build converted tree at beginning of buffer */
+ tmp = buf;
+ /* But if that overlaps with the old tree... */
+ if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) {
+ /* Try right after the old tree instead */
+ tmp = (char *)(uintptr_t)fdtend;
+ if ((tmp + newsize) > ((char *)buf + bufsize))
+ return -FDT_ERR_NOSPACE;
+ }
+
+ fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size);
+ memmove(buf, tmp, newsize);
+
+ fdt_set_magic(buf, FDT_MAGIC);
+ fdt_set_totalsize(buf, bufsize);
+ fdt_set_version(buf, 17);
+ fdt_set_last_comp_version(buf, 16);
+ fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
+
+ return 0;
+}
+
+int fdt_pack(void *fdt)
+{
+ int mem_rsv_size;
+
+ FDT_RW_PROBE(fdt);
+
+ mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+ * sizeof(struct fdt_reserve_entry);
+ fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
+ fdt_set_totalsize(fdt, fdt_data_size_(fdt));
+
+ return 0;
+}
diff --git a/roms/opensbi/lib/utils/libfdt/fdt_strerror.c b/roms/opensbi/lib/utils/libfdt/fdt_strerror.c
new file mode 100644
index 000000000..768db66ea
--- /dev/null
+++ b/roms/opensbi/lib/utils/libfdt/fdt_strerror.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+struct fdt_errtabent {
+ const char *str;
+};
+
+#define FDT_ERRTABENT(val) \
+ [(val)] = { .str = #val, }
+
+static struct fdt_errtabent fdt_errtable[] = {
+ FDT_ERRTABENT(FDT_ERR_NOTFOUND),
+ FDT_ERRTABENT(FDT_ERR_EXISTS),
+ FDT_ERRTABENT(FDT_ERR_NOSPACE),
+
+ FDT_ERRTABENT(FDT_ERR_BADOFFSET),
+ FDT_ERRTABENT(FDT_ERR_BADPATH),
+ FDT_ERRTABENT(FDT_ERR_BADPHANDLE),
+ FDT_ERRTABENT(FDT_ERR_BADSTATE),
+
+ FDT_ERRTABENT(FDT_ERR_TRUNCATED),
+ FDT_ERRTABENT(FDT_ERR_BADMAGIC),
+ FDT_ERRTABENT(FDT_ERR_BADVERSION),
+ FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE),
+ FDT_ERRTABENT(FDT_ERR_BADLAYOUT),
+ FDT_ERRTABENT(FDT_ERR_INTERNAL),
+ FDT_ERRTABENT(FDT_ERR_BADNCELLS),
+ FDT_ERRTABENT(FDT_ERR_BADVALUE),
+ FDT_ERRTABENT(FDT_ERR_BADOVERLAY),
+ FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
+ FDT_ERRTABENT(FDT_ERR_BADFLAGS),
+};
+#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
+
+const char *fdt_strerror(int errval)
+{
+ if (errval > 0)
+ return "<valid offset/length>";
+ else if (errval == 0)
+ return "<no error>";
+ else if (errval > -FDT_ERRTABSIZE) {
+ const char *s = fdt_errtable[-errval].str;
+
+ if (s)
+ return s;
+ }
+
+ return "<unknown error>";
+}
diff --git a/roms/opensbi/lib/utils/libfdt/fdt_sw.c b/roms/opensbi/lib/utils/libfdt/fdt_sw.c
new file mode 100644
index 000000000..26759d5df
--- /dev/null
+++ b/roms/opensbi/lib/utils/libfdt/fdt_sw.c
@@ -0,0 +1,381 @@
+// 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"
+
+static int fdt_sw_probe_(void *fdt)
+{
+ 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;
+}
+
+#define FDT_SW_PROBE(fdt) \
+ { \
+ int err; \
+ if ((err = fdt_sw_probe_(fdt)) != 0) \
+ return err; \
+ }
+
+/* 'memrsv' state: Initial state after fdt_create()
+ *
+ * Allowed functions:
+ * fdt_add_reservmap_entry()
+ * fdt_finish_reservemap() [moves to 'struct' state]
+ */
+static int fdt_sw_probe_memrsv_(void *fdt)
+{
+ int err = fdt_sw_probe_(fdt);
+ if (err)
+ return err;
+
+ if (!can_assume(VALID_INPUT) && fdt_off_dt_strings(fdt) != 0)
+ return -FDT_ERR_BADSTATE;
+ return 0;
+}
+
+#define FDT_SW_PROBE_MEMRSV(fdt) \
+ { \
+ int err; \
+ if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \
+ return err; \
+ }
+
+/* 'struct' state: Enter this state after fdt_finish_reservemap()
+ *
+ * Allowed functions:
+ * fdt_begin_node()
+ * fdt_end_node()
+ * fdt_property*()
+ * fdt_finish() [moves to 'complete' state]
+ */
+static int fdt_sw_probe_struct_(void *fdt)
+{
+ int err = fdt_sw_probe_(fdt);
+ if (err)
+ return err;
+
+ if (!can_assume(VALID_INPUT) &&
+ fdt_off_dt_strings(fdt) != fdt_totalsize(fdt))
+ return -FDT_ERR_BADSTATE;
+ return 0;
+}
+
+#define FDT_SW_PROBE_STRUCT(fdt) \
+ { \
+ int err; \
+ if ((err = fdt_sw_probe_struct_(fdt)) != 0) \
+ return err; \
+ }
+
+static inline uint32_t sw_flags(void *fdt)
+{
+ /* assert: (fdt_magic(fdt) == FDT_SW_MAGIC) */
+ return fdt_last_comp_version(fdt);
+}
+
+/* 'complete' state: Enter this state after fdt_finish()
+ *
+ * Allowed functions: none
+ */
+
+static void *fdt_grab_space_(void *fdt, size_t len)
+{
+ int offset = fdt_size_dt_struct(fdt);
+ int spaceleft;
+
+ spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
+ - fdt_size_dt_strings(fdt);
+
+ if ((offset + len < offset) || (offset + len > spaceleft))
+ return NULL;
+
+ fdt_set_size_dt_struct(fdt, offset + len);
+ return fdt_offset_ptr_w_(fdt, offset);
+}
+
+int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags)
+{
+ const size_t hdrsize = FDT_ALIGN(sizeof(struct fdt_header),
+ sizeof(struct fdt_reserve_entry));
+ void *fdt = buf;
+
+ if (bufsize < hdrsize)
+ return -FDT_ERR_NOSPACE;
+
+ if (flags & ~FDT_CREATE_FLAGS_ALL)
+ return -FDT_ERR_BADFLAGS;
+
+ memset(buf, 0, bufsize);
+
+ /*
+ * magic and last_comp_version keep intermediate state during the fdt
+ * creation process, which is replaced with the proper FDT format by
+ * fdt_finish().
+ *
+ * flags should be accessed with sw_flags().
+ */
+ fdt_set_magic(fdt, FDT_SW_MAGIC);
+ fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
+ fdt_set_last_comp_version(fdt, flags);
+
+ fdt_set_totalsize(fdt, bufsize);
+
+ fdt_set_off_mem_rsvmap(fdt, hdrsize);
+ fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
+ fdt_set_off_dt_strings(fdt, 0);
+
+ return 0;
+}
+
+int fdt_create(void *buf, int bufsize)
+{
+ return fdt_create_with_flags(buf, bufsize, 0);
+}
+
+int fdt_resize(void *fdt, void *buf, int bufsize)
+{
+ size_t headsize, tailsize;
+ char *oldtail, *newtail;
+
+ FDT_SW_PROBE(fdt);
+
+ headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+ tailsize = fdt_size_dt_strings(fdt);
+
+ if (!can_assume(VALID_DTB) &&
+ headsize + tailsize > fdt_totalsize(fdt))
+ return -FDT_ERR_INTERNAL;
+
+ if ((headsize + tailsize) > bufsize)
+ return -FDT_ERR_NOSPACE;
+
+ oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize;
+ newtail = (char *)buf + bufsize - tailsize;
+
+ /* Two cases to avoid clobbering data if the old and new
+ * buffers partially overlap */
+ if (buf <= fdt) {
+ memmove(buf, fdt, headsize);
+ memmove(newtail, oldtail, tailsize);
+ } else {
+ memmove(newtail, oldtail, tailsize);
+ memmove(buf, fdt, headsize);
+ }
+
+ fdt_set_totalsize(buf, bufsize);
+ if (fdt_off_dt_strings(buf))
+ fdt_set_off_dt_strings(buf, bufsize);
+
+ return 0;
+}
+
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
+{
+ struct fdt_reserve_entry *re;
+ int offset;
+
+ FDT_SW_PROBE_MEMRSV(fdt);
+
+ offset = fdt_off_dt_struct(fdt);
+ if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
+ return -FDT_ERR_NOSPACE;
+
+ re = (struct fdt_reserve_entry *)((char *)fdt + offset);
+ re->address = cpu_to_fdt64(addr);
+ re->size = cpu_to_fdt64(size);
+
+ fdt_set_off_dt_struct(fdt, offset + sizeof(*re));
+
+ return 0;
+}
+
+int fdt_finish_reservemap(void *fdt)
+{
+ int err = fdt_add_reservemap_entry(fdt, 0, 0);
+
+ if (err)
+ return err;
+
+ fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt));
+ return 0;
+}
+
+int fdt_begin_node(void *fdt, const char *name)
+{
+ struct fdt_node_header *nh;
+ int namelen;
+
+ FDT_SW_PROBE_STRUCT(fdt);
+
+ namelen = strlen(name) + 1;
+ nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
+ if (! nh)
+ return -FDT_ERR_NOSPACE;
+
+ nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+ memcpy(nh->name, name, namelen);
+ return 0;
+}
+
+int fdt_end_node(void *fdt)
+{
+ fdt32_t *en;
+
+ FDT_SW_PROBE_STRUCT(fdt);
+
+ en = fdt_grab_space_(fdt, FDT_TAGSIZE);
+ if (! en)
+ return -FDT_ERR_NOSPACE;
+
+ *en = cpu_to_fdt32(FDT_END_NODE);
+ return 0;
+}
+
+static int fdt_add_string_(void *fdt, const char *s)
+{
+ char *strtab = (char *)fdt + fdt_totalsize(fdt);
+ int strtabsize = fdt_size_dt_strings(fdt);
+ int len = strlen(s) + 1;
+ int struct_top, offset;
+
+ offset = -strtabsize - len;
+ struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+ if (fdt_totalsize(fdt) + offset < struct_top)
+ return 0; /* no more room :( */
+
+ memcpy(strtab + offset, s, len);
+ fdt_set_size_dt_strings(fdt, strtabsize + len);
+ return offset;
+}
+
+/* Must only be used to roll back in case of error */
+static void fdt_del_last_string_(void *fdt, const char *s)
+{
+ int strtabsize = fdt_size_dt_strings(fdt);
+ int len = strlen(s) + 1;
+
+ fdt_set_size_dt_strings(fdt, strtabsize - len);
+}
+
+static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
+{
+ char *strtab = (char *)fdt + fdt_totalsize(fdt);
+ int strtabsize = fdt_size_dt_strings(fdt);
+ const char *p;
+
+ *allocated = 0;
+
+ p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
+ if (p)
+ return p - strtab;
+
+ *allocated = 1;
+
+ return fdt_add_string_(fdt, s);
+}
+
+int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
+{
+ struct fdt_property *prop;
+ int nameoff;
+ int allocated;
+
+ FDT_SW_PROBE_STRUCT(fdt);
+
+ /* String de-duplication can be slow, _NO_NAME_DEDUP skips it */
+ if (sw_flags(fdt) & FDT_CREATE_FLAG_NO_NAME_DEDUP) {
+ allocated = 1;
+ nameoff = fdt_add_string_(fdt, name);
+ } else {
+ nameoff = fdt_find_add_string_(fdt, name, &allocated);
+ }
+ if (nameoff == 0)
+ return -FDT_ERR_NOSPACE;
+
+ prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
+ if (! prop) {
+ if (allocated)
+ fdt_del_last_string_(fdt, name);
+ return -FDT_ERR_NOSPACE;
+ }
+
+ prop->tag = cpu_to_fdt32(FDT_PROP);
+ prop->nameoff = cpu_to_fdt32(nameoff);
+ prop->len = cpu_to_fdt32(len);
+ *valp = prop->data;
+ return 0;
+}
+
+int fdt_property(void *fdt, const char *name, const void *val, int len)
+{
+ void *ptr;
+ int ret;
+
+ ret = fdt_property_placeholder(fdt, name, len, &ptr);
+ if (ret)
+ return ret;
+ memcpy(ptr, val, len);
+ return 0;
+}
+
+int fdt_finish(void *fdt)
+{
+ char *p = (char *)fdt;
+ fdt32_t *end;
+ int oldstroffset, newstroffset;
+ uint32_t tag;
+ int offset, nextoffset;
+
+ FDT_SW_PROBE_STRUCT(fdt);
+
+ /* Add terminator */
+ end = fdt_grab_space_(fdt, sizeof(*end));
+ if (! end)
+ return -FDT_ERR_NOSPACE;
+ *end = cpu_to_fdt32(FDT_END);
+
+ /* Relocate the string table */
+ oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
+ newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+ memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
+ fdt_set_off_dt_strings(fdt, newstroffset);
+
+ /* Walk the structure, correcting string offsets */
+ offset = 0;
+ while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
+ if (tag == FDT_PROP) {
+ struct fdt_property *prop =
+ fdt_offset_ptr_w_(fdt, offset);
+ int nameoff;
+
+ nameoff = fdt32_to_cpu(prop->nameoff);
+ nameoff += fdt_size_dt_strings(fdt);
+ prop->nameoff = cpu_to_fdt32(nameoff);
+ }
+ offset = nextoffset;
+ }
+ if (nextoffset < 0)
+ return nextoffset;
+
+ /* Finally, adjust the header */
+ fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
+
+ /* And fix up fields that were keeping intermediate state. */
+ fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
+ fdt_set_magic(fdt, FDT_MAGIC);
+
+ return 0;
+}
diff --git a/roms/opensbi/lib/utils/libfdt/fdt_wip.c b/roms/opensbi/lib/utils/libfdt/fdt_wip.c
new file mode 100644
index 000000000..f64139e0b
--- /dev/null
+++ b/roms/opensbi/lib/utils/libfdt/fdt_wip.c
@@ -0,0 +1,94 @@
+// 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_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
+ const char *name, int namelen,
+ uint32_t idx, const void *val,
+ int len)
+{
+ void *propval;
+ int proplen;
+
+ propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen,
+ &proplen);
+ if (!propval)
+ return proplen;
+
+ if (proplen < (len + idx))
+ return -FDT_ERR_NOSPACE;
+
+ memcpy((char *)propval + idx, val, len);
+ return 0;
+}
+
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len)
+{
+ const void *propval;
+ int proplen;
+
+ propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
+ if (!propval)
+ return proplen;
+
+ if (proplen != len)
+ return -FDT_ERR_NOSPACE;
+
+ return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name,
+ strlen(name), 0,
+ val, len);
+}
+
+static void fdt_nop_region_(void *start, int len)
+{
+ fdt32_t *p;
+
+ for (p = start; (char *)p < ((char *)start + len); p++)
+ *p = cpu_to_fdt32(FDT_NOP);
+}
+
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
+{
+ struct fdt_property *prop;
+ int len;
+
+ prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
+ if (!prop)
+ return len;
+
+ fdt_nop_region_(prop, len + sizeof(*prop));
+
+ return 0;
+}
+
+int fdt_node_end_offset_(void *fdt, int offset)
+{
+ int depth = 0;
+
+ while ((offset >= 0) && (depth >= 0))
+ offset = fdt_next_node(fdt, offset, &depth);
+
+ return offset;
+}
+
+int fdt_nop_node(void *fdt, int nodeoffset)
+{
+ int endoffset;
+
+ endoffset = fdt_node_end_offset_(fdt, nodeoffset);
+ if (endoffset < 0)
+ return endoffset;
+
+ fdt_nop_region_(fdt_offset_ptr_w(fdt, nodeoffset, 0),
+ endoffset - nodeoffset);
+ return 0;
+}
diff --git a/roms/opensbi/lib/utils/libfdt/libfdt.h b/roms/opensbi/lib/utils/libfdt/libfdt.h
new file mode 100644
index 000000000..48f375c9c
--- /dev/null
+++ b/roms/opensbi/lib/utils/libfdt/libfdt.h
@@ -0,0 +1,2072 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
+#ifndef LIBFDT_H
+#define LIBFDT_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ */
+
+#include <libfdt_env.h>
+#include <fdt.h>
+
+#define FDT_FIRST_SUPPORTED_VERSION 0x02
+#define FDT_LAST_SUPPORTED_VERSION 0x11
+
+/* Error codes: informative error codes */
+#define FDT_ERR_NOTFOUND 1
+ /* FDT_ERR_NOTFOUND: The requested node or property does not exist */
+#define FDT_ERR_EXISTS 2
+ /* FDT_ERR_EXISTS: Attempted to create a node or property which
+ * already exists */
+#define FDT_ERR_NOSPACE 3
+ /* FDT_ERR_NOSPACE: Operation needed to expand the device
+ * tree, but its buffer did not have sufficient space to
+ * contain the expanded tree. Use fdt_open_into() to move the
+ * device tree to a buffer with more space. */
+
+/* Error codes: codes for bad parameters */
+#define FDT_ERR_BADOFFSET 4
+ /* FDT_ERR_BADOFFSET: Function was passed a structure block
+ * offset which is out-of-bounds, or which points to an
+ * unsuitable part of the structure for the operation. */
+#define FDT_ERR_BADPATH 5
+ /* FDT_ERR_BADPATH: Function was passed a badly formatted path
+ * (e.g. missing a leading / for a function which requires an
+ * absolute path) */
+#define FDT_ERR_BADPHANDLE 6
+ /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle.
+ * This can be caused either by an invalid phandle property
+ * length, or the phandle value was either 0 or -1, which are
+ * not permitted. */
+#define FDT_ERR_BADSTATE 7
+ /* FDT_ERR_BADSTATE: Function was passed an incomplete device
+ * tree created by the sequential-write functions, which is
+ * not sufficiently complete for the requested operation. */
+
+/* Error codes: codes for bad device tree blobs */
+#define FDT_ERR_TRUNCATED 8
+ /* FDT_ERR_TRUNCATED: FDT or a sub-block is improperly
+ * terminated (overflows, goes outside allowed bounds, or
+ * isn't properly terminated). */
+#define FDT_ERR_BADMAGIC 9
+ /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
+ * device tree at all - it is missing the flattened device
+ * tree magic number. */
+#define FDT_ERR_BADVERSION 10
+ /* FDT_ERR_BADVERSION: Given device tree has a version which
+ * can't be handled by the requested operation. For
+ * read-write functions, this may mean that fdt_open_into() is
+ * required to convert the tree to the expected version. */
+#define FDT_ERR_BADSTRUCTURE 11
+ /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt
+ * structure block or other serious error (e.g. misnested
+ * nodes, or subnodes preceding properties). */
+#define FDT_ERR_BADLAYOUT 12
+ /* FDT_ERR_BADLAYOUT: For read-write functions, the given
+ * device tree has it's sub-blocks in an order that the
+ * function can't handle (memory reserve map, then structure,
+ * then strings). Use fdt_open_into() to reorganize the tree
+ * into a form suitable for the read-write operations. */
+
+/* "Can't happen" error indicating a bug in libfdt */
+#define FDT_ERR_INTERNAL 13
+ /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion.
+ * Should never be returned, if it is, it indicates a bug in
+ * libfdt itself. */
+
+/* Errors in device tree content */
+#define FDT_ERR_BADNCELLS 14
+ /* FDT_ERR_BADNCELLS: Device tree has a #address-cells, #size-cells
+ * or similar property with a bad format or value */
+
+#define FDT_ERR_BADVALUE 15
+ /* FDT_ERR_BADVALUE: Device tree has a property with an unexpected
+ * value. For example: a property expected to contain a string list
+ * is not NUL-terminated within the length of its value. */
+
+#define FDT_ERR_BADOVERLAY 16
+ /* FDT_ERR_BADOVERLAY: The device tree overlay, while
+ * correctly structured, cannot be applied due to some
+ * unexpected or missing value, property or node. */
+
+#define FDT_ERR_NOPHANDLES 17
+ /* FDT_ERR_NOPHANDLES: The device tree doesn't have any
+ * phandle available anymore without causing an overflow */
+
+#define FDT_ERR_BADFLAGS 18
+ /* FDT_ERR_BADFLAGS: The function was passed a flags field that
+ * contains invalid flags or an invalid combination of flags. */
+
+#define FDT_ERR_MAX 18
+
+/* constants */
+#define FDT_MAX_PHANDLE 0xfffffffe
+ /* Valid values for phandles range from 1 to 2^32-2. */
+
+/**********************************************************************/
+/* Low-level functions (you probably don't need these) */
+/**********************************************************************/
+
+#ifndef SWIG /* This function is not useful in Python */
+const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen);
+#endif
+static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
+{
+ return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen);
+}
+
+uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
+
+/*
+ * Alignment helpers:
+ * These helpers access words from a device tree blob. They're
+ * built to work even with unaligned pointers on platforms (ike
+ * ARM) that don't like unaligned loads and stores
+ */
+
+static inline uint32_t fdt32_ld(const fdt32_t *p)
+{
+ const uint8_t *bp = (const uint8_t *)p;
+
+ return ((uint32_t)bp[0] << 24)
+ | ((uint32_t)bp[1] << 16)
+ | ((uint32_t)bp[2] << 8)
+ | bp[3];
+}
+
+static inline void fdt32_st(void *property, uint32_t value)
+{
+ uint8_t *bp = (uint8_t *)property;
+
+ bp[0] = value >> 24;
+ bp[1] = (value >> 16) & 0xff;
+ bp[2] = (value >> 8) & 0xff;
+ bp[3] = value & 0xff;
+}
+
+static inline uint64_t fdt64_ld(const fdt64_t *p)
+{
+ const uint8_t *bp = (const uint8_t *)p;
+
+ return ((uint64_t)bp[0] << 56)
+ | ((uint64_t)bp[1] << 48)
+ | ((uint64_t)bp[2] << 40)
+ | ((uint64_t)bp[3] << 32)
+ | ((uint64_t)bp[4] << 24)
+ | ((uint64_t)bp[5] << 16)
+ | ((uint64_t)bp[6] << 8)
+ | bp[7];
+}
+
+static inline void fdt64_st(void *property, uint64_t value)
+{
+ uint8_t *bp = (uint8_t *)property;
+
+ bp[0] = value >> 56;
+ bp[1] = (value >> 48) & 0xff;
+ bp[2] = (value >> 40) & 0xff;
+ bp[3] = (value >> 32) & 0xff;
+ bp[4] = (value >> 24) & 0xff;
+ bp[5] = (value >> 16) & 0xff;
+ bp[6] = (value >> 8) & 0xff;
+ bp[7] = value & 0xff;
+}
+
+/**********************************************************************/
+/* Traversal functions */
+/**********************************************************************/
+
+int fdt_next_node(const void *fdt, int offset, int *depth);
+
+/**
+ * fdt_first_subnode() - get offset of first direct subnode
+ *
+ * @fdt: FDT blob
+ * @offset: Offset of node to check
+ * @return offset of first subnode, or -FDT_ERR_NOTFOUND if there is none
+ */
+int fdt_first_subnode(const void *fdt, int offset);
+
+/**
+ * fdt_next_subnode() - get offset of next direct subnode
+ *
+ * After first calling fdt_first_subnode(), call this function repeatedly to
+ * get direct subnodes of a parent node.
+ *
+ * @fdt: FDT blob
+ * @offset: Offset of previous subnode
+ * @return offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more
+ * subnodes
+ */
+int fdt_next_subnode(const void *fdt, int offset);
+
+/**
+ * fdt_for_each_subnode - iterate over all subnodes of a parent
+ *
+ * @node: child node (int, lvalue)
+ * @fdt: FDT blob (const void *)
+ * @parent: parent node (int)
+ *
+ * This is actually a wrapper around a for loop and would be used like so:
+ *
+ * fdt_for_each_subnode(node, fdt, parent) {
+ * Use node
+ * ...
+ * }
+ *
+ * if ((node < 0) && (node != -FDT_ERR_NOTFOUND)) {
+ * Error handling
+ * }
+ *
+ * Note that this is implemented as a macro and @node is used as
+ * iterator in the loop. The parent variable be constant or even a
+ * literal.
+ *
+ */
+#define fdt_for_each_subnode(node, fdt, parent) \
+ for (node = fdt_first_subnode(fdt, parent); \
+ node >= 0; \
+ node = fdt_next_subnode(fdt, node))
+
+/**********************************************************************/
+/* General functions */
+/**********************************************************************/
+#define fdt_get_header(fdt, field) \
+ (fdt32_ld(&((const struct fdt_header *)(fdt))->field))
+#define fdt_magic(fdt) (fdt_get_header(fdt, magic))
+#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize))
+#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct))
+#define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings))
+#define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap))
+#define fdt_version(fdt) (fdt_get_header(fdt, version))
+#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version))
+#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys))
+#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings))
+#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct))
+
+#define fdt_set_hdr_(name) \
+ static inline void fdt_set_##name(void *fdt, uint32_t val) \
+ { \
+ struct fdt_header *fdth = (struct fdt_header *)fdt; \
+ fdth->name = cpu_to_fdt32(val); \
+ }
+fdt_set_hdr_(magic);
+fdt_set_hdr_(totalsize);
+fdt_set_hdr_(off_dt_struct);
+fdt_set_hdr_(off_dt_strings);
+fdt_set_hdr_(off_mem_rsvmap);
+fdt_set_hdr_(version);
+fdt_set_hdr_(last_comp_version);
+fdt_set_hdr_(boot_cpuid_phys);
+fdt_set_hdr_(size_dt_strings);
+fdt_set_hdr_(size_dt_struct);
+#undef fdt_set_hdr_
+
+/**
+ * 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);
+
+/**
+ * fdt_check_header - sanity check a device tree header
+
+ * @fdt: pointer to data which might be a flattened device tree
+ *
+ * fdt_check_header() checks that the given buffer contains what
+ * appears to be a flattened device tree, and that the header contains
+ * valid information (to the extent that can be determined from the
+ * header alone).
+ *
+ * returns:
+ * 0, if the buffer appears to contain a valid device tree
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_TRUNCATED, standard meanings, as above
+ */
+int fdt_check_header(const void *fdt);
+
+/**
+ * fdt_move - move a device tree around in memory
+ * @fdt: pointer to the device tree to move
+ * @buf: pointer to memory where the device is to be moved
+ * @bufsize: size of the memory space at buf
+ *
+ * fdt_move() relocates, if possible, the device tree blob located at
+ * fdt to the buffer at buf of size bufsize. The buffer may overlap
+ * with the existing device tree blob at fdt. Therefore,
+ * fdt_move(fdt, fdt, fdt_totalsize(fdt))
+ * should always succeed.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_move(const void *fdt, void *buf, int bufsize);
+
+/**********************************************************************/
+/* Read-only functions */
+/**********************************************************************/
+
+int fdt_check_full(const void *fdt, size_t bufsize);
+
+/**
+ * fdt_get_string - retrieve a string from the strings block of a device tree
+ * @fdt: pointer to the device tree blob
+ * @stroffset: offset of the string within the strings block (native endian)
+ * @lenp: optional pointer to return the string's length
+ *
+ * fdt_get_string() retrieves a pointer to a single string from the
+ * strings block of the device tree blob at fdt, and optionally also
+ * returns the string's length in *lenp.
+ *
+ * returns:
+ * a pointer to the string, on success
+ * NULL, if stroffset is out of bounds, or doesn't point to a valid string
+ */
+const char *fdt_get_string(const void *fdt, int stroffset, int *lenp);
+
+/**
+ * fdt_string - retrieve a string from the strings block of a device tree
+ * @fdt: pointer to the device tree blob
+ * @stroffset: offset of the string within the strings block (native endian)
+ *
+ * fdt_string() retrieves a pointer to a single string from the
+ * strings block of the device tree blob at fdt.
+ *
+ * returns:
+ * a pointer to the string, on success
+ * NULL, if stroffset is out of bounds, or doesn't point to a valid string
+ */
+const char *fdt_string(const void *fdt, int stroffset);
+
+/**
+ * fdt_find_max_phandle - find and return the highest phandle in a tree
+ * @fdt: pointer to the device tree blob
+ * @phandle: return location for the highest phandle value found in the tree
+ *
+ * fdt_find_max_phandle() finds the highest phandle value in the given device
+ * tree. The value returned in @phandle is only valid if the function returns
+ * success.
+ *
+ * returns:
+ * 0 on success or a negative error code on failure
+ */
+int fdt_find_max_phandle(const void *fdt, uint32_t *phandle);
+
+/**
+ * fdt_get_max_phandle - retrieves the highest phandle in a tree
+ * @fdt: pointer to the device tree blob
+ *
+ * fdt_get_max_phandle retrieves the highest phandle in the given
+ * device tree. This will ignore badly formatted phandles, or phandles
+ * with a value of 0 or -1.
+ *
+ * This function is deprecated in favour of fdt_find_max_phandle().
+ *
+ * returns:
+ * the highest phandle on success
+ * 0, if no phandle was found in the device tree
+ * -1, if an error occurred
+ */
+static inline uint32_t fdt_get_max_phandle(const void *fdt)
+{
+ uint32_t phandle;
+ int err;
+
+ err = fdt_find_max_phandle(fdt, &phandle);
+ if (err < 0)
+ return (uint32_t)-1;
+
+ return phandle;
+}
+
+/**
+ * fdt_generate_phandle - return a new, unused phandle for a device tree blob
+ * @fdt: pointer to the device tree blob
+ * @phandle: return location for the new phandle
+ *
+ * Walks the device tree blob and looks for the highest phandle value. On
+ * success, the new, unused phandle value (one higher than the previously
+ * highest phandle value in the device tree blob) will be returned in the
+ * @phandle parameter.
+ *
+ * Returns:
+ * 0 on success or a negative error-code on failure
+ */
+int fdt_generate_phandle(const void *fdt, uint32_t *phandle);
+
+/**
+ * fdt_num_mem_rsv - retrieve the number of memory reserve map entries
+ * @fdt: pointer to the device tree blob
+ *
+ * Returns the number of entries in the device tree blob's memory
+ * reservation map. This does not include the terminating 0,0 entry
+ * or any other (0,0) entries reserved for expansion.
+ *
+ * returns:
+ * the number of entries
+ */
+int fdt_num_mem_rsv(const void *fdt);
+
+/**
+ * fdt_get_mem_rsv - retrieve one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: pointers to 64-bit variables
+ *
+ * On success, *address and *size will contain the address and size of
+ * the n-th reserve map entry from the device tree blob, in
+ * native-endian format.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size);
+
+/**
+ * fdt_subnode_offset_namelen - find a subnode based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_subnode_offset(), but only examine the first
+ * namelen characters of name for matching the subnode name. This is
+ * useful for finding subnodes based on a portion of a larger string,
+ * such as a full path.
+ */
+#ifndef SWIG /* Not available in Python */
+int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
+ const char *name, int namelen);
+#endif
+/**
+ * fdt_subnode_offset - find a subnode of a given node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_subnode_offset() finds a subnode of the node at structure block
+ * offset parentoffset with the given name. name may include a unit
+ * address, in which case fdt_subnode_offset() will find the subnode
+ * with that unit address, or the unit address may be omitted, in
+ * which case fdt_subnode_offset() will find an arbitrary subnode
+ * whose name excluding unit address matches the given name.
+ *
+ * returns:
+ * structure block offset of the requested subnode (>=0), on success
+ * -FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE
+ * tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_path_offset_namelen - find a tree node by its full path
+ * @fdt: pointer to the device tree blob
+ * @path: full path of the node to locate
+ * @namelen: number of characters of path to consider
+ *
+ * Identical to fdt_path_offset(), but only consider the first namelen
+ * characters of path as the path name.
+ */
+#ifndef SWIG /* Not available in Python */
+int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen);
+#endif
+
+/**
+ * fdt_path_offset - find a tree node by its full path
+ * @fdt: pointer to the device tree blob
+ * @path: full path of the node to locate
+ *
+ * fdt_path_offset() finds a node of a given path in the device tree.
+ * Each path component may omit the unit address portion, but the
+ * results of this are undefined if any such path component is
+ * ambiguous (that is if there are multiple nodes at the relevant
+ * level matching the given component, differentiated only by unit
+ * address).
+ *
+ * returns:
+ * structure block offset of the node with the requested path (>=0), on
+ * success
+ * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid
+ * -FDT_ERR_NOTFOUND, if the requested node does not exist
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_path_offset(const void *fdt, const char *path);
+
+/**
+ * fdt_get_name - retrieve the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the starting node
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_name() retrieves the name (including unit address) of the
+ * device tree node at structure block offset nodeoffset. If lenp is
+ * non-NULL, the length of this name is also returned, in the integer
+ * pointed to by lenp.
+ *
+ * returns:
+ * pointer to the node's name, on success
+ * If lenp is non-NULL, *lenp contains the length of that name
+ * (>=0)
+ * NULL, on error
+ * if lenp is non-NULL *lenp contains an error code (<0):
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
+ * tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp);
+
+/**
+ * fdt_first_property_offset - find the offset of a node's first property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ *
+ * fdt_first_property_offset() finds the first property of the node at
+ * the given structure block offset.
+ *
+ * returns:
+ * structure block offset of the property (>=0), on success
+ * -FDT_ERR_NOTFOUND, if the requested node has no properties
+ * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_first_property_offset(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_next_property_offset - step through a node's properties
+ * @fdt: pointer to the device tree blob
+ * @offset: structure block offset of a property
+ *
+ * fdt_next_property_offset() finds the property immediately after the
+ * one at the given structure block offset. This will be a property
+ * of the same node as the given property.
+ *
+ * returns:
+ * structure block offset of the next property (>=0), on success
+ * -FDT_ERR_NOTFOUND, if the given property is the last in its node
+ * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_next_property_offset(const void *fdt, int offset);
+
+/**
+ * fdt_for_each_property_offset - iterate over all properties of a node
+ *
+ * @property_offset: property offset (int, lvalue)
+ * @fdt: FDT blob (const void *)
+ * @node: node offset (int)
+ *
+ * This is actually a wrapper around a for loop and would be used like so:
+ *
+ * fdt_for_each_property_offset(property, fdt, node) {
+ * Use property
+ * ...
+ * }
+ *
+ * if ((property < 0) && (property != -FDT_ERR_NOTFOUND)) {
+ * Error handling
+ * }
+ *
+ * Note that this is implemented as a macro and property is used as
+ * iterator in the loop. The node variable can be constant or even a
+ * literal.
+ */
+#define fdt_for_each_property_offset(property, fdt, node) \
+ for (property = fdt_first_property_offset(fdt, node); \
+ property >= 0; \
+ property = fdt_next_property_offset(fdt, property))
+
+/**
+ * fdt_get_property_by_offset - retrieve the property at a given offset
+ * @fdt: pointer to the device tree blob
+ * @offset: offset of the property to retrieve
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_property_by_offset() retrieves a pointer to the
+ * fdt_property structure within the device tree blob at the given
+ * offset. If lenp is non-NULL, the length of the property value is
+ * also returned, in the integer pointed to by lenp.
+ *
+ * Note that this code only works on device tree versions >= 16. fdt_getprop()
+ * works on all versions.
+ *
+ * returns:
+ * pointer to the structure representing the property
+ * if lenp is non-NULL, *lenp contains the length of the property
+ * value (>=0)
+ * NULL, on error
+ * if lenp is non-NULL, *lenp contains an error code (<0):
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
+ int offset,
+ int *lenp);
+
+/**
+ * fdt_get_property_namelen - find a property based on substring
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @namelen: number of characters of name to consider
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * Identical to fdt_get_property(), but only examine the first namelen
+ * characters of name for matching the property name.
+ */
+#ifndef SWIG /* Not available in Python */
+const struct fdt_property *fdt_get_property_namelen(const void *fdt,
+ int nodeoffset,
+ const char *name,
+ int namelen, int *lenp);
+#endif
+
+/**
+ * fdt_get_property - find a given property in a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_property() retrieves a pointer to the fdt_property
+ * structure within the device tree blob corresponding to the property
+ * named 'name' of the node at offset nodeoffset. If lenp is
+ * non-NULL, the length of the property value is also returned, in the
+ * integer pointed to by lenp.
+ *
+ * returns:
+ * pointer to the structure representing the property
+ * if lenp is non-NULL, *lenp contains the length of the property
+ * value (>=0)
+ * NULL, on error
+ * if lenp is non-NULL, *lenp contains an error code (<0):
+ * -FDT_ERR_NOTFOUND, node does not have named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
+ * tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset,
+ const char *name, int *lenp);
+static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
+ const char *name,
+ int *lenp)
+{
+ return (struct fdt_property *)(uintptr_t)
+ fdt_get_property(fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_getprop_by_offset - retrieve the value of a property at a given offset
+ * @fdt: pointer to the device tree blob
+ * @offset: offset of the property to read
+ * @namep: pointer to a string variable (will be overwritten) or NULL
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop_by_offset() retrieves a pointer to the value of the
+ * property at structure block offset 'offset' (this will be a pointer
+ * to within the device blob itself, not a copy of the value). If
+ * lenp is non-NULL, the length of the property value is also
+ * returned, in the integer pointed to by lenp. If namep is non-NULL,
+ * the property's namne will also be returned in the char * pointed to
+ * by namep (this will be a pointer to within the device tree's string
+ * block, not a new copy of the name).
+ *
+ * returns:
+ * pointer to the property's value
+ * if lenp is non-NULL, *lenp contains the length of the property
+ * value (>=0)
+ * if namep is non-NULL *namep contiains a pointer to the property
+ * name.
+ * NULL, on error
+ * if lenp is non-NULL, *lenp contains an error code (<0):
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+#ifndef SWIG /* This function is not useful in Python */
+const void *fdt_getprop_by_offset(const void *fdt, int offset,
+ const char **namep, int *lenp);
+#endif
+
+/**
+ * fdt_getprop_namelen - get property value based on substring
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @namelen: number of characters of name to consider
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * Identical to fdt_getprop(), but only examine the first namelen
+ * characters of name for matching the property name.
+ */
+#ifndef SWIG /* Not available in Python */
+const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
+ const char *name, int namelen, int *lenp);
+static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset,
+ const char *name, int namelen,
+ int *lenp)
+{
+ return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name,
+ namelen, lenp);
+}
+#endif
+
+/**
+ * fdt_getprop - retrieve the value of a given property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop() retrieves a pointer to the value of the property
+ * named 'name' of the node at offset nodeoffset (this will be a
+ * pointer to within the device blob itself, not a copy of the value).
+ * If lenp is non-NULL, the length of the property value is also
+ * returned, in the integer pointed to by lenp.
+ *
+ * returns:
+ * pointer to the property's value
+ * if lenp is non-NULL, *lenp contains the length of the property
+ * value (>=0)
+ * NULL, on error
+ * if lenp is non-NULL, *lenp contains an error code (<0):
+ * -FDT_ERR_NOTFOUND, node does not have named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
+ * tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+ const char *name, int *lenp);
+static inline void *fdt_getprop_w(void *fdt, int nodeoffset,
+ const char *name, int *lenp)
+{
+ return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_get_phandle - retrieve the phandle of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the node
+ *
+ * fdt_get_phandle() retrieves the phandle of the device tree node at
+ * structure block offset nodeoffset.
+ *
+ * returns:
+ * the phandle of the node at nodeoffset, on success (!= 0, != -1)
+ * 0, if the node has no phandle, or another error occurs
+ */
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_get_alias_namelen - get alias based on substring
+ * @fdt: pointer to the device tree blob
+ * @name: name of the alias th look up
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_get_alias(), but only examine the first namelen
+ * characters of name for matching the alias name.
+ */
+#ifndef SWIG /* Not available in Python */
+const char *fdt_get_alias_namelen(const void *fdt,
+ const char *name, int namelen);
+#endif
+
+/**
+ * fdt_get_alias - retrieve the path referenced by a given alias
+ * @fdt: pointer to the device tree blob
+ * @name: name of the alias th look up
+ *
+ * fdt_get_alias() retrieves the value of a given alias. That is, the
+ * value of the property named 'name' in the node /aliases.
+ *
+ * returns:
+ * a pointer to the expansion of the alias named 'name', if it exists
+ * NULL, if the given alias or the /aliases node does not exist
+ */
+const char *fdt_get_alias(const void *fdt, const char *name);
+
+/**
+ * fdt_get_path - determine the full path of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose path to find
+ * @buf: character buffer to contain the returned path (will be overwritten)
+ * @buflen: size of the character buffer at buf
+ *
+ * fdt_get_path() computes the full path of the node at offset
+ * nodeoffset, and records that path in the buffer at buf.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ * 0, on success
+ * buf contains the absolute path of the node at
+ * nodeoffset, as a NUL-terminated string.
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1)
+ * characters and will not fit in the given buffer.
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen);
+
+/**
+ * fdt_supernode_atdepth_offset - find a specific ancestor of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ * @supernodedepth: depth of the ancestor to find
+ * @nodedepth: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_supernode_atdepth_offset() finds an ancestor of the given node
+ * at a specific depth from the root (where the root itself has depth
+ * 0, its immediate subnodes depth 1 and so forth). So
+ * fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL);
+ * will always return 0, the offset of the root node. If the node at
+ * nodeoffset has depth D, then:
+ * fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL);
+ * will return nodeoffset itself.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ * structure block offset of the node at node offset's ancestor
+ * of depth supernodedepth (>=0), on success
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of
+ * nodeoffset
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+ int supernodedepth, int *nodedepth);
+
+/**
+ * fdt_node_depth - find the depth of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_node_depth() finds the depth of a given node. The root node
+ * has depth 0, its immediate subnodes depth 1 and so forth.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ * depth of the node at nodeoffset (>=0), on success
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_depth(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_parent_offset - find the parent of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_parent_offset() locates the parent node of a given node (that
+ * is, it finds the offset of the node which contains the node at
+ * nodeoffset as a subnode).
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset, *twice*.
+ *
+ * returns:
+ * structure block offset of the parent of the node at nodeoffset
+ * (>=0), on success
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_parent_offset(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_node_offset_by_prop_value - find nodes with a given property value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @propname: property name to check
+ * @propval: property value to search for
+ * @proplen: length of the value in propval
+ *
+ * fdt_node_offset_by_prop_value() returns the offset of the first
+ * node after startoffset, which has a property named propname whose
+ * value is of length proplen and has value equal to propval; or if
+ * startoffset is -1, the very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ * offset = fdt_node_offset_by_prop_value(fdt, -1, propname,
+ * propval, proplen);
+ * while (offset != -FDT_ERR_NOTFOUND) {
+ * // other code here
+ * offset = fdt_node_offset_by_prop_value(fdt, offset, propname,
+ * propval, proplen);
+ * }
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ * structure block offset of the located node (>= 0, >startoffset),
+ * on success
+ * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ * tree after startoffset
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+ const char *propname,
+ const void *propval, int proplen);
+
+/**
+ * fdt_node_offset_by_phandle - find the node with a given phandle
+ * @fdt: pointer to the device tree blob
+ * @phandle: phandle value
+ *
+ * fdt_node_offset_by_phandle() returns the offset of the node
+ * which has the given phandle value. If there is more than one node
+ * in the tree with the given phandle (an invalid tree), results are
+ * undefined.
+ *
+ * returns:
+ * structure block offset of the located node (>= 0), on success
+ * -FDT_ERR_NOTFOUND, no node with that phandle exists
+ * -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1)
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle);
+
+/**
+ * fdt_node_check_compatible: check a node's compatible property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @compatible: string to match against
+ *
+ *
+ * fdt_node_check_compatible() returns 0 if the given node contains a
+ * 'compatible' property with the given string as one of its elements,
+ * it returns non-zero otherwise, or on error.
+ *
+ * returns:
+ * 0, if the node has a 'compatible' property listing the given string
+ * 1, if the node has a 'compatible' property, but it does not list
+ * the given string
+ * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property
+ * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+ const char *compatible);
+
+/**
+ * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @compatible: 'compatible' string to match against
+ *
+ * fdt_node_offset_by_compatible() returns the offset of the first
+ * node after startoffset, which has a 'compatible' property which
+ * lists the given compatible string; or if startoffset is -1, the
+ * very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ * offset = fdt_node_offset_by_compatible(fdt, -1, compatible);
+ * while (offset != -FDT_ERR_NOTFOUND) {
+ * // other code here
+ * offset = fdt_node_offset_by_compatible(fdt, offset, compatible);
+ * }
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ * structure block offset of the located node (>= 0, >startoffset),
+ * on success
+ * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ * tree after startoffset
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+ const char *compatible);
+
+/**
+ * fdt_stringlist_contains - check a string list property for a string
+ * @strlist: Property containing a list of strings to check
+ * @listlen: Length of property
+ * @str: String to search for
+ *
+ * This is a utility function provided for convenience. The list contains
+ * one or more strings, each terminated by \0, as is found in a device tree
+ * "compatible" property.
+ *
+ * @return: 1 if the string is found in the list, 0 not found, or invalid list
+ */
+int fdt_stringlist_contains(const char *strlist, int listlen, const char *str);
+
+/**
+ * fdt_stringlist_count - count the number of strings in a string list
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @property: name of the property containing the string list
+ * @return:
+ * the number of strings in the given property
+ * -FDT_ERR_BADVALUE if the property value is not NUL-terminated
+ * -FDT_ERR_NOTFOUND if the property does not exist
+ */
+int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property);
+
+/**
+ * fdt_stringlist_search - find a string in a string list and return its index
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @property: name of the property containing the string list
+ * @string: string to look up in the string list
+ *
+ * Note that it is possible for this function to succeed on property values
+ * that are not NUL-terminated. That's because the function will stop after
+ * finding the first occurrence of @string. This can for example happen with
+ * small-valued cell properties, such as #address-cells, when searching for
+ * the empty string.
+ *
+ * @return:
+ * the index of the string in the list of strings
+ * -FDT_ERR_BADVALUE if the property value is not NUL-terminated
+ * -FDT_ERR_NOTFOUND if the property does not exist or does not contain
+ * the given string
+ */
+int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
+ const char *string);
+
+/**
+ * fdt_stringlist_get() - obtain the string at a given index in a string list
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @property: name of the property containing the string list
+ * @index: index of the string to return
+ * @lenp: return location for the string length or an error code on failure
+ *
+ * Note that this will successfully extract strings from properties with
+ * non-NUL-terminated values. For example on small-valued cell properties
+ * this function will return the empty string.
+ *
+ * If non-NULL, the length of the string (on success) or a negative error-code
+ * (on failure) will be stored in the integer pointer to by lenp.
+ *
+ * @return:
+ * A pointer to the string at the given index in the string list or NULL on
+ * failure. On success the length of the string will be stored in the memory
+ * location pointed to by the lenp parameter, if non-NULL. On failure one of
+ * the following negative error codes will be returned in the lenp parameter
+ * (if non-NULL):
+ * -FDT_ERR_BADVALUE if the property value is not NUL-terminated
+ * -FDT_ERR_NOTFOUND if the property does not exist
+ */
+const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
+ const char *property, int index,
+ int *lenp);
+
+/**********************************************************************/
+/* Read-only functions (addressing related) */
+/**********************************************************************/
+
+/**
+ * FDT_MAX_NCELLS - maximum value for #address-cells and #size-cells
+ *
+ * This is the maximum value for #address-cells, #size-cells and
+ * similar properties that will be processed by libfdt. IEE1275
+ * requires that OF implementations handle values up to 4.
+ * Implementations may support larger values, but in practice higher
+ * values aren't used.
+ */
+#define FDT_MAX_NCELLS 4
+
+/**
+ * fdt_address_cells - retrieve address size for a bus represented in the tree
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to find the address size for
+ *
+ * When the node has a valid #address-cells property, returns its value.
+ *
+ * returns:
+ * 0 <= n < FDT_MAX_NCELLS, on success
+ * 2, if the node has no #address-cells property
+ * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ * #address-cells property
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_address_cells(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_size_cells - retrieve address range size for a bus represented in the
+ * tree
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to find the address range size for
+ *
+ * When the node has a valid #size-cells property, returns its value.
+ *
+ * returns:
+ * 0 <= n < FDT_MAX_NCELLS, on success
+ * 1, if the node has no #size-cells property
+ * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ * #size-cells property
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_size_cells(const void *fdt, int nodeoffset);
+
+
+/**********************************************************************/
+/* Write-in-place functions */
+/**********************************************************************/
+
+/**
+ * fdt_setprop_inplace_namelen_partial - change a property's value,
+ * but not its size
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @namelen: number of characters of name to consider
+ * @idx: index of the property to change in the array
+ * @val: pointer to data to replace the property value with
+ * @len: length of the property value
+ *
+ * Identical to fdt_setprop_inplace(), but modifies the given property
+ * starting from the given index, and using only the first characters
+ * of the name. It is useful when you want to manipulate only one value of
+ * an array and you have a string that doesn't end with \0.
+ */
+#ifndef SWIG /* Not available in Python */
+int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
+ const char *name, int namelen,
+ uint32_t idx, const void *val,
+ int len);
+#endif
+
+/**
+ * fdt_setprop_inplace - change a property's value, but not its size
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to replace the property value with
+ * @len: length of the property value
+ *
+ * fdt_setprop_inplace() replaces the value of a given property with
+ * the data in val, of length len. This function cannot change the
+ * size of a property, and so will only work if len is equal to the
+ * current length of the property.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, if len is not equal to the property's current length
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+#ifndef SWIG /* Not available in Python */
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len);
+#endif
+
+/**
+ * fdt_setprop_inplace_u32 - change the value of a 32-bit integer property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value to replace the property with
+ *
+ * fdt_setprop_inplace_u32() replaces the value of a given property
+ * with the 32-bit integer value in val, converting val to big-endian
+ * if necessary. This function cannot change the size of a property,
+ * and so will only work if the property already exists and has length
+ * 4.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, if the property's length is not equal to 4
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_inplace_u32(void *fdt, int nodeoffset,
+ const char *name, uint32_t val)
+{
+ fdt32_t tmp = cpu_to_fdt32(val);
+ return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_inplace_u64 - change the value of a 64-bit integer property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 64-bit integer value to replace the property with
+ *
+ * fdt_setprop_inplace_u64() replaces the value of a given property
+ * with the 64-bit integer value in val, converting val to big-endian
+ * if necessary. This function cannot change the size of a property,
+ * and so will only work if the property already exists and has length
+ * 8.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, if the property's length is not equal to 8
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset,
+ const char *name, uint64_t val)
+{
+ fdt64_t tmp = cpu_to_fdt64(val);
+ return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_inplace_cell - change the value of a single-cell property
+ *
+ * This is an alternative name for fdt_setprop_inplace_u32()
+ */
+static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset,
+ const char *name, uint32_t val)
+{
+ return fdt_setprop_inplace_u32(fdt, nodeoffset, name, val);
+}
+
+/**
+ * fdt_nop_property - replace a property with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_nop_property() will replace a given property's representation
+ * in the blob with FDT_NOP tags, effectively removing it from the
+ * tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the property, and will not alter or move any other part of the
+ * tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_nop_node - replace a node (subtree) with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_nop_node() will replace a given node's representation in the
+ * blob, including all its subnodes, if any, with FDT_NOP tags,
+ * effectively removing it from the tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the node and its properties and subnodes, and will not alter or
+ * move any other part of the tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_node(void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Sequential write functions */
+/**********************************************************************/
+
+/* fdt_create_with_flags flags */
+#define FDT_CREATE_FLAG_NO_NAME_DEDUP 0x1
+ /* FDT_CREATE_FLAG_NO_NAME_DEDUP: Do not try to de-duplicate property
+ * names in the fdt. This can result in faster creation times, but
+ * a larger fdt. */
+
+#define FDT_CREATE_FLAGS_ALL (FDT_CREATE_FLAG_NO_NAME_DEDUP)
+
+/**
+ * fdt_create_with_flags - begin creation of a new fdt
+ * @fdt: pointer to memory allocated where fdt will be created
+ * @bufsize: size of the memory space at fdt
+ * @flags: a valid combination of FDT_CREATE_FLAG_ flags, or 0.
+ *
+ * fdt_create_with_flags() begins the process of creating a new fdt with
+ * the sequential write interface.
+ *
+ * fdt creation process must end with fdt_finished() to produce a valid fdt.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt
+ * -FDT_ERR_BADFLAGS, flags is not valid
+ */
+int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags);
+
+/**
+ * fdt_create - begin creation of a new fdt
+ * @fdt: pointer to memory allocated where fdt will be created
+ * @bufsize: size of the memory space at fdt
+ *
+ * fdt_create() is equivalent to fdt_create_with_flags() with flags=0.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt
+ */
+int fdt_create(void *buf, int bufsize);
+
+int fdt_resize(void *fdt, void *buf, int bufsize);
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
+int fdt_finish_reservemap(void *fdt);
+int fdt_begin_node(void *fdt, const char *name);
+int fdt_property(void *fdt, const char *name, const void *val, int len);
+static inline int fdt_property_u32(void *fdt, const char *name, uint32_t val)
+{
+ fdt32_t tmp = cpu_to_fdt32(val);
+ return fdt_property(fdt, name, &tmp, sizeof(tmp));
+}
+static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val)
+{
+ fdt64_t tmp = cpu_to_fdt64(val);
+ return fdt_property(fdt, name, &tmp, sizeof(tmp));
+}
+
+#ifndef SWIG /* Not available in Python */
+static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
+{
+ return fdt_property_u32(fdt, name, val);
+}
+#endif
+
+/**
+ * fdt_property_placeholder - add a new property and return a ptr to its value
+ *
+ * @fdt: pointer to the device tree blob
+ * @name: name of property to add
+ * @len: length of property value in bytes
+ * @valp: returns a pointer to where where the value should be placed
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_NOSPACE, standard meanings
+ */
+int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp);
+
+#define fdt_property_string(fdt, name, str) \
+ fdt_property(fdt, name, str, strlen(str)+1)
+int fdt_end_node(void *fdt);
+int fdt_finish(void *fdt);
+
+/**********************************************************************/
+/* Read-write functions */
+/**********************************************************************/
+
+int fdt_create_empty_tree(void *buf, int bufsize);
+int fdt_open_into(const void *fdt, void *buf, int bufsize);
+int fdt_pack(void *fdt);
+
+/**
+ * fdt_add_mem_rsv - add one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: 64-bit values (native endian)
+ *
+ * Adds a reserve map entry to the given blob reserving a region at
+ * address address of length size.
+ *
+ * This function will insert data into the reserve map and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new reservation entry
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size);
+
+/**
+ * fdt_del_mem_rsv - remove a memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @n: entry to remove
+ *
+ * fdt_del_mem_rsv() removes the n-th memory reserve map entry from
+ * the blob.
+ *
+ * This function will delete data from the reservation table and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there
+ * are less than n+1 reserve map entries)
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_mem_rsv(void *fdt, int n);
+
+/**
+ * fdt_set_name - change the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ * @name: name to give the node
+ *
+ * fdt_set_name() replaces the name (including unit address, if any)
+ * of the given node with the given string. NOTE: this function can't
+ * efficiently check if the new name is unique amongst the given
+ * node's siblings; results are undefined if this function is invoked
+ * with a name equal to one of the given node's siblings.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob
+ * to contain the new name
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_set_name(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_setprop - create or change a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to set the property value to
+ * @len: length of the property value
+ *
+ * fdt_setprop() sets the value of the named property in the given
+ * node to the given value and length, creating the property if it
+ * does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len);
+
+/**
+ * fdt_setprop_placeholder - allocate space for a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @len: length of the property value
+ * @prop_data: return pointer to property data
+ *
+ * fdt_setprop_placeholer() allocates the named property in the given node.
+ * If the property exists it is resized. In either case a pointer to the
+ * property data is returned.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
+ int len, void **prop_data);
+
+/**
+ * fdt_setprop_u32 - set a property to a 32-bit integer
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value for the property (native endian)
+ *
+ * fdt_setprop_u32() sets the value of the named property in the given
+ * node to the given 32-bit integer value (converting to big-endian if
+ * necessary), or creates a new property with that value if it does
+ * not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name,
+ uint32_t val)
+{
+ fdt32_t tmp = cpu_to_fdt32(val);
+ return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_u64 - set a property to a 64-bit integer
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 64-bit integer value for the property (native endian)
+ *
+ * fdt_setprop_u64() sets the value of the named property in the given
+ * node to the given 64-bit integer value (converting to big-endian if
+ * necessary), or creates a new property with that value if it does
+ * not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name,
+ uint64_t val)
+{
+ fdt64_t tmp = cpu_to_fdt64(val);
+ return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_cell - set a property to a single cell value
+ *
+ * This is an alternative name for fdt_setprop_u32()
+ */
+static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
+ uint32_t val)
+{
+ return fdt_setprop_u32(fdt, nodeoffset, name, val);
+}
+
+/**
+ * fdt_setprop_string - set a property to a string value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @str: string value for the property
+ *
+ * fdt_setprop_string() sets the value of the named property in the
+ * given node to the given string value (using the length of the
+ * string to determine the new length of the property), or creates a
+ * new property with that value if it does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+#define fdt_setprop_string(fdt, nodeoffset, name, str) \
+ fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+
+
+/**
+ * fdt_setprop_empty - set a property to an empty value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ *
+ * fdt_setprop_empty() sets the value of the named property in the
+ * given node to an empty (zero length) value, or creates a new empty
+ * property if it does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+#define fdt_setprop_empty(fdt, nodeoffset, name) \
+ fdt_setprop((fdt), (nodeoffset), (name), NULL, 0)
+
+/**
+ * fdt_appendprop - append to or create a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to append to
+ * @val: pointer to data to append to the property value
+ * @len: length of the data to append to the property value
+ *
+ * fdt_appendprop() appends the value to the named property in the
+ * given node, creating the property if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len);
+
+/**
+ * fdt_appendprop_u32 - append a 32-bit integer value to a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value to append to the property (native endian)
+ *
+ * fdt_appendprop_u32() appends the given 32-bit integer value
+ * (converting to big-endian if necessary) to the value of the named
+ * property in the given node, or creates a new property with that
+ * value if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_appendprop_u32(void *fdt, int nodeoffset,
+ const char *name, uint32_t val)
+{
+ fdt32_t tmp = cpu_to_fdt32(val);
+ return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_appendprop_u64 - append a 64-bit integer value to a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 64-bit integer value to append to the property (native endian)
+ *
+ * fdt_appendprop_u64() appends the given 64-bit integer value
+ * (converting to big-endian if necessary) to the value of the named
+ * property in the given node, or creates a new property with that
+ * value if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_appendprop_u64(void *fdt, int nodeoffset,
+ const char *name, uint64_t val)
+{
+ fdt64_t tmp = cpu_to_fdt64(val);
+ return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_appendprop_cell - append a single cell value to a property
+ *
+ * This is an alternative name for fdt_appendprop_u32()
+ */
+static inline int fdt_appendprop_cell(void *fdt, int nodeoffset,
+ const char *name, uint32_t val)
+{
+ return fdt_appendprop_u32(fdt, nodeoffset, name, val);
+}
+
+/**
+ * fdt_appendprop_string - append a string to a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @str: string value to append to the property
+ *
+ * fdt_appendprop_string() appends the given string to the value of
+ * the named property in the given node, or creates a new property
+ * with that value if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+#define fdt_appendprop_string(fdt, nodeoffset, name, str) \
+ fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+
+/**
+ * fdt_appendprop_addrrange - append a address range property
+ * @fdt: pointer to the device tree blob
+ * @parent: offset of the parent node
+ * @nodeoffset: offset of the node to add a property at
+ * @name: name of property
+ * @addr: start address of a given range
+ * @size: size of a given range
+ *
+ * fdt_appendprop_addrrange() appends an address range value (start
+ * address and size) to the value of the named property in the given
+ * node, or creates a new property with that value if it does not
+ * already exist.
+ * If "name" is not specified, a default "reg" is used.
+ * Cell sizes are determined by parent's #address-cells and #size-cells.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ * #address-cells property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADVALUE, addr or size doesn't fit to respective cells size
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain a new property
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
+ const char *name, uint64_t addr, uint64_t size);
+
+/**
+ * fdt_delprop - delete a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_del_property() will delete the given property.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_delprop(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_add_subnode_namelen - creates a new node based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_add_subnode(), but use only the first namelen
+ * characters of name as the name of the new node. This is useful for
+ * creating subnodes based on a portion of a larger string, such as a
+ * full path.
+ */
+#ifndef SWIG /* Not available in Python */
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+ const char *name, int namelen);
+#endif
+
+/**
+ * fdt_add_subnode - creates a new node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_add_subnode() creates a new node as a subnode of the node at
+ * structure block offset parentoffset, with the given name (which
+ * should include the unit address, if any).
+ *
+ * This function will insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+
+ * returns:
+ * structure block offset of the created nodeequested subnode (>=0), on
+ * success
+ * -FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE
+ * tag
+ * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of
+ * the given name
+ * -FDT_ERR_NOSPACE, if there is insufficient free space in the
+ * blob to contain the new node
+ * -FDT_ERR_NOSPACE
+ * -FDT_ERR_BADLAYOUT
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_del_node - delete a node (subtree)
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_del_node() will remove the given node, including all its
+ * subnodes if any, from the blob.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_node(void *fdt, int nodeoffset);
+
+/**
+ * fdt_overlay_apply - Applies a DT overlay on a base DT
+ * @fdt: pointer to the base device tree blob
+ * @fdto: pointer to the device tree overlay blob
+ *
+ * fdt_overlay_apply() will apply the given device tree overlay on the
+ * given base device tree.
+ *
+ * Expect the base device tree to be modified, even if the function
+ * returns an error.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there's not enough space in the base device tree
+ * -FDT_ERR_NOTFOUND, the overlay points to some inexistant nodes or
+ * properties in the base DT
+ * -FDT_ERR_BADPHANDLE,
+ * -FDT_ERR_BADOVERLAY,
+ * -FDT_ERR_NOPHANDLES,
+ * -FDT_ERR_INTERNAL,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADOFFSET,
+ * -FDT_ERR_BADPATH,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_overlay_apply(void *fdt, void *fdto);
+
+/**********************************************************************/
+/* Debugging / informational functions */
+/**********************************************************************/
+
+const char *fdt_strerror(int errval);
+
+#endif /* LIBFDT_H */
diff --git a/roms/opensbi/lib/utils/libfdt/libfdt_env.h b/roms/opensbi/lib/utils/libfdt/libfdt_env.h
new file mode 100644
index 000000000..bc3e75886
--- /dev/null
+++ b/roms/opensbi/lib/utils/libfdt/libfdt_env.h
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
+#ifndef LIBFDT_ENV_H
+#define LIBFDT_ENV_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ * Copyright 2012 Kim Phillips, Freescale Semiconductor.
+ */
+
+#include <sbi/sbi_string.h>
+#include <sbi/sbi_types.h>
+
+#define INT_MAX ((int)(~0U >> 1))
+#define UINT_MAX ((unsigned int)~0U)
+#define INT32_MAX INT_MAX
+#define UINT32_MAX UINT_MAX
+
+#ifdef __CHECKER__
+#define FDT_FORCE __attribute__((force))
+#define FDT_BITWISE __attribute__((bitwise))
+#else
+#define FDT_FORCE
+#define FDT_BITWISE
+#endif
+
+#define memmove sbi_memmove
+#define memcpy sbi_memcpy
+#define memcmp sbi_memcmp
+#define memchr sbi_memchr
+#define memset sbi_memset
+#define strchr sbi_strchr
+#define strrchr sbi_strrchr
+#define strcpy sbi_strcpy
+#define strcmp sbi_strcmp
+#define strncmp sbi_strncmp
+#define strlen sbi_strlen
+#define strnlen sbi_strnlen
+
+typedef uint16_t FDT_BITWISE fdt16_t;
+typedef uint32_t FDT_BITWISE fdt32_t;
+typedef uint64_t FDT_BITWISE fdt64_t;
+
+#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n])
+#define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1))
+#define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \
+ (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3))
+#define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \
+ (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \
+ (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \
+ (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7))
+
+static inline uint16_t fdt16_to_cpu(fdt16_t x)
+{
+ return (FDT_FORCE uint16_t)CPU_TO_FDT16(x);
+}
+static inline fdt16_t cpu_to_fdt16(uint16_t x)
+{
+ return (FDT_FORCE fdt16_t)CPU_TO_FDT16(x);
+}
+
+static inline uint32_t fdt32_to_cpu(fdt32_t x)
+{
+ return (FDT_FORCE uint32_t)CPU_TO_FDT32(x);
+}
+static inline fdt32_t cpu_to_fdt32(uint32_t x)
+{
+ return (FDT_FORCE fdt32_t)CPU_TO_FDT32(x);
+}
+
+static inline uint64_t fdt64_to_cpu(fdt64_t x)
+{
+ return (FDT_FORCE uint64_t)CPU_TO_FDT64(x);
+}
+static inline fdt64_t cpu_to_fdt64(uint64_t x)
+{
+ return (FDT_FORCE fdt64_t)CPU_TO_FDT64(x);
+}
+#undef CPU_TO_FDT64
+#undef CPU_TO_FDT32
+#undef CPU_TO_FDT16
+#undef EXTRACT_BYTE
+
+#ifdef __APPLE__
+#include <AvailabilityMacros.h>
+
+/* strnlen() is not available on Mac OS < 10.7 */
+# if !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED < \
+ MAC_OS_X_VERSION_10_7)
+
+#define strnlen fdt_strnlen
+
+/*
+ * fdt_strnlen: returns the length of a string or max_count - which ever is
+ * smallest.
+ * Input 1 string: the string whose size is to be determined
+ * Input 2 max_count: the maximum value returned by this function
+ * Output: length of the string or max_count (the smallest of the two)
+ */
+static inline size_t fdt_strnlen(const char *string, size_t max_count)
+{
+ const char *p = memchr(string, 0, max_count);
+ return p ? p - string : max_count;
+}
+
+#endif /* !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED <
+ MAC_OS_X_VERSION_10_7) */
+
+#endif /* __APPLE__ */
+
+#endif /* LIBFDT_ENV_H */
diff --git a/roms/opensbi/lib/utils/libfdt/libfdt_internal.h b/roms/opensbi/lib/utils/libfdt/libfdt_internal.h
new file mode 100644
index 000000000..d4e0bd49c
--- /dev/null
+++ b/roms/opensbi/lib/utils/libfdt/libfdt_internal.h
@@ -0,0 +1,173 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
+#ifndef LIBFDT_INTERNAL_H
+#define LIBFDT_INTERNAL_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ */
+#include <fdt.h>
+
+#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
+#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
+
+int32_t fdt_ro_probe_(const void *fdt);
+#define FDT_RO_PROBE(fdt) \
+ { \
+ int32_t totalsize_; \
+ if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \
+ return totalsize_; \
+ }
+
+int fdt_check_node_offset_(const void *fdt, int offset);
+int fdt_check_prop_offset_(const void *fdt, int offset);
+const char *fdt_find_string_(const char *strtab, int tabsize, const char *s);
+int fdt_node_end_offset_(void *fdt, int nodeoffset);
+
+static inline const void *fdt_offset_ptr_(const void *fdt, int offset)
+{
+ return (const char *)fdt + fdt_off_dt_struct(fdt) + offset;
+}
+
+static inline void *fdt_offset_ptr_w_(void *fdt, int offset)
+{
+ return (void *)(uintptr_t)fdt_offset_ptr_(fdt, offset);
+}
+
+static inline const struct fdt_reserve_entry *fdt_mem_rsv_(const void *fdt, int n)
+{
+ const struct fdt_reserve_entry *rsv_table =
+ (const struct fdt_reserve_entry *)
+ ((const char *)fdt + fdt_off_mem_rsvmap(fdt));
+
+ return rsv_table + n;
+}
+static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n)
+{
+ return (void *)(uintptr_t)fdt_mem_rsv_(fdt, 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 */
diff --git a/roms/opensbi/lib/utils/libfdt/objects.mk b/roms/opensbi/lib/utils/libfdt/objects.mk
new file mode 100644
index 000000000..8c060df9d
--- /dev/null
+++ b/roms/opensbi/lib/utils/libfdt/objects.mk
@@ -0,0 +1,16 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2019 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Atish Patra<atish.patra@wdc.com>
+#
+
+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))
+
+libsbiutils-objs-y += $(addprefix libfdt/,$(libfdt_files))
+libsbiutils-genflags-y += -I$(libsbiutils_dir)/libfdt/
diff --git a/roms/opensbi/lib/utils/libfdt/version.lds b/roms/opensbi/lib/utils/libfdt/version.lds
new file mode 100644
index 000000000..7ab85f1d9
--- /dev/null
+++ b/roms/opensbi/lib/utils/libfdt/version.lds
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
+LIBFDT_1.2 {
+ global:
+ fdt_next_node;
+ fdt_check_header;
+ fdt_move;
+ fdt_string;
+ fdt_num_mem_rsv;
+ fdt_get_mem_rsv;
+ fdt_subnode_offset_namelen;
+ fdt_subnode_offset;
+ fdt_path_offset_namelen;
+ fdt_path_offset;
+ fdt_get_name;
+ fdt_get_property_namelen;
+ fdt_get_property;
+ fdt_getprop_namelen;
+ fdt_getprop;
+ fdt_get_phandle;
+ fdt_get_alias_namelen;
+ fdt_get_alias;
+ fdt_get_path;
+ fdt_header_size;
+ fdt_supernode_atdepth_offset;
+ fdt_node_depth;
+ fdt_parent_offset;
+ fdt_node_offset_by_prop_value;
+ fdt_node_offset_by_phandle;
+ fdt_node_check_compatible;
+ fdt_node_offset_by_compatible;
+ fdt_setprop_inplace;
+ fdt_nop_property;
+ fdt_nop_node;
+ fdt_create;
+ fdt_add_reservemap_entry;
+ fdt_finish_reservemap;
+ fdt_begin_node;
+ fdt_property;
+ fdt_end_node;
+ fdt_finish;
+ fdt_open_into;
+ fdt_pack;
+ fdt_add_mem_rsv;
+ fdt_del_mem_rsv;
+ fdt_set_name;
+ fdt_setprop;
+ fdt_delprop;
+ fdt_add_subnode_namelen;
+ fdt_add_subnode;
+ fdt_del_node;
+ fdt_strerror;
+ fdt_offset_ptr;
+ fdt_next_tag;
+ fdt_appendprop;
+ fdt_create_empty_tree;
+ fdt_first_property_offset;
+ fdt_get_property_by_offset;
+ fdt_getprop_by_offset;
+ fdt_next_property_offset;
+ fdt_first_subnode;
+ fdt_next_subnode;
+ fdt_address_cells;
+ fdt_size_cells;
+ fdt_stringlist_contains;
+ fdt_stringlist_count;
+ fdt_stringlist_search;
+ fdt_stringlist_get;
+ fdt_resize;
+ fdt_overlay_apply;
+ fdt_get_string;
+ fdt_find_max_phandle;
+ fdt_generate_phandle;
+ fdt_check_full;
+ fdt_setprop_placeholder;
+ fdt_property_placeholder;
+ fdt_header_size_;
+ fdt_appendprop_addrrange;
+ fdt_setprop_inplace_namelen_partial;
+ fdt_create_with_flags;
+ local:
+ *;
+};
diff --git a/roms/opensbi/lib/utils/reset/fdt_reset.c b/roms/opensbi/lib/utils/reset/fdt_reset.c
new file mode 100644
index 000000000..dead8a342
--- /dev/null
+++ b/roms/opensbi/lib/utils/reset/fdt_reset.c
@@ -0,0 +1,62 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/sbi_scratch.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/reset/fdt_reset.h>
+
+extern struct fdt_reset fdt_reset_sifive;
+extern struct fdt_reset fdt_reset_htif;
+
+static struct fdt_reset *reset_drivers[] = {
+ &fdt_reset_sifive,
+ &fdt_reset_htif,
+};
+
+static struct fdt_reset *current_driver = NULL;
+
+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)
+ current_driver->system_reset(reset_type, reset_reason);
+}
+
+int fdt_reset_init(void)
+{
+ int pos, noff, rc;
+ struct fdt_reset *drv;
+ const struct fdt_match *match;
+ void *fdt = sbi_scratch_thishart_arg1_ptr();
+
+ for (pos = 0; pos < array_size(reset_drivers); pos++) {
+ drv = reset_drivers[pos];
+
+ noff = fdt_find_match(fdt, -1, drv->match_table, &match);
+ if (noff < 0)
+ continue;
+
+ if (drv->init) {
+ rc = drv->init(fdt, noff, match);
+ if (rc)
+ return rc;
+ }
+ current_driver = drv;
+ break;
+ }
+
+ return 0;
+}
diff --git a/roms/opensbi/lib/utils/reset/fdt_reset_htif.c b/roms/opensbi/lib/utils/reset/fdt_reset_htif.c
new file mode 100644
index 000000000..587e7d65e
--- /dev/null
+++ b/roms/opensbi/lib/utils/reset/fdt_reset_htif.c
@@ -0,0 +1,23 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi_utils/reset/fdt_reset.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/sys/htif.h>
+
+static const struct fdt_match htif_reset_match[] = {
+ { .compatible = "ucb,htif0" },
+ { },
+};
+
+struct fdt_reset fdt_reset_htif = {
+ .match_table = htif_reset_match,
+ .system_reset_check = htif_system_reset_check,
+ .system_reset = htif_system_reset
+};
diff --git a/roms/opensbi/lib/utils/reset/fdt_reset_sifive.c b/roms/opensbi/lib/utils/reset/fdt_reset_sifive.c
new file mode 100644
index 000000000..38b520c48
--- /dev/null
+++ b/roms/opensbi/lib/utils/reset/fdt_reset_sifive.c
@@ -0,0 +1,38 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/sbi_scratch.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/reset/fdt_reset.h>
+#include <sbi_utils/sys/sifive_test.h>
+
+static int sifive_test_reset_init(void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ int rc;
+ unsigned long addr;
+
+ rc = fdt_get_node_addr_size(fdt, nodeoff, &addr, NULL);
+ if (rc)
+ return rc;
+
+ return sifive_test_init(addr);
+}
+
+static const struct fdt_match sifive_test_reset_match[] = {
+ { .compatible = "sifive,test1" },
+ { },
+};
+
+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
+};
diff --git a/roms/opensbi/lib/utils/reset/objects.mk b/roms/opensbi/lib/utils/reset/objects.mk
new file mode 100644
index 000000000..b447261f8
--- /dev/null
+++ b/roms/opensbi/lib/utils/reset/objects.mk
@@ -0,0 +1,12 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2020 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+
+libsbiutils-objs-y += reset/fdt_reset.o
+libsbiutils-objs-y += reset/fdt_reset_htif.o
+libsbiutils-objs-y += reset/fdt_reset_sifive.o
diff --git a/roms/opensbi/lib/utils/serial/fdt_serial.c b/roms/opensbi/lib/utils/serial/fdt_serial.c
new file mode 100644
index 000000000..b9ce67ef1
--- /dev/null
+++ b/roms/opensbi/lib/utils/serial/fdt_serial.c
@@ -0,0 +1,111 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <libfdt.h>
+#include <sbi/sbi_scratch.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/serial/fdt_serial.h>
+
+extern struct fdt_serial fdt_serial_uart8250;
+extern struct fdt_serial fdt_serial_sifive;
+extern struct fdt_serial fdt_serial_htif;
+extern struct fdt_serial fdt_serial_shakti;
+
+static struct fdt_serial *serial_drivers[] = {
+ &fdt_serial_uart8250,
+ &fdt_serial_sifive,
+ &fdt_serial_htif,
+ &fdt_serial_shakti,
+};
+
+static void dummy_putc(char ch)
+{
+}
+
+static int dummy_getc(void)
+{
+ return -1;
+}
+
+static struct fdt_serial dummy = {
+ .match_table = NULL,
+ .init = NULL,
+ .putc = dummy_putc,
+ .getc = dummy_getc,
+};
+
+static struct fdt_serial *current_driver = &dummy;
+
+void fdt_serial_putc(char ch)
+{
+ current_driver->putc(ch);
+}
+
+int fdt_serial_getc(void)
+{
+ return current_driver->getc();
+}
+
+int fdt_serial_init(void)
+{
+ const void *prop;
+ struct fdt_serial *drv;
+ const struct fdt_match *match;
+ int pos, noff = -1, len, coff, rc;
+ void *fdt = sbi_scratch_thishart_arg1_ptr();
+
+ /* Find offset of node pointed by stdout-path */
+ coff = fdt_path_offset(fdt, "/chosen");
+ if (-1 < coff) {
+ prop = fdt_getprop(fdt, coff, "stdout-path", &len);
+ if (prop && len)
+ noff = fdt_path_offset(fdt, prop);
+ }
+
+ /* First check DT node pointed by stdout-path */
+ for (pos = 0; pos < array_size(serial_drivers) && -1 < noff; pos++) {
+ drv = serial_drivers[pos];
+
+ match = fdt_match_node(fdt, noff, drv->match_table);
+ if (!match)
+ continue;
+
+ if (drv->init) {
+ rc = drv->init(fdt, noff, match);
+ if (rc)
+ return rc;
+ }
+ current_driver = drv;
+ break;
+ }
+
+ /* Check if we found desired driver */
+ if (current_driver != &dummy)
+ goto done;
+
+ /* Lastly check all DT nodes */
+ for (pos = 0; pos < array_size(serial_drivers); pos++) {
+ drv = serial_drivers[pos];
+
+ noff = fdt_find_match(fdt, -1, drv->match_table, &match);
+ if (noff < 0)
+ continue;
+
+ if (drv->init) {
+ rc = drv->init(fdt, noff, match);
+ if (rc)
+ return rc;
+ }
+ current_driver = drv;
+ break;
+ }
+
+done:
+ return 0;
+}
diff --git a/roms/opensbi/lib/utils/serial/fdt_serial_htif.c b/roms/opensbi/lib/utils/serial/fdt_serial_htif.c
new file mode 100644
index 000000000..32d695317
--- /dev/null
+++ b/roms/opensbi/lib/utils/serial/fdt_serial_htif.c
@@ -0,0 +1,24 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/serial/fdt_serial.h>
+#include <sbi_utils/sys/htif.h>
+
+static const struct fdt_match serial_htif_match[] = {
+ { .compatible = "ucb,htif0" },
+ { },
+};
+
+struct fdt_serial fdt_serial_htif = {
+ .match_table = serial_htif_match,
+ .init = NULL,
+ .getc = htif_getc,
+ .putc = htif_putc
+};
diff --git a/roms/opensbi/lib/utils/serial/fdt_serial_shakti.c b/roms/opensbi/lib/utils/serial/fdt_serial_shakti.c
new file mode 100644
index 000000000..c6385a577
--- /dev/null
+++ b/roms/opensbi/lib/utils/serial/fdt_serial_shakti.c
@@ -0,0 +1,35 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Vijai Kumar K <vijai@behindbytes.com>
+ *
+ */
+
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/serial/fdt_serial.h>
+#include <sbi_utils/serial/shakti-uart.h>
+
+static int serial_shakti_init(void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ int rc;
+ struct platform_uart_data uart;
+
+ rc = fdt_parse_shakti_uart_node(fdt, nodeoff, &uart);
+ if (rc)
+ return rc;
+
+ return shakti_uart_init(uart.addr, uart.freq, uart.baud);
+}
+
+static const struct fdt_match serial_shakti_match[] = {
+ { .compatible = "shakti,uart0" },
+ { },
+};
+
+struct fdt_serial fdt_serial_shakti = {
+ .match_table = serial_shakti_match,
+ .init = serial_shakti_init,
+ .getc = shakti_uart_getc,
+ .putc = shakti_uart_putc
+};
diff --git a/roms/opensbi/lib/utils/serial/fdt_serial_sifive.c b/roms/opensbi/lib/utils/serial/fdt_serial_sifive.c
new file mode 100644
index 000000000..9e487a2b5
--- /dev/null
+++ b/roms/opensbi/lib/utils/serial/fdt_serial_sifive.c
@@ -0,0 +1,38 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/serial/fdt_serial.h>
+#include <sbi_utils/serial/sifive-uart.h>
+
+static int serial_sifive_init(void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ int rc;
+ struct platform_uart_data uart;
+
+ rc = fdt_parse_sifive_uart_node(fdt, nodeoff, &uart);
+ if (rc)
+ return rc;
+
+ return sifive_uart_init(uart.addr, uart.freq, uart.baud);
+}
+
+static const struct fdt_match serial_sifive_match[] = {
+ { .compatible = "sifive,fu540-c000-uart" },
+ { .compatible = "sifive,uart0" },
+ { },
+};
+
+struct fdt_serial fdt_serial_sifive = {
+ .match_table = serial_sifive_match,
+ .init = serial_sifive_init,
+ .getc = sifive_uart_getc,
+ .putc = sifive_uart_putc
+};
diff --git a/roms/opensbi/lib/utils/serial/fdt_serial_uart8250.c b/roms/opensbi/lib/utils/serial/fdt_serial_uart8250.c
new file mode 100644
index 000000000..5030b823a
--- /dev/null
+++ b/roms/opensbi/lib/utils/serial/fdt_serial_uart8250.c
@@ -0,0 +1,39 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/serial/fdt_serial.h>
+#include <sbi_utils/serial/uart8250.h>
+
+static int serial_uart8250_init(void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ int rc;
+ struct platform_uart_data uart;
+
+ rc = fdt_parse_uart8250_node(fdt, nodeoff, &uart);
+ if (rc)
+ return rc;
+
+ return uart8250_init(uart.addr, uart.freq, uart.baud,
+ uart.reg_shift, uart.reg_io_width);
+}
+
+static const struct fdt_match serial_uart8250_match[] = {
+ { .compatible = "ns16550" },
+ { .compatible = "ns16550a" },
+ { },
+};
+
+struct fdt_serial fdt_serial_uart8250 = {
+ .match_table = serial_uart8250_match,
+ .init = serial_uart8250_init,
+ .getc = uart8250_getc,
+ .putc = uart8250_putc
+};
diff --git a/roms/opensbi/lib/utils/serial/objects.mk b/roms/opensbi/lib/utils/serial/objects.mk
new file mode 100644
index 000000000..c0746f07e
--- /dev/null
+++ b/roms/opensbi/lib/utils/serial/objects.mk
@@ -0,0 +1,17 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2019 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+
+libsbiutils-objs-y += serial/fdt_serial.o
+libsbiutils-objs-y += serial/fdt_serial_htif.o
+libsbiutils-objs-y += serial/fdt_serial_shakti.o
+libsbiutils-objs-y += serial/fdt_serial_sifive.o
+libsbiutils-objs-y += serial/fdt_serial_uart8250.o
+libsbiutils-objs-y += serial/shakti-uart.o
+libsbiutils-objs-y += serial/sifive-uart.o
+libsbiutils-objs-y += serial/uart8250.o
diff --git a/roms/opensbi/lib/utils/serial/shakti-uart.c b/roms/opensbi/lib/utils/serial/shakti-uart.c
new file mode 100644
index 000000000..7c1148ee1
--- /dev/null
+++ b/roms/opensbi/lib/utils/serial/shakti-uart.c
@@ -0,0 +1,48 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Vijai Kumar K <vijai@behindbytes.com>
+ */
+
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_console.h>
+#include <sbi_utils/serial/shakti-uart.h>
+
+#define REG_BAUD 0x00
+#define REG_TX 0x04
+#define REG_RX 0x08
+#define REG_STATUS 0x0C
+#define REG_DELAY 0x10
+#define REG_CONTROL 0x14
+#define REG_INT_EN 0x18
+#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) & UART_TX_FULL))
+ ;
+ writeb(ch, uart_base + REG_TX);
+}
+
+int shakti_uart_getc(void)
+{
+ u16 status = readw(uart_base + REG_STATUS);
+ if (status & UART_RX_FULL)
+ return readb(uart_base + REG_RX);
+ return -1;
+}
+
+int shakti_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
+{
+ uart_base = (volatile void *)base;
+ u16 baud = (u16)(in_freq/(16 * baudrate));
+ writew(baud, uart_base + REG_BAUD);
+
+ return 0;
+}
diff --git a/roms/opensbi/lib/utils/serial/sifive-uart.c b/roms/opensbi/lib/utils/serial/sifive-uart.c
new file mode 100644
index 000000000..72c8a6249
--- /dev/null
+++ b/roms/opensbi/lib/utils/serial/sifive-uart.c
@@ -0,0 +1,102 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_console.h>
+#include <sbi_utils/serial/sifive-uart.h>
+
+/* clang-format off */
+
+#define UART_REG_TXFIFO 0
+#define UART_REG_RXFIFO 1
+#define UART_REG_TXCTRL 2
+#define UART_REG_RXCTRL 3
+#define UART_REG_IE 4
+#define UART_REG_IP 5
+#define UART_REG_DIV 6
+
+#define UART_TXFIFO_FULL 0x80000000
+#define UART_RXFIFO_EMPTY 0x80000000
+#define UART_RXFIFO_DATA 0x000000ff
+#define UART_TXCTRL_TXEN 0x1
+#define UART_RXCTRL_RXEN 0x1
+
+/* clang-format on */
+
+static volatile void *uart_base;
+static u32 uart_in_freq;
+static u32 uart_baudrate;
+
+/**
+ * Find minimum divisor divides in_freq to max_target_hz;
+ * Based on uart driver n SiFive FSBL.
+ *
+ * f_baud = f_in / (div + 1) => div = (f_in / f_baud) - 1
+ * The nearest integer solution requires rounding up as to not exceed max_target_hz.
+ * div = ceil(f_in / f_baud) - 1
+ * = floor((f_in - 1 + f_baud) / f_baud) - 1
+ * This should not overflow as long as (f_in - 1 + f_baud) does not exceed
+ * 2^32 - 1, which is unlikely since we represent frequencies in kHz.
+ */
+static inline unsigned int uart_min_clk_divisor(uint64_t in_freq,
+ uint64_t max_target_hz)
+{
+ uint64_t quotient = (in_freq + max_target_hz - 1) / (max_target_hz);
+ /* Avoid underflow */
+ if (quotient == 0) {
+ return 0;
+ } else {
+ return quotient - 1;
+ }
+}
+
+static u32 get_reg(u32 num)
+{
+ return readl(uart_base + (num * 0x4));
+}
+
+static void set_reg(u32 num, u32 val)
+{
+ writel(val, uart_base + (num * 0x4));
+}
+
+void sifive_uart_putc(char ch)
+{
+ while (get_reg(UART_REG_TXFIFO) & UART_TXFIFO_FULL)
+ ;
+
+ set_reg(UART_REG_TXFIFO, ch);
+}
+
+int sifive_uart_getc(void)
+{
+ u32 ret = get_reg(UART_REG_RXFIFO);
+ if (!(ret & UART_RXFIFO_EMPTY))
+ return ret & UART_RXFIFO_DATA;
+ return -1;
+}
+
+int sifive_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
+{
+ uart_base = (volatile void *)base;
+ uart_in_freq = in_freq;
+ uart_baudrate = baudrate;
+
+ /* Configure baudrate */
+ if (in_freq)
+ set_reg(UART_REG_DIV, uart_min_clk_divisor(in_freq, baudrate));
+ /* Disable interrupts */
+ set_reg(UART_REG_IE, 0);
+ /* Enable TX */
+ set_reg(UART_REG_TXCTRL, UART_TXCTRL_TXEN);
+ /* Enable Rx */
+ set_reg(UART_REG_RXCTRL, UART_RXCTRL_RXEN);
+
+ return 0;
+}
diff --git a/roms/opensbi/lib/utils/serial/uart8250.c b/roms/opensbi/lib/utils/serial/uart8250.c
new file mode 100644
index 000000000..9635ba863
--- /dev/null
+++ b/roms/opensbi/lib/utils/serial/uart8250.c
@@ -0,0 +1,125 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/riscv_io.h>
+#include <sbi_utils/serial/uart8250.h>
+
+/* clang-format off */
+
+#define UART_RBR_OFFSET 0 /* In: Recieve Buffer Register */
+#define UART_THR_OFFSET 0 /* Out: Transmitter Holding Register */
+#define UART_DLL_OFFSET 0 /* Out: Divisor Latch Low */
+#define UART_IER_OFFSET 1 /* I/O: Interrupt Enable Register */
+#define UART_DLM_OFFSET 1 /* Out: Divisor Latch High */
+#define UART_FCR_OFFSET 2 /* Out: FIFO Control Register */
+#define UART_IIR_OFFSET 2 /* I/O: Interrupt Identification Register */
+#define UART_LCR_OFFSET 3 /* Out: Line Control Register */
+#define UART_MCR_OFFSET 4 /* Out: Modem Control Register */
+#define UART_LSR_OFFSET 5 /* In: Line Status Register */
+#define UART_MSR_OFFSET 6 /* In: Modem Status Register */
+#define UART_SCR_OFFSET 7 /* I/O: Scratch Register */
+#define UART_MDR1_OFFSET 8 /* I/O: Mode Register */
+
+#define UART_LSR_FIFOE 0x80 /* Fifo error */
+#define UART_LSR_TEMT 0x40 /* Transmitter empty */
+#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
+#define UART_LSR_BI 0x10 /* Break interrupt indicator */
+#define UART_LSR_FE 0x08 /* Frame error indicator */
+#define UART_LSR_PE 0x04 /* Parity error indicator */
+#define UART_LSR_OE 0x02 /* Overrun error indicator */
+#define UART_LSR_DR 0x01 /* Receiver data ready */
+#define UART_LSR_BRK_ERROR_BITS 0x1E /* BI, FE, PE, OE bits */
+
+/* clang-format on */
+
+static volatile void *uart8250_base;
+static u32 uart8250_in_freq;
+static u32 uart8250_baudrate;
+static u32 uart8250_reg_width;
+static u32 uart8250_reg_shift;
+
+static u32 get_reg(u32 num)
+{
+ u32 offset = num << uart8250_reg_shift;
+
+ if (uart8250_reg_width == 1)
+ return readb(uart8250_base + offset);
+ else if (uart8250_reg_width == 2)
+ return readw(uart8250_base + offset);
+ else
+ return readl(uart8250_base + offset);
+}
+
+static void set_reg(u32 num, u32 val)
+{
+ u32 offset = num << uart8250_reg_shift;
+
+ if (uart8250_reg_width == 1)
+ writeb(val, uart8250_base + offset);
+ else if (uart8250_reg_width == 2)
+ writew(val, uart8250_base + offset);
+ else
+ writel(val, uart8250_base + offset);
+}
+
+void uart8250_putc(char ch)
+{
+ while ((get_reg(UART_LSR_OFFSET) & UART_LSR_THRE) == 0)
+ ;
+
+ set_reg(UART_THR_OFFSET, ch);
+}
+
+int uart8250_getc(void)
+{
+ if (get_reg(UART_LSR_OFFSET) & UART_LSR_DR)
+ return get_reg(UART_RBR_OFFSET);
+ return -1;
+}
+
+int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
+ u32 reg_width)
+{
+ u16 bdiv;
+
+ uart8250_base = (volatile void *)base;
+ uart8250_reg_shift = reg_shift;
+ uart8250_reg_width = reg_width;
+ uart8250_in_freq = in_freq;
+ uart8250_baudrate = baudrate;
+
+ bdiv = uart8250_in_freq / (16 * uart8250_baudrate);
+
+ /* Disable all interrupts */
+ set_reg(UART_IER_OFFSET, 0x00);
+ /* Enable DLAB */
+ set_reg(UART_LCR_OFFSET, 0x80);
+
+ if (bdiv) {
+ /* Set divisor low byte */
+ set_reg(UART_DLL_OFFSET, bdiv & 0xff);
+ /* Set divisor high byte */
+ set_reg(UART_DLM_OFFSET, (bdiv >> 8) & 0xff);
+ }
+
+ /* 8 bits, no parity, one stop bit */
+ set_reg(UART_LCR_OFFSET, 0x03);
+ /* Enable FIFO */
+ set_reg(UART_FCR_OFFSET, 0x01);
+ /* No modem control DTR RTS */
+ set_reg(UART_MCR_OFFSET, 0x00);
+ /* Clear line status */
+ get_reg(UART_LSR_OFFSET);
+ /* Read receive buffer */
+ get_reg(UART_RBR_OFFSET);
+ /* Set scratchpad */
+ set_reg(UART_SCR_OFFSET, 0x00);
+
+ return 0;
+}
diff --git a/roms/opensbi/lib/utils/sys/clint.c b/roms/opensbi/lib/utils/sys/clint.c
new file mode 100644
index 000000000..7a392aad8
--- /dev/null
+++ b/roms/opensbi/lib/utils/sys/clint.c
@@ -0,0 +1,203 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_atomic.h>
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_hartmask.h>
+#include <sbi_utils/sys/clint.h>
+
+#define CLINT_IPI_OFF 0
+#define CLINT_TIME_CMP_OFF 0x4000
+#define CLINT_TIME_VAL_OFF 0xbff8
+
+static struct clint_data *clint_ipi_hartid2data[SBI_HARTMASK_MAX_BITS];
+
+void clint_ipi_send(u32 target_hart)
+{
+ struct clint_data *clint;
+
+ if (SBI_HARTMASK_MAX_BITS <= target_hart)
+ return;
+ clint = clint_ipi_hartid2data[target_hart];
+ if (!clint)
+ return;
+
+ /* Set CLINT IPI */
+ writel(1, &clint->ipi[target_hart - clint->first_hartid]);
+}
+
+void clint_ipi_clear(u32 target_hart)
+{
+ struct clint_data *clint;
+
+ if (SBI_HARTMASK_MAX_BITS <= target_hart)
+ return;
+ clint = clint_ipi_hartid2data[target_hart];
+ if (!clint)
+ return;
+
+ /* Clear CLINT IPI */
+ writel(0, &clint->ipi[target_hart - clint->first_hartid]);
+}
+
+int clint_warm_ipi_init(void)
+{
+ /* Clear CLINT IPI for current HART */
+ clint_ipi_clear(current_hartid());
+
+ return 0;
+}
+
+int clint_cold_ipi_init(struct clint_data *clint)
+{
+ u32 i;
+
+ if (!clint)
+ return SBI_EINVAL;
+
+ /* Initialize private data */
+ clint->ipi = (void *)clint->addr;
+
+ /* Update IPI hartid table */
+ for (i = 0; i < clint->hart_count; i++)
+ clint_ipi_hartid2data[clint->first_hartid + i] = clint;
+
+ return 0;
+}
+
+static struct clint_data *clint_timer_hartid2data[SBI_HARTMASK_MAX_BITS];
+
+#if __riscv_xlen != 32
+static u64 clint_time_rd64(volatile u64 *addr)
+{
+ return readq_relaxed(addr);
+}
+
+static void clint_time_wr64(u64 value, volatile u64 *addr)
+{
+ writeq_relaxed(value, addr);
+}
+#endif
+
+static u64 clint_time_rd32(volatile u64 *addr)
+{
+ u32 lo, hi;
+
+ do {
+ hi = readl_relaxed((u32 *)addr + 1);
+ lo = readl_relaxed((u32 *)addr);
+ } while (hi != readl_relaxed((u32 *)addr + 1));
+
+ return ((u64)hi << 32) | (u64)lo;
+}
+
+static void clint_time_wr32(u64 value, volatile u64 *addr)
+{
+ u32 mask = -1U;
+
+ writel_relaxed(value & mask, (void *)(addr));
+ writel_relaxed(value >> 32, (void *)(addr) + 0x04);
+}
+
+u64 clint_timer_value(void)
+{
+ struct clint_data *clint = clint_timer_hartid2data[current_hartid()];
+
+ /* Read CLINT Time Value */
+ return clint->time_rd(clint->time_val) + clint->time_delta;
+}
+
+void clint_timer_event_stop(void)
+{
+ u32 target_hart = current_hartid();
+ struct clint_data *clint = clint_timer_hartid2data[target_hart];
+
+ /* Clear CLINT Time Compare */
+ clint->time_wr(-1ULL,
+ &clint->time_cmp[target_hart - clint->first_hartid]);
+}
+
+void clint_timer_event_start(u64 next_event)
+{
+ u32 target_hart = current_hartid();
+ struct clint_data *clint = clint_timer_hartid2data[target_hart];
+
+ /* Program CLINT Time Compare */
+ clint->time_wr(next_event - clint->time_delta,
+ &clint->time_cmp[target_hart - clint->first_hartid]);
+}
+
+int clint_warm_timer_init(void)
+{
+ u64 v1, v2, mv;
+ u32 target_hart = current_hartid();
+ struct clint_data *reference;
+ struct clint_data *clint = clint_timer_hartid2data[target_hart];
+
+ if (!clint)
+ return SBI_ENODEV;
+
+ /*
+ * Compute delta if reference available
+ *
+ * We deliberately compute time_delta in warm init so that time_delta
+ * is computed on a HART which is going to use given CLINT. We use
+ * atomic flag timer_delta_computed to ensure that only one HART does
+ * time_delta computation.
+ */
+ if (clint->time_delta_reference) {
+ reference = clint->time_delta_reference;
+ if (!atomic_raw_xchg_ulong(&clint->time_delta_computed, 1)) {
+ v1 = clint->time_rd(clint->time_val);
+ mv = reference->time_rd(reference->time_val);
+ v2 = clint->time_rd(clint->time_val);
+ clint->time_delta = mv - ((v1 / 2) + (v2 / 2));
+ }
+ }
+
+ /* Clear CLINT Time Compare */
+ clint->time_wr(-1ULL,
+ &clint->time_cmp[target_hart - clint->first_hartid]);
+
+ return 0;
+}
+
+int clint_cold_timer_init(struct clint_data *clint,
+ struct clint_data *reference)
+{
+ u32 i;
+
+ if (!clint)
+ return SBI_EINVAL;
+
+ /* Initialize private data */
+ clint->time_delta_reference = reference;
+ clint->time_delta_computed = 0;
+ clint->time_delta = 0;
+ clint->time_val = (u64 *)((void *)clint->addr + CLINT_TIME_VAL_OFF);
+ clint->time_cmp = (u64 *)((void *)clint->addr + CLINT_TIME_CMP_OFF);
+ clint->time_rd = clint_time_rd32;
+ clint->time_wr = clint_time_wr32;
+
+ /* Override read/write accessors for 64bit MMIO */
+#if __riscv_xlen != 32
+ if (clint->has_64bit_mmio) {
+ clint->time_rd = clint_time_rd64;
+ clint->time_wr = clint_time_wr64;
+ }
+#endif
+
+ /* Update timer hartid table */
+ for (i = 0; i < clint->hart_count; i++)
+ clint_timer_hartid2data[clint->first_hartid + i] = clint;
+
+ return 0;
+}
diff --git a/roms/opensbi/lib/utils/sys/htif.c b/roms/opensbi/lib/utils/sys/htif.c
new file mode 100644
index 000000000..fd70fb981
--- /dev/null
+++ b/roms/opensbi/lib/utils/sys/htif.c
@@ -0,0 +1,154 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2010-2020, The Regents of the University of California
+ * (Regents). All Rights Reserved.
+ */
+
+#include <sbi/riscv_locks.h>
+#include <sbi_utils/sys/htif.h>
+
+#define HTIF_DATA_BITS 48
+#define HTIF_DATA_MASK ((1ULL << HTIF_DATA_BITS) - 1)
+#define HTIF_DATA_SHIFT 0
+#define HTIF_CMD_BITS 8
+#define HTIF_CMD_MASK ((1ULL << HTIF_CMD_BITS) - 1)
+#define HTIF_CMD_SHIFT 48
+#define HTIF_DEV_BITS 8
+#define HTIF_DEV_MASK ((1ULL << HTIF_DEV_BITS) - 1)
+#define HTIF_DEV_SHIFT 56
+
+#define HTIF_DEV_SYSTEM 0
+#define HTIF_DEV_CONSOLE 1
+
+#define HTIF_CONSOLE_CMD_GETC 0
+#define HTIF_CONSOLE_CMD_PUTC 1
+
+#if __riscv_xlen == 64
+# define TOHOST_CMD(dev, cmd, payload) \
+ (((uint64_t)(dev) << HTIF_DEV_SHIFT) | \
+ ((uint64_t)(cmd) << HTIF_CMD_SHIFT) | \
+ (uint64_t)(payload))
+#else
+# define TOHOST_CMD(dev, cmd, payload) ({ \
+ if ((dev) || (cmd)) __builtin_trap(); \
+ (payload); })
+#endif
+#define FROMHOST_DEV(fromhost_value) \
+ ((uint64_t)((fromhost_value) >> HTIF_DEV_SHIFT) & HTIF_DEV_MASK)
+#define FROMHOST_CMD(fromhost_value) \
+ ((uint64_t)((fromhost_value) >> HTIF_CMD_SHIFT) & HTIF_CMD_MASK)
+#define FROMHOST_DATA(fromhost_value) \
+ ((uint64_t)((fromhost_value) >> HTIF_DATA_SHIFT) & HTIF_DATA_MASK)
+
+#define PK_SYS_write 64
+
+volatile uint64_t tohost __attribute__((section(".htif")));
+volatile uint64_t fromhost __attribute__((section(".htif")));
+static int htif_console_buf;
+static spinlock_t htif_lock = SPIN_LOCK_INITIALIZER;
+
+static void __check_fromhost()
+{
+ uint64_t fh = fromhost;
+ if (!fh)
+ return;
+ fromhost = 0;
+
+ /* this should be from the console */
+ if (FROMHOST_DEV(fh) != HTIF_DEV_CONSOLE)
+ __builtin_trap();
+ switch (FROMHOST_CMD(fh)) {
+ case HTIF_CONSOLE_CMD_GETC:
+ htif_console_buf = 1 + (uint8_t)FROMHOST_DATA(fh);
+ break;
+ case HTIF_CONSOLE_CMD_PUTC:
+ break;
+ default:
+ __builtin_trap();
+ }
+}
+
+static void __set_tohost(uint64_t dev, uint64_t cmd, uint64_t data)
+{
+ while (tohost)
+ __check_fromhost();
+ tohost = TOHOST_CMD(dev, cmd, data);
+}
+
+#if __riscv_xlen == 32
+static void do_tohost_fromhost(uint64_t dev, uint64_t cmd, uint64_t data)
+{
+ spin_lock(&htif_lock);
+
+ __set_tohost(HTIF_DEV_SYSTEM, cmd, data);
+
+ while (1) {
+ uint64_t fh = fromhost;
+ if (fh) {
+ if (FROMHOST_DEV(fh) == HTIF_DEV_SYSTEM &&
+ FROMHOST_CMD(fh) == cmd) {
+ fromhost = 0;
+ break;
+ }
+ __check_fromhost();
+ }
+ }
+
+ spin_unlock(&htif_lock);
+}
+
+void htif_putc(char ch)
+{
+ /* HTIF devices are not supported on RV32, so do a proxy write call */
+ volatile uint64_t magic_mem[8];
+ magic_mem[0] = PK_SYS_write;
+ magic_mem[1] = HTIF_DEV_CONSOLE;
+ magic_mem[2] = (uint64_t)(uintptr_t)&ch;
+ magic_mem[3] = HTIF_CONSOLE_CMD_PUTC;
+ do_tohost_fromhost(HTIF_DEV_SYSTEM, 0, (uint64_t)(uintptr_t)magic_mem);
+}
+#else
+void htif_putc(char ch)
+{
+ spin_lock(&htif_lock);
+ __set_tohost(HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_PUTC, ch);
+ spin_unlock(&htif_lock);
+}
+#endif
+
+int htif_getc(void)
+{
+ int ch;
+
+#if __riscv_xlen == 32
+ /* HTIF devices are not supported on RV32 */
+ return -1;
+#endif
+
+ spin_lock(&htif_lock);
+
+ __check_fromhost();
+ ch = htif_console_buf;
+ if (ch >= 0) {
+ htif_console_buf = -1;
+ __set_tohost(HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_GETC, 0);
+ }
+
+ spin_unlock(&htif_lock);
+
+ return ch - 1;
+}
+
+int htif_system_reset_check(u32 type, u32 reason)
+{
+ return 1;
+}
+
+void htif_system_reset(u32 type, u32 reason)
+{
+ while (1) {
+ fromhost = 0;
+ tohost = 1;
+ }
+}
diff --git a/roms/opensbi/lib/utils/sys/objects.mk b/roms/opensbi/lib/utils/sys/objects.mk
new file mode 100644
index 000000000..7878ca8b4
--- /dev/null
+++ b/roms/opensbi/lib/utils/sys/objects.mk
@@ -0,0 +1,12 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2019 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+
+libsbiutils-objs-y += sys/clint.o
+libsbiutils-objs-y += sys/htif.o
+libsbiutils-objs-y += sys/sifive_test.o
diff --git a/roms/opensbi/lib/utils/sys/sifive_test.c b/roms/opensbi/lib/utils/sys/sifive_test.c
new file mode 100644
index 000000000..fdf31690c
--- /dev/null
+++ b/roms/opensbi/lib/utils/sys/sifive_test.c
@@ -0,0 +1,57 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_ecall_interface.h>
+#include <sbi_utils/sys/sifive_test.h>
+
+#define FINISHER_FAIL 0x3333
+#define FINISHER_PASS 0x5555
+#define FINISHER_RESET 0x7777
+
+static void *sifive_test_base;
+
+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_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_SRST_RESET_TYPE_COLD_REBOOT:
+ case SBI_SRST_RESET_TYPE_WARM_REBOOT:
+ writew(FINISHER_RESET, sifive_test_base);
+ break;
+ }
+}
+
+int sifive_test_init(unsigned long base)
+{
+ sifive_test_base = (void *)base;
+
+ return 0;
+}
diff --git a/roms/opensbi/lib/utils/timer/fdt_timer.c b/roms/opensbi/lib/utils/timer/fdt_timer.c
new file mode 100644
index 000000000..d1d0e0ce1
--- /dev/null
+++ b/roms/opensbi/lib/utils/timer/fdt_timer.c
@@ -0,0 +1,112 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/sbi_scratch.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/timer/fdt_timer.h>
+
+extern struct fdt_timer fdt_timer_clint;
+
+static struct fdt_timer *timer_drivers[] = {
+ &fdt_timer_clint
+};
+
+static u64 dummy_value(void)
+{
+ return 0;
+}
+
+static void dummy_event_stop(void)
+{
+}
+
+static void dummy_event_start(u64 next_event)
+{
+}
+
+static struct fdt_timer dummy = {
+ .match_table = NULL,
+ .cold_init = NULL,
+ .warm_init = NULL,
+ .exit = NULL,
+ .value = dummy_value,
+ .event_stop = dummy_event_stop,
+ .event_start = dummy_event_start
+};
+
+static struct fdt_timer *current_driver = &dummy;
+
+u64 fdt_timer_value(void)
+{
+ return current_driver->value();
+}
+
+void fdt_timer_event_stop(void)
+{
+ current_driver->event_stop();
+}
+
+void fdt_timer_event_start(u64 next_event)
+{
+ current_driver->event_start(next_event);
+}
+
+void fdt_timer_exit(void)
+{
+ if (current_driver->exit)
+ current_driver->exit();
+}
+
+static int fdt_timer_warm_init(void)
+{
+ if (current_driver->warm_init)
+ return current_driver->warm_init();
+ return 0;
+}
+
+static int fdt_timer_cold_init(void)
+{
+ int pos, noff, rc;
+ struct fdt_timer *drv;
+ const struct fdt_match *match;
+ void *fdt = sbi_scratch_thishart_arg1_ptr();
+
+ for (pos = 0; pos < array_size(timer_drivers); pos++) {
+ drv = timer_drivers[pos];
+
+ noff = -1;
+ while ((noff = fdt_find_match(fdt, noff,
+ drv->match_table, &match)) >= 0) {
+ if (drv->cold_init) {
+ rc = drv->cold_init(fdt, noff, match);
+ if (rc)
+ return rc;
+ }
+ current_driver = drv;
+ }
+
+ if (current_driver != &dummy)
+ break;
+ }
+
+ return 0;
+}
+
+int fdt_timer_init(bool cold_boot)
+{
+ int rc;
+
+ if (cold_boot) {
+ rc = fdt_timer_cold_init();
+ if (rc)
+ return rc;
+ }
+
+ return fdt_timer_warm_init();
+}
diff --git a/roms/opensbi/lib/utils/timer/fdt_timer_clint.c b/roms/opensbi/lib/utils/timer/fdt_timer_clint.c
new file mode 100644
index 000000000..fe6670866
--- /dev/null
+++ b/roms/opensbi/lib/utils/timer/fdt_timer_clint.c
@@ -0,0 +1,52 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/sbi_error.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/timer/fdt_timer.h>
+#include <sbi_utils/sys/clint.h>
+
+#define CLINT_TIMER_MAX_NR 16
+
+static unsigned long clint_timer_count = 0;
+static struct clint_data clint_timer[CLINT_TIMER_MAX_NR];
+
+static int timer_clint_cold_init(void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ int rc;
+ struct clint_data *ct, *ctmaster = NULL;
+
+ if (CLINT_TIMER_MAX_NR <= clint_timer_count)
+ return SBI_ENOSPC;
+ ct = &clint_timer[clint_timer_count++];
+ if (1 < clint_timer_count)
+ ctmaster = &clint_timer[0];
+
+ rc = fdt_parse_clint_node(fdt, nodeoff, TRUE, ct);
+ if (rc)
+ return rc;
+
+ return clint_cold_timer_init(ct, ctmaster);
+}
+
+static const struct fdt_match timer_clint_match[] = {
+ { .compatible = "riscv,clint0" },
+ { },
+};
+
+struct fdt_timer fdt_timer_clint = {
+ .match_table = timer_clint_match,
+ .cold_init = timer_clint_cold_init,
+ .warm_init = clint_warm_timer_init,
+ .exit = NULL,
+ .value = clint_timer_value,
+ .event_stop = clint_timer_event_stop,
+ .event_start = clint_timer_event_start,
+};
diff --git a/roms/opensbi/lib/utils/timer/objects.mk b/roms/opensbi/lib/utils/timer/objects.mk
new file mode 100644
index 000000000..1b84e926c
--- /dev/null
+++ b/roms/opensbi/lib/utils/timer/objects.mk
@@ -0,0 +1,11 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2020 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+
+libsbiutils-objs-y += timer/fdt_timer.o
+libsbiutils-objs-y += timer/fdt_timer_clint.o
diff --git a/roms/opensbi/platform/andes/ae350/cache.c b/roms/opensbi/platform/andes/ae350/cache.c
new file mode 100644
index 000000000..af724c5c7
--- /dev/null
+++ b/roms/opensbi/platform/andes/ae350/cache.c
@@ -0,0 +1,89 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Andes Technology Corporation
+ *
+ * Authors:
+ * Nylon Chen <nylon7@andestech.com>
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_types.h>
+#include "platform.h"
+
+uintptr_t mcall_set_mcache_ctl(unsigned long input)
+{
+ csr_clear(CSR_MCACHECTL, V5_MCACHE_CTL_MASK);
+ csr_write(CSR_MCACHECTL, input);
+ return 0;
+}
+
+uintptr_t mcall_set_mmisc_ctl(unsigned long input)
+{
+ csr_clear(CSR_MMISCCTL, V5_MMISC_CTL_MASK);
+ csr_write(CSR_MMISCCTL, input);
+ return 0;
+}
+
+uintptr_t mcall_icache_op(unsigned int enable)
+{
+ if (enable) {
+ csr_set(CSR_MCACHECTL, V5_MCACHE_CTL_IC_EN);
+ } else {
+ csr_clear(CSR_MCACHECTL, V5_MCACHE_CTL_IC_EN);
+ asm volatile("fence.i\n\t");
+ }
+ return 0;
+}
+
+uintptr_t mcall_dcache_op(unsigned int enable)
+{
+ if (enable) {
+ csr_set(CSR_MCACHECTL, V5_MCACHE_CTL_DC_EN);
+ } else {
+ csr_clear(CSR_MCACHECTL, V5_MCACHE_CTL_DC_EN);
+ csr_write(CSR_MCCTLCOMMAND, V5_UCCTL_L1D_WBINVAL_ALL);
+ }
+ return 0;
+}
+
+uintptr_t mcall_l1_cache_i_prefetch_op(unsigned long enable)
+{
+ if (enable) {
+ csr_set(CSR_MCACHECTL, V5_MCACHE_CTL_L1I_PREFETCH_EN);
+ } else {
+ csr_clear(CSR_MCACHECTL, V5_MCACHE_CTL_L1I_PREFETCH_EN);
+ }
+ return 0;
+}
+
+uintptr_t mcall_l1_cache_d_prefetch_op(unsigned long enable)
+{
+ if (enable) {
+ csr_set(CSR_MCACHECTL, V5_MCACHE_CTL_L1D_PREFETCH_EN);
+ } else {
+ csr_clear(CSR_MCACHECTL, V5_MCACHE_CTL_L1D_PREFETCH_EN);
+ }
+ return 0;
+}
+
+uintptr_t mcall_non_blocking_load_store(unsigned long enable)
+{
+ if (enable) {
+ csr_set(CSR_MCACHECTL, V5_MMISC_CTL_NON_BLOCKING_EN);
+ } else {
+ csr_clear(CSR_MCACHECTL, V5_MMISC_CTL_NON_BLOCKING_EN);
+ }
+ return 0;
+}
+
+uintptr_t mcall_write_around(unsigned long enable)
+{
+ if (enable) {
+ csr_set(CSR_MCACHECTL, V5_MCACHE_CTL_DC_WAROUND_1_EN);
+ } else {
+ csr_clear(CSR_MCACHECTL, V5_MCACHE_CTL_DC_WAROUND_1_EN);
+ }
+ return 0;
+}
diff --git a/roms/opensbi/platform/andes/ae350/cache.h b/roms/opensbi/platform/andes/ae350/cache.h
new file mode 100644
index 000000000..e1c1826f3
--- /dev/null
+++ b/roms/opensbi/platform/andes/ae350/cache.h
@@ -0,0 +1,17 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Andes Technology Corporation
+ *
+ * Authors:
+ * Nylon Chen <nylon7@andestech.com>
+ */
+
+uintptr_t mcall_set_mcache_ctl(unsigned long input);
+uintptr_t mcall_set_mmisc_ctl(unsigned long input);
+uintptr_t mcall_icache_op(unsigned int enable);
+uintptr_t mcall_dcache_op(unsigned int enable);
+uintptr_t mcall_l1_cache_i_prefetch_op(unsigned long enable);
+uintptr_t mcall_l1_cache_d_prefetch_op(unsigned long enable);
+uintptr_t mcall_non_blocking_load_store(unsigned long enable);
+uintptr_t mcall_write_around(unsigned long enable);
diff --git a/roms/opensbi/platform/andes/ae350/config.mk b/roms/opensbi/platform/andes/ae350/config.mk
new file mode 100644
index 000000000..f555ef5be
--- /dev/null
+++ b/roms/opensbi/platform/andes/ae350/config.mk
@@ -0,0 +1,36 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2019 Andes Technology Corporation
+#
+# Authors:
+# Zong Li <zong@andestech.com>
+# Nylon Chen <nylon7@andestech.com>
+
+# Compiler flags
+platform-cppflags-y =
+platform-cflags-y =
+platform-asflags-y =
+platform-ldflags-y =
+
+# Blobs to build
+FW_TEXT_START=0x00000000
+
+FW_DYNAMIC=y
+
+FW_JUMP=y
+ifeq ($(PLATFORM_RISCV_XLEN), 32)
+ FW_JUMP_ADDR=0x400000
+else
+ FW_JUMP_ADDR=0x200000
+endif
+FW_JUMP_FDT_ADDR=0x2000000
+
+FW_PAYLOAD=y
+ifeq ($(PLATFORM_RISCV_XLEN), 32)
+ FW_PAYLOAD_OFFSET=0x400000
+else
+ FW_PAYLOAD_OFFSET=0x200000
+endif
+
+FW_PAYLOAD_FDT_ADDR=0x2000000
diff --git a/roms/opensbi/platform/andes/ae350/objects.mk b/roms/opensbi/platform/andes/ae350/objects.mk
new file mode 100644
index 000000000..5369677c3
--- /dev/null
+++ b/roms/opensbi/platform/andes/ae350/objects.mk
@@ -0,0 +1,11 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2019 Andes Technology Corporation
+#
+# Authors:
+# Zong Li <zong@andestech.com>
+# Nylon Chen <nylon7@andestech.com>
+#
+
+platform-objs-y += cache.o platform.o plicsw.o plmt.o
diff --git a/roms/opensbi/platform/andes/ae350/platform.c b/roms/opensbi/platform/andes/ae350/platform.c
new file mode 100644
index 000000000..aec91cdff
--- /dev/null
+++ b/roms/opensbi/platform/andes/ae350/platform.c
@@ -0,0 +1,192 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Andes Technology Corporation
+ *
+ * Authors:
+ * Zong Li <zong@andestech.com>
+ * Nylon Chen <nylon7@andestech.com>
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#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>
+#include "platform.h"
+#include "plicsw.h"
+#include "plmt.h"
+#include "cache.h"
+
+static struct plic_data plic = {
+ .addr = AE350_PLIC_ADDR,
+ .num_src = AE350_PLIC_NUM_SOURCES,
+};
+
+/* Platform final initialization. */
+static int ae350_final_init(bool cold_boot)
+{
+ void *fdt;
+
+ /* enable L1 cache */
+ uintptr_t mcache_ctl_val = csr_read(CSR_MCACHECTL);
+
+ if (!(mcache_ctl_val & V5_MCACHE_CTL_IC_EN))
+ mcache_ctl_val |= V5_MCACHE_CTL_IC_EN;
+ if (!(mcache_ctl_val & V5_MCACHE_CTL_DC_EN))
+ mcache_ctl_val |= V5_MCACHE_CTL_DC_EN;
+ if (!(mcache_ctl_val & V5_MCACHE_CTL_CCTL_SUEN))
+ mcache_ctl_val |= V5_MCACHE_CTL_CCTL_SUEN;
+ csr_write(CSR_MCACHECTL, mcache_ctl_val);
+
+ /* enable L2 cache */
+ uint32_t *l2c_ctl_base = (void *)AE350_L2C_ADDR + V5_L2C_CTL_OFFSET;
+ uint32_t l2c_ctl_val = *l2c_ctl_base;
+
+ if (!(l2c_ctl_val & V5_L2C_CTL_ENABLE_MASK))
+ l2c_ctl_val |= V5_L2C_CTL_ENABLE_MASK;
+ *l2c_ctl_base = l2c_ctl_val;
+
+ if (!cold_boot)
+ return 0;
+
+ fdt = sbi_scratch_thishart_arg1_ptr();
+ fdt_fixups(fdt);
+
+ return 0;
+}
+
+/* Initialize the platform console. */
+static int ae350_console_init(void)
+{
+ return uart8250_init(AE350_UART_ADDR,
+ AE350_UART_FREQUENCY,
+ AE350_UART_BAUDRATE,
+ AE350_UART_REG_SHIFT,
+ AE350_UART_REG_WIDTH);
+}
+
+/* Initialize the platform interrupt controller for current HART. */
+static int ae350_irqchip_init(bool cold_boot)
+{
+ u32 hartid = current_hartid();
+ int ret;
+
+ if (cold_boot) {
+ ret = plic_cold_irqchip_init(&plic);
+ if (ret)
+ return ret;
+ }
+
+ return plic_warm_irqchip_init(&plic, 2 * hartid, 2 * hartid + 1);
+}
+
+/* Initialize IPI for current HART. */
+static int ae350_ipi_init(bool cold_boot)
+{
+ int ret;
+
+ if (cold_boot) {
+ ret = plicsw_cold_ipi_init(AE350_PLICSW_ADDR,
+ AE350_HART_COUNT);
+ if (ret)
+ return ret;
+ }
+
+ return plicsw_warm_ipi_init();
+}
+
+/* Initialize platform timer for current HART. */
+static int ae350_timer_init(bool cold_boot)
+{
+ int ret;
+
+ if (cold_boot) {
+ ret = plmt_cold_timer_init(AE350_PLMT_ADDR,
+ AE350_HART_COUNT);
+ if (ret)
+ return ret;
+ }
+
+ return plmt_warm_timer_init();
+}
+
+/* Vendor-Specific SBI handler */
+static int ae350_vendor_ext_provider(long extid, long funcid,
+ const struct sbi_trap_regs *regs, unsigned long *out_value,
+ struct sbi_trap_info *out_trap)
+{
+ int ret = 0;
+ switch (funcid) {
+ case SBI_EXT_ANDES_GET_MCACHE_CTL_STATUS:
+ *out_value = csr_read(CSR_MCACHECTL);
+ break;
+ case SBI_EXT_ANDES_GET_MMISC_CTL_STATUS:
+ *out_value = csr_read(CSR_MMISCCTL);
+ break;
+ case SBI_EXT_ANDES_SET_MCACHE_CTL:
+ ret = mcall_set_mcache_ctl(regs->a0);
+ break;
+ case SBI_EXT_ANDES_SET_MMISC_CTL:
+ ret = mcall_set_mmisc_ctl(regs->a0);
+ break;
+ case SBI_EXT_ANDES_ICACHE_OP:
+ ret = mcall_icache_op(regs->a0);
+ break;
+ case SBI_EXT_ANDES_DCACHE_OP:
+ ret = mcall_dcache_op(regs->a0);
+ break;
+ case SBI_EXT_ANDES_L1CACHE_I_PREFETCH:
+ ret = mcall_l1_cache_i_prefetch_op(regs->a0);
+ break;
+ case SBI_EXT_ANDES_L1CACHE_D_PREFETCH:
+ ret = mcall_l1_cache_d_prefetch_op(regs->a0);
+ break;
+ case SBI_EXT_ANDES_NON_BLOCKING_LOAD_STORE:
+ ret = mcall_non_blocking_load_store(regs->a0);
+ break;
+ case SBI_EXT_ANDES_WRITE_AROUND:
+ ret = mcall_write_around(regs->a0);
+ break;
+ default:
+ sbi_printf("Unsupported vendor sbi call : %ld\n", funcid);
+ asm volatile("ebreak");
+ }
+ return ret;
+}
+
+/* Platform descriptor. */
+const struct sbi_platform_operations platform_ops = {
+ .final_init = ae350_final_init,
+
+ .console_init = ae350_console_init,
+ .console_putc = uart8250_putc,
+ .console_getc = uart8250_getc,
+
+ .irqchip_init = ae350_irqchip_init,
+
+ .ipi_init = ae350_ipi_init,
+ .ipi_send = plicsw_ipi_send,
+ .ipi_clear = plicsw_ipi_clear,
+
+ .timer_init = ae350_timer_init,
+ .timer_value = plmt_timer_value,
+ .timer_event_start = plmt_timer_event_start,
+ .timer_event_stop = plmt_timer_event_stop,
+
+ .vendor_ext_provider = ae350_vendor_ext_provider
+};
+
+const struct sbi_platform platform = {
+ .opensbi_version = OPENSBI_VERSION,
+ .platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
+ .name = "Andes AE350",
+ .features = SBI_PLATFORM_DEFAULT_FEATURES,
+ .hart_count = AE350_HART_COUNT,
+ .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
+ .platform_ops_addr = (unsigned long)&platform_ops
+};
diff --git a/roms/opensbi/platform/andes/ae350/platform.h b/roms/opensbi/platform/andes/ae350/platform.h
new file mode 100644
index 000000000..f34ca0fcc
--- /dev/null
+++ b/roms/opensbi/platform/andes/ae350/platform.h
@@ -0,0 +1,125 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Andes Technology Corporation
+ *
+ * Authors:
+ * Zong Li <zong@andestech.com>
+ * Nylon Chen <nylon7@andestech.com>
+ */
+
+#ifndef _AE350_PLATFORM_H_
+#define _AE350_PLATFORM_H_
+
+#define AE350_HART_COUNT 4
+
+#define AE350_PLIC_ADDR 0xe4000000
+#define AE350_PLIC_NUM_SOURCES 71
+
+#define AE350_PLICSW_ADDR 0xe6400000
+
+#define AE350_PLMT_ADDR 0xe6000000
+
+#define AE350_L2C_ADDR 0xe0500000
+
+#define AE350_UART_ADDR_OFFSET 0x20
+#define AE350_UART_ADDR (0xf0300000 + AE350_UART_ADDR_OFFSET)
+#define AE350_UART_FREQUENCY 19660800
+#define AE350_UART_BAUDRATE 38400
+#define AE350_UART_REG_SHIFT 2
+#define AE350_UART_REG_WIDTH 0
+
+/*Memory and Miscellaneous Registers*/
+#define CSR_MILMB 0x7c0
+#define CSR_MDLMB 0x7c1
+#define CSR_MECC_CDOE 0x7c2
+#define CSR_MNVEC 0x7c3
+#define CSR_MPFTCTL 0x7c5
+#define CSR_MCACHECTL 0x7ca
+#define CSR_MCCTLBEGINADDR 0x7cb
+#define CSR_MCCTLCOMMAND 0x7cc
+#define CSR_MCCTLDATA 0x7cc
+#define CSR_SCCTLDATA 0x9cd
+#define CSR_UCCTLBEGINADDR 0x80c
+#define CSR_MMISCCTL 0x7d0
+
+enum sbi_ext_andes_fid {
+ SBI_EXT_ANDES_GET_MCACHE_CTL_STATUS = 0,
+ SBI_EXT_ANDES_GET_MMISC_CTL_STATUS,
+ SBI_EXT_ANDES_SET_MCACHE_CTL,
+ SBI_EXT_ANDES_SET_MMISC_CTL,
+ SBI_EXT_ANDES_ICACHE_OP,
+ SBI_EXT_ANDES_DCACHE_OP,
+ SBI_EXT_ANDES_L1CACHE_I_PREFETCH,
+ SBI_EXT_ANDES_L1CACHE_D_PREFETCH,
+ SBI_EXT_ANDES_NON_BLOCKING_LOAD_STORE,
+ SBI_EXT_ANDES_WRITE_AROUND,
+};
+
+/* nds v5 mmisc_ctl register*/
+#define V5_MMISC_CTL_VEC_PLIC_OFFSET 1
+#define V5_MMISC_CTL_RVCOMPM_OFFSET 2
+#define V5_MMISC_CTL_BRPE_OFFSET 3
+#define V5_MMISC_CTL_MSA_OR_UNA_OFFSET 6
+#define V5_MMISC_CTL_NON_BLOCKING_OFFSET 8
+#define V5_MCACHE_CTL_L1I_PREFETCH_OFFSET 9
+#define V5_MCACHE_CTL_L1D_PREFETCH_OFFSET 10
+#define V5_MCACHE_CTL_DC_WAROUND_OFFSET_1 13
+#define V5_MCACHE_CTL_DC_WAROUND_OFFSET_2 14
+
+#define V5_MMISC_CTL_VEC_PLIC_EN (1UL << V5_MMISC_CTL_VEC_PLIC_OFFSET)
+#define V5_MMISC_CTL_RVCOMPM_EN (1UL << V5_MMISC_CTL_RVCOMPM_OFFSET)
+#define V5_MMISC_CTL_BRPE_EN (1UL << V5_MMISC_CTL_BRPE_OFFSET)
+#define V5_MMISC_CTL_MSA_OR_UNA_EN (1UL << V5_MMISC_CTL_MSA_OR_UNA_OFFSET)
+#define V5_MMISC_CTL_NON_BLOCKING_EN (1UL << V5_MMISC_CTL_NON_BLOCKING_OFFSET)
+#define V5_MCACHE_CTL_L1I_PREFETCH_EN (1UL << V5_MCACHE_CTL_L1I_PREFETCH_OFFSET)
+#define V5_MCACHE_CTL_L1D_PREFETCH_EN (1UL << V5_MCACHE_CTL_L1D_PREFETCH_OFFSET)
+#define V5_MCACHE_CTL_DC_WAROUND_1_EN (1UL << V5_MCACHE_CTL_DC_WAROUND_OFFSET_1)
+#define V5_MCACHE_CTL_DC_WAROUND_2_EN (1UL << V5_MCACHE_CTL_DC_WAROUND_OFFSET_2)
+
+#define V5_MMISC_CTL_MASK (V5_MMISC_CTL_VEC_PLIC_EN | V5_MMISC_CTL_RVCOMPM_EN \
+ | V5_MMISC_CTL_BRPE_EN | V5_MMISC_CTL_MSA_OR_UNA_EN | V5_MMISC_CTL_NON_BLOCKING_EN)
+
+/* nds mcache_ctl register*/
+#define V5_MCACHE_CTL_IC_EN_OFFSET 0
+#define V5_MCACHE_CTL_DC_EN_OFFSET 1
+#define V5_MCACHE_CTL_IC_ECCEN_OFFSET 2
+#define V5_MCACHE_CTL_DC_ECCEN_OFFSET 4
+#define V5_MCACHE_CTL_IC_RWECC_OFFSET 6
+#define V5_MCACHE_CTL_DC_RWECC_OFFSET 7
+#define V5_MCACHE_CTL_CCTL_SUEN_OFFSET 8
+
+/*nds cctl command*/
+#define V5_UCCTL_L1D_WBINVAL_ALL 6
+#define V5_UCCTL_L1D_WB_ALL 7
+
+#define V5_MCACHE_CTL_IC_EN (1UL << V5_MCACHE_CTL_IC_EN_OFFSET)
+#define V5_MCACHE_CTL_DC_EN (1UL << V5_MCACHE_CTL_DC_EN_OFFSET)
+#define V5_MCACHE_CTL_IC_RWECC (1UL << V5_MCACHE_CTL_IC_RWECC_OFFSET)
+#define V5_MCACHE_CTL_DC_RWECC (1UL << V5_MCACHE_CTL_DC_RWECC_OFFSET)
+#define V5_MCACHE_CTL_CCTL_SUEN (1UL << V5_MCACHE_CTL_CCTL_SUEN_OFFSET)
+
+#define V5_MCACHE_CTL_MASK (V5_MCACHE_CTL_IC_EN | V5_MCACHE_CTL_DC_EN \
+ | V5_MCACHE_CTL_IC_RWECC | V5_MCACHE_CTL_DC_RWECC \
+ | V5_MCACHE_CTL_CCTL_SUEN | V5_MCACHE_CTL_L1I_PREFETCH_EN \
+ | V5_MCACHE_CTL_L1D_PREFETCH_EN | V5_MCACHE_CTL_DC_WAROUND_1_EN \
+ | V5_MCACHE_CTL_DC_WAROUND_2_EN)
+
+#define V5_L2C_CTL_OFFSET 0x8
+#define V5_L2C_CTL_ENABLE_OFFSET 0
+#define V5_L2C_CTL_IPFDPT_OFFSET 3
+#define V5_L2C_CTL_DPFDPT_OFFSET 5
+#define V5_L2C_CTL_TRAMOCTL_OFFSET 8
+#define V5_L2C_CTL_TRAMICTL_OFFSET 10
+#define V5_L2C_CTL_DRAMOCTL_OFFSET 11
+#define V5_L2C_CTL_DRAMICTL_OFFSET 13
+
+#define V5_L2C_CTL_ENABLE_MASK (1UL << V5_L2C_CTL_ENABLE_OFFSET)
+#define V5_L2C_CTL_IPFDPT_MASK (3UL << V5_L2C_CTL_IPFDPT_OFFSET)
+#define V5_L2C_CTL_DPFDPT_MASK (3UL << V5_L2C_CTL_DPFDPT_OFFSET)
+#define V5_L2C_CTL_TRAMOCTL_MASK (3UL << V5_L2C_CTL_TRAMOCTL_OFFSET)
+#define V5_L2C_CTL_TRAMICTL_MASK (1UL << V5_L2C_CTL_TRAMICTL_OFFSET)
+#define V5_L2C_CTL_DRAMOCTL_MASK (3UL << V5_L2C_CTL_DRAMOCTL_OFFSET)
+#define V5_L2C_CTL_DRAMICTL_MASK (1UL << V5_L2C_CTL_DRAMICTL_OFFSET)
+
+#endif /* _AE350_PLATFORM_H_ */
diff --git a/roms/opensbi/platform/andes/ae350/plicsw.c b/roms/opensbi/platform/andes/ae350/plicsw.c
new file mode 100644
index 000000000..d07df28c8
--- /dev/null
+++ b/roms/opensbi/platform/andes/ae350/plicsw.c
@@ -0,0 +1,145 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Andes Technology Corporation
+ *
+ * Authors:
+ * Zong Li <zong@andestech.com>
+ * Nylon Chen <nylon7@andestech.com>
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_types.h>
+#include "plicsw.h"
+#include "platform.h"
+
+static u32 plicsw_ipi_hart_count;
+static struct plicsw plicsw_dev[AE350_HART_COUNT];
+
+static inline void plicsw_claim(void)
+{
+ u32 source_hart = current_hartid();
+
+ plicsw_dev[source_hart].source_id =
+ readl(plicsw_dev[source_hart].plicsw_claim);
+}
+
+static inline void plicsw_complete(void)
+{
+ u32 source_hart = current_hartid();
+ u32 source = plicsw_dev[source_hart].source_id;
+
+ writel(source, plicsw_dev[source_hart].plicsw_claim);
+}
+
+static inline u32 plicsw_get_pending(u32 source_hart, u32 target_hart)
+{
+ return readl(plicsw_dev[source_hart].plicsw_pending)
+ & (PLICSW_HART_MASK >> target_hart);
+}
+
+static inline void plic_sw_pending(u32 target_hart)
+{
+ /*
+ * The pending array registers are w1s type.
+ * IPI pending array mapping as following:
+ *
+ * Pending array start address: base + 0x1000
+ * -------------------------------------
+ * | hart 3 | hart 2 | hart 1 | hart 0 |
+ * -------------------------------------
+ * Each hart X can send IPI to another hart by setting the
+ * corresponding bit in hart X own region(see the below).
+ *
+ * In each hart region:
+ * -----------------------------------------------
+ * | bit 7 | bit 6 | bit 5 | bit 4 | ... | bit 0 |
+ * -----------------------------------------------
+ * The bit 7 is used to send IPI to hart 0
+ * The bit 6 is used to send IPI to hart 1
+ * The bit 5 is used to send IPI to hart 2
+ * The bit 4 is used to send IPI to hart 3
+ */
+ u32 source_hart = current_hartid();
+ u32 target_offset = (PLICSW_PENDING_PER_HART - 1) - target_hart;
+ u32 per_hart_offset = PLICSW_PENDING_PER_HART * source_hart;
+ u32 val = 1 << target_offset << per_hart_offset;
+
+ writel(val, plicsw_dev[source_hart].plicsw_pending);
+}
+
+void plicsw_ipi_send(u32 target_hart)
+{
+ if (plicsw_ipi_hart_count <= target_hart)
+ return;
+
+ /* Set PLICSW IPI */
+ plic_sw_pending(target_hart);
+}
+
+void plicsw_ipi_clear(u32 target_hart)
+{
+ if (plicsw_ipi_hart_count <= target_hart)
+ return;
+
+ /* Clear CLINT IPI */
+ plicsw_claim();
+ plicsw_complete();
+}
+
+int plicsw_warm_ipi_init(void)
+{
+ u32 hartid = current_hartid();
+
+ if (!plicsw_dev[hartid].plicsw_pending
+ && !plicsw_dev[hartid].plicsw_enable
+ && !plicsw_dev[hartid].plicsw_claim)
+ return -1;
+
+ /* Clear PLICSW IPI */
+ plicsw_ipi_clear(hartid);
+
+ return 0;
+}
+
+int plicsw_cold_ipi_init(unsigned long base, u32 hart_count)
+{
+ /* Setup source priority */
+ uint32_t *priority = (void *)base + PLICSW_PRIORITY_BASE;
+
+ for (int i = 0; i < AE350_HART_COUNT*PLICSW_PENDING_PER_HART; i++)
+ writel(1, &priority[i]);
+
+ /* Setup target enable.*/
+ uint32_t enable_mask = PLICSW_HART_MASK;
+
+ for (int i = 0; i < AE350_HART_COUNT; i++) {
+ uint32_t *enable = (void *)base + PLICSW_ENABLE_BASE
+ + PLICSW_ENABLE_PER_HART * i;
+ writel(enable_mask, &enable[0]);
+ enable_mask >>= 1;
+ }
+
+ /* Figure-out PLICSW IPI register address */
+ plicsw_ipi_hart_count = hart_count;
+
+ for (u32 hartid = 0; hartid < AE350_HART_COUNT; hartid++) {
+ plicsw_dev[hartid].source_id = 0;
+ plicsw_dev[hartid].plicsw_pending =
+ (void *)base
+ + PLICSW_PENDING_BASE
+ + ((hartid / 4) * 4);
+ plicsw_dev[hartid].plicsw_enable =
+ (void *)base
+ + PLICSW_ENABLE_BASE
+ + PLICSW_ENABLE_PER_HART * hartid;
+ plicsw_dev[hartid].plicsw_claim =
+ (void *)base
+ + PLICSW_CONTEXT_BASE
+ + PLICSW_CONTEXT_CLAIM
+ + PLICSW_CONTEXT_PER_HART * hartid;
+ }
+
+ return 0;
+}
diff --git a/roms/opensbi/platform/andes/ae350/plicsw.h b/roms/opensbi/platform/andes/ae350/plicsw.h
new file mode 100644
index 000000000..8be61945b
--- /dev/null
+++ b/roms/opensbi/platform/andes/ae350/plicsw.h
@@ -0,0 +1,46 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Andes Technology Corporation
+ *
+ * Authors:
+ * Zong Li <zong@andestech.com>
+ * Nylon Chen <nylon7@andestech.com>
+ */
+
+#ifndef _AE350_PLICSW_H_
+#define _AE350_PLICSW_H_
+
+#define PLICSW_PRIORITY_BASE 0x4
+
+#define PLICSW_PENDING_BASE 0x1000
+#define PLICSW_PENDING_PER_HART 0x8
+
+#define PLICSW_ENABLE_BASE 0x2000
+#define PLICSW_ENABLE_PER_HART 0x80
+
+#define PLICSW_CONTEXT_BASE 0x200000
+#define PLICSW_CONTEXT_PER_HART 0x1000
+#define PLICSW_CONTEXT_CLAIM 0x4
+
+#define PLICSW_HART_MASK 0x80808080
+
+struct plicsw {
+ u32 source_id;
+
+ volatile uint32_t *plicsw_pending;
+ volatile uint32_t *plicsw_enable;
+ volatile uint32_t *plicsw_claim;
+};
+
+void plicsw_ipi_send(u32 target_hart);
+
+void plicsw_ipi_sync(u32 target_hart);
+
+void plicsw_ipi_clear(u32 target_hart);
+
+int plicsw_warm_ipi_init(void);
+
+int plicsw_cold_ipi_init(unsigned long base, u32 hart_count);
+
+#endif /* _AE350_PLICSW_H_ */
diff --git a/roms/opensbi/platform/andes/ae350/plmt.c b/roms/opensbi/platform/andes/ae350/plmt.c
new file mode 100644
index 000000000..3848e158d
--- /dev/null
+++ b/roms/opensbi/platform/andes/ae350/plmt.c
@@ -0,0 +1,97 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Andes Technology Corporation
+ *
+ * Authors:
+ * Zong Li <zong@andestech.com>
+ * Nylon Chen <nylon7@andestech.com>
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_io.h>
+
+static u32 plmt_time_hart_count;
+static volatile void *plmt_time_base;
+static volatile u64 *plmt_time_val;
+static volatile u64 *plmt_time_cmp;
+
+u64 plmt_timer_value(void)
+{
+#if __riscv_xlen == 64
+ return readq_relaxed(plmt_time_val);
+#else
+ u32 lo, hi;
+
+ do {
+ hi = readl_relaxed((void *)plmt_time_val + 0x04);
+ lo = readl_relaxed(plmt_time_val);
+ } while (hi != readl_relaxed((void *)plmt_time_val + 0x04));
+
+ return ((u64)hi << 32) | (u64)lo;
+#endif
+}
+
+void plmt_timer_event_stop(void)
+{
+ u32 target_hart = current_hartid();
+
+ if (plmt_time_hart_count <= target_hart)
+ return;
+
+ /* Clear PLMT Time Compare */
+#if __riscv_xlen == 64
+ writeq_relaxed(-1ULL, &plmt_time_cmp[target_hart]);
+#else
+ writel_relaxed(-1UL, &plmt_time_cmp[target_hart]);
+ writel_relaxed(-1UL, (void *)(&plmt_time_cmp[target_hart]) + 0x04);
+#endif
+}
+
+void plmt_timer_event_start(u64 next_event)
+{
+ u32 target_hart = current_hartid();
+
+ if (plmt_time_hart_count <= target_hart)
+ return;
+
+ /* Program PLMT Time Compare */
+#if __riscv_xlen == 64
+ writeq_relaxed(next_event, &plmt_time_cmp[target_hart]);
+#else
+ u32 mask = -1UL;
+
+ writel_relaxed(next_event & mask, &plmt_time_cmp[target_hart]);
+ writel_relaxed(next_event >> 32,
+ (void *)(&plmt_time_cmp[target_hart]) + 0x04);
+#endif
+
+}
+
+int plmt_warm_timer_init(void)
+{
+ u32 target_hart = current_hartid();
+
+ if (plmt_time_hart_count <= target_hart || !plmt_time_base)
+ return -1;
+
+ /* Clear PLMT Time Compare */
+#if __riscv_xlen == 64
+ writeq_relaxed(-1ULL, &plmt_time_cmp[target_hart]);
+#else
+ writel_relaxed(-1UL, &plmt_time_cmp[target_hart]);
+ writel_relaxed(-1UL, (void *)(&plmt_time_cmp[target_hart]) + 0x04);
+#endif
+
+ return 0;
+}
+
+int plmt_cold_timer_init(unsigned long base, u32 hart_count)
+{
+ plmt_time_hart_count = hart_count;
+ plmt_time_base = (void *)base;
+ plmt_time_val = (u64 *)(plmt_time_base);
+ plmt_time_cmp = (u64 *)(plmt_time_base + 0x8);
+
+ return 0;
+}
diff --git a/roms/opensbi/platform/andes/ae350/plmt.h b/roms/opensbi/platform/andes/ae350/plmt.h
new file mode 100644
index 000000000..129fcf8d1
--- /dev/null
+++ b/roms/opensbi/platform/andes/ae350/plmt.h
@@ -0,0 +1,23 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Andes Technology Corporation
+ *
+ * Authors:
+ * Zong Li <zong@andestech.com>
+ */
+
+#ifndef _AE350_PLMT_H_
+#define _AE350_PLMT_H_
+
+u64 plmt_timer_value(void);
+
+void plmt_timer_event_stop(void);
+
+void plmt_timer_event_start(u64 next_event);
+
+int plmt_warm_timer_init(void);
+
+int plmt_cold_timer_init(unsigned long base, u32 hart_count);
+
+#endif /* _AE350_PLMT_H_ */
diff --git a/roms/opensbi/platform/fpga/ariane/config.mk b/roms/opensbi/platform/fpga/ariane/config.mk
new file mode 100644
index 000000000..3556461a1
--- /dev/null
+++ b/roms/opensbi/platform/fpga/ariane/config.mk
@@ -0,0 +1,36 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (C) 2019 FORTH-ICS/CARV
+# Panagiotis Peristerakis <perister@ics.forth.gr>
+#
+
+#for more infos, check out /platform/template/config.mk
+
+PLATFORM_RISCV_XLEN = 64
+
+# Blobs to build
+FW_TEXT_START=0x80000000
+FW_JUMP=n
+
+ifeq ($(PLATFORM_RISCV_XLEN), 32)
+ # This needs to be 4MB aligned for 32-bit support
+ FW_JUMP_ADDR=0x80400000
+ else
+ # This needs to be 2MB aligned for 64-bit support
+ FW_JUMP_ADDR=0x80200000
+ endif
+FW_JUMP_FDT_ADDR=0x82200000
+
+# Firmware with payload configuration.
+FW_PAYLOAD=y
+
+ifeq ($(PLATFORM_RISCV_XLEN), 32)
+# This needs to be 4MB aligned for 32-bit support
+ FW_PAYLOAD_OFFSET=0x400000
+else
+# This needs to be 2MB aligned for 64-bit support
+ FW_PAYLOAD_OFFSET=0x200000
+endif
+FW_PAYLOAD_FDT_ADDR=0x82200000
+FW_PAYLOAD_ALIGN=0x1000
diff --git a/roms/opensbi/platform/fpga/ariane/objects.mk b/roms/opensbi/platform/fpga/ariane/objects.mk
new file mode 100644
index 000000000..814e6da63
--- /dev/null
+++ b/roms/opensbi/platform/fpga/ariane/objects.mk
@@ -0,0 +1,8 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (C) 2019 FORTH-ICS/CARV
+# Panagiotis Peristerakis <perister@ics.forth.gr>
+#
+
+platform-objs-y += platform.o
diff --git a/roms/opensbi/platform/fpga/ariane/platform.c b/roms/opensbi/platform/fpga/ariane/platform.c
new file mode 100644
index 000000000..ea179e52d
--- /dev/null
+++ b/roms/opensbi/platform/fpga/ariane/platform.c
@@ -0,0 +1,177 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (C) 2019 FORTH-ICS/CARV
+ * Panagiotis Peristerakis <perister@ics.forth.gr>
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_const.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_platform.h>
+#include <sbi_utils/fdt/fdt_fixup.h>
+#include <sbi_utils/irqchip/plic.h>
+#include <sbi_utils/serial/uart8250.h>
+#include <sbi_utils/sys/clint.h>
+
+#define ARIANE_UART_ADDR 0x10000000
+#define ARIANE_UART_FREQ 50000000
+#define ARIANE_UART_BAUDRATE 115200
+#define ARIANE_UART_REG_SHIFT 2
+#define ARIANE_UART_REG_WIDTH 4
+#define ARIANE_PLIC_ADDR 0xc000000
+#define ARIANE_PLIC_NUM_SOURCES 3
+#define ARIANE_HART_COUNT 1
+#define ARIANE_CLINT_ADDR 0x2000000
+
+static struct plic_data plic = {
+ .addr = ARIANE_PLIC_ADDR,
+ .num_src = ARIANE_PLIC_NUM_SOURCES,
+};
+
+static struct clint_data clint = {
+ .addr = ARIANE_CLINT_ADDR,
+ .first_hartid = 0,
+ .hart_count = ARIANE_HART_COUNT,
+ .has_64bit_mmio = TRUE,
+};
+
+/*
+ * Ariane platform early initialization.
+ */
+static int ariane_early_init(bool cold_boot)
+{
+ /* For now nothing to do. */
+ return 0;
+}
+
+/*
+ * Ariane platform final initialization.
+ */
+static int ariane_final_init(bool cold_boot)
+{
+ void *fdt;
+
+ if (!cold_boot)
+ return 0;
+
+ fdt = sbi_scratch_thishart_arg1_ptr();
+ fdt_fixups(fdt);
+
+ return 0;
+}
+
+/*
+ * Initialize the ariane console.
+ */
+static int ariane_console_init(void)
+{
+ return uart8250_init(ARIANE_UART_ADDR,
+ ARIANE_UART_FREQ,
+ ARIANE_UART_BAUDRATE,
+ ARIANE_UART_REG_SHIFT,
+ ARIANE_UART_REG_WIDTH);
+}
+
+static int plic_ariane_warm_irqchip_init(int m_cntx_id, int s_cntx_id)
+{
+ size_t i, ie_words = ARIANE_PLIC_NUM_SOURCES / 32 + 1;
+
+ /* By default, enable all IRQs for M-mode of target HART */
+ if (m_cntx_id > -1) {
+ for (i = 0; i < ie_words; i++)
+ plic_set_ie(&plic, m_cntx_id, i, 1);
+ }
+ /* Enable all IRQs for S-mode of target HART */
+ if (s_cntx_id > -1) {
+ for (i = 0; i < ie_words; i++)
+ plic_set_ie(&plic, s_cntx_id, i, 1);
+ }
+ /* By default, enable M-mode threshold */
+ if (m_cntx_id > -1)
+ plic_set_thresh(&plic, m_cntx_id, 1);
+ /* By default, disable S-mode threshold */
+ if (s_cntx_id > -1)
+ plic_set_thresh(&plic, s_cntx_id, 0);
+
+ return 0;
+}
+
+/*
+ * Initialize the ariane interrupt controller for current HART.
+ */
+static int ariane_irqchip_init(bool cold_boot)
+{
+ u32 hartid = current_hartid();
+ int ret;
+
+ if (cold_boot) {
+ ret = plic_cold_irqchip_init(&plic);
+ if (ret)
+ return ret;
+ }
+ return plic_ariane_warm_irqchip_init(2 * hartid, 2 * hartid + 1);
+}
+
+/*
+ * Initialize IPI for current HART.
+ */
+static int ariane_ipi_init(bool cold_boot)
+{
+ int ret;
+
+ if (cold_boot) {
+ ret = clint_cold_ipi_init(&clint);
+ if (ret)
+ return ret;
+ }
+
+ return clint_warm_ipi_init();
+}
+
+/*
+ * Initialize ariane timer for current HART.
+ */
+static int ariane_timer_init(bool cold_boot)
+{
+ int ret;
+
+ if (cold_boot) {
+ ret = clint_cold_timer_init(&clint, NULL);
+ if (ret)
+ return ret;
+ }
+
+ return clint_warm_timer_init();
+}
+
+/*
+ * Platform descriptor.
+ */
+const struct sbi_platform_operations platform_ops = {
+ .early_init = ariane_early_init,
+ .final_init = ariane_final_init,
+ .console_init = ariane_console_init,
+ .console_putc = uart8250_putc,
+ .console_getc = uart8250_getc,
+ .irqchip_init = ariane_irqchip_init,
+ .ipi_init = ariane_ipi_init,
+ .ipi_send = clint_ipi_send,
+ .ipi_clear = clint_ipi_clear,
+ .timer_init = ariane_timer_init,
+ .timer_value = clint_timer_value,
+ .timer_event_start = clint_timer_event_start,
+ .timer_event_stop = clint_timer_event_stop,
+};
+
+const struct sbi_platform platform = {
+ .opensbi_version = OPENSBI_VERSION,
+ .platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
+ .name = "ARIANE RISC-V",
+ .features = SBI_PLATFORM_DEFAULT_FEATURES,
+ .hart_count = ARIANE_HART_COUNT,
+ .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
+ .platform_ops_addr = (unsigned long)&platform_ops
+};
diff --git a/roms/opensbi/platform/fpga/openpiton/config.mk b/roms/opensbi/platform/fpga/openpiton/config.mk
new file mode 100644
index 000000000..a969b250a
--- /dev/null
+++ b/roms/opensbi/platform/fpga/openpiton/config.mk
@@ -0,0 +1,35 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2020 Western Digital Corporation or its affiliates.
+#
+
+#for more infos, check out /platform/template/config.mk
+
+PLATFORM_RISCV_XLEN = 64
+
+# Blobs to build
+FW_TEXT_START=0x80000000
+FW_JUMP=n
+
+ifeq ($(PLATFORM_RISCV_XLEN), 32)
+ # This needs to be 4MB aligned for 32-bit support
+ FW_JUMP_ADDR=0x80400000
+ else
+ # This needs to be 2MB aligned for 64-bit support
+ FW_JUMP_ADDR=0x80200000
+ endif
+FW_JUMP_FDT_ADDR=0x82200000
+
+# Firmware with payload configuration.
+FW_PAYLOAD=y
+
+ifeq ($(PLATFORM_RISCV_XLEN), 32)
+# This needs to be 4MB aligned for 32-bit support
+ FW_PAYLOAD_OFFSET=0x400000
+else
+# This needs to be 2MB aligned for 64-bit support
+ FW_PAYLOAD_OFFSET=0x200000
+endif
+FW_PAYLOAD_FDT_ADDR=0x82200000
+FW_PAYLOAD_ALIGN=0x1000
diff --git a/roms/opensbi/platform/fpga/openpiton/objects.mk b/roms/opensbi/platform/fpga/openpiton/objects.mk
new file mode 100644
index 000000000..30a3c4fb8
--- /dev/null
+++ b/roms/opensbi/platform/fpga/openpiton/objects.mk
@@ -0,0 +1,7 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2020 Western Digital Corporation or its affiliates.
+#
+
+platform-objs-y += platform.o
diff --git a/roms/opensbi/platform/fpga/openpiton/platform.c b/roms/opensbi/platform/fpga/openpiton/platform.c
new file mode 100644
index 000000000..5eae47799
--- /dev/null
+++ b/roms/opensbi/platform/fpga/openpiton/platform.c
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_const.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_platform.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/fdt/fdt_fixup.h>
+#include <sbi_utils/irqchip/plic.h>
+#include <sbi_utils/serial/uart8250.h>
+#include <sbi_utils/sys/clint.h>
+
+#define OPENPITON_DEFAULT_UART_ADDR 0xfff0c2c000
+#define OPENPITON_DEFAULT_UART_FREQ 60000000
+#define OPENPITON_DEFAULT_UART_BAUDRATE 115200
+#define OPENPITON_DEFAULT_UART_REG_SHIFT 0
+#define OPENPITON_DEFAULT_UART_REG_WIDTH 1
+#define OPENPITON_DEFAULT_PLIC_ADDR 0xfff1100000
+#define OPENPITON_DEFAULT_PLIC_NUM_SOURCES 2
+#define OPENPITON_DEFAULT_HART_COUNT 3
+#define OPENPITON_DEFAULT_CLINT_ADDR 0xfff1020000
+
+static struct platform_uart_data uart = {
+ OPENPITON_DEFAULT_UART_ADDR,
+ OPENPITON_DEFAULT_UART_FREQ,
+ OPENPITON_DEFAULT_UART_BAUDRATE,
+};
+static struct plic_data plic = {
+ .addr = OPENPITON_DEFAULT_PLIC_ADDR,
+ .num_src = OPENPITON_DEFAULT_PLIC_NUM_SOURCES,
+};
+
+static struct clint_data clint = {
+ .addr = OPENPITON_DEFAULT_CLINT_ADDR,
+ .first_hartid = 0,
+ .hart_count = OPENPITON_DEFAULT_HART_COUNT,
+ .has_64bit_mmio = TRUE,
+};
+
+/*
+ * OpenPiton platform early initialization.
+ */
+static int openpiton_early_init(bool cold_boot)
+{
+ void *fdt;
+ struct platform_uart_data uart_data;
+ struct plic_data plic_data;
+ unsigned long clint_addr;
+ int rc;
+
+ if (!cold_boot)
+ return 0;
+ fdt = sbi_scratch_thishart_arg1_ptr();
+
+ rc = fdt_parse_uart8250(fdt, &uart_data, "ns16550");
+ if (!rc)
+ uart = uart_data;
+
+ rc = fdt_parse_plic(fdt, &plic_data, "riscv,plic0");
+ if (!rc)
+ plic = plic_data;
+
+ rc = fdt_parse_compat_addr(fdt, &clint_addr, "riscv,clint0");
+ if (!rc)
+ clint.addr = clint_addr;
+
+ return 0;
+}
+
+/*
+ * OpenPiton platform final initialization.
+ */
+static int openpiton_final_init(bool cold_boot)
+{
+ void *fdt;
+
+ if (!cold_boot)
+ return 0;
+
+ fdt = sbi_scratch_thishart_arg1_ptr();
+ fdt_fixups(fdt);
+
+ return 0;
+}
+
+/*
+ * Initialize the openpiton console.
+ */
+static int openpiton_console_init(void)
+{
+ return uart8250_init(uart.addr,
+ uart.freq,
+ uart.baud,
+ OPENPITON_DEFAULT_UART_REG_SHIFT,
+ OPENPITON_DEFAULT_UART_REG_WIDTH);
+}
+
+static int plic_openpiton_warm_irqchip_init(int m_cntx_id, int s_cntx_id)
+{
+ size_t i, ie_words = plic.num_src / 32 + 1;
+
+ /* By default, enable all IRQs for M-mode of target HART */
+ if (m_cntx_id > -1) {
+ for (i = 0; i < ie_words; i++)
+ plic_set_ie(&plic, m_cntx_id, i, 1);
+ }
+ /* Enable all IRQs for S-mode of target HART */
+ if (s_cntx_id > -1) {
+ for (i = 0; i < ie_words; i++)
+ plic_set_ie(&plic, s_cntx_id, i, 1);
+ }
+ /* By default, enable M-mode threshold */
+ if (m_cntx_id > -1)
+ plic_set_thresh(&plic, m_cntx_id, 1);
+ /* By default, disable S-mode threshold */
+ if (s_cntx_id > -1)
+ plic_set_thresh(&plic, s_cntx_id, 0);
+
+ return 0;
+}
+
+/*
+ * Initialize the openpiton interrupt controller for current HART.
+ */
+static int openpiton_irqchip_init(bool cold_boot)
+{
+ u32 hartid = current_hartid();
+ int ret;
+
+ if (cold_boot) {
+ ret = plic_cold_irqchip_init(&plic);
+ if (ret)
+ return ret;
+ }
+ return plic_openpiton_warm_irqchip_init(2 * hartid, 2 * hartid + 1);
+}
+
+/*
+ * Initialize IPI for current HART.
+ */
+static int openpiton_ipi_init(bool cold_boot)
+{
+ int ret;
+
+ if (cold_boot) {
+ ret = clint_cold_ipi_init(&clint);
+ if (ret)
+ return ret;
+ }
+
+ return clint_warm_ipi_init();
+}
+
+/*
+ * Initialize openpiton timer for current HART.
+ */
+static int openpiton_timer_init(bool cold_boot)
+{
+ int ret;
+
+ if (cold_boot) {
+ ret = clint_cold_timer_init(&clint, NULL);
+ if (ret)
+ return ret;
+ }
+
+ return clint_warm_timer_init();
+}
+
+/*
+ * Platform descriptor.
+ */
+const struct sbi_platform_operations platform_ops = {
+ .early_init = openpiton_early_init,
+ .final_init = openpiton_final_init,
+ .console_init = openpiton_console_init,
+ .console_putc = uart8250_putc,
+ .console_getc = uart8250_getc,
+ .irqchip_init = openpiton_irqchip_init,
+ .ipi_init = openpiton_ipi_init,
+ .ipi_send = clint_ipi_send,
+ .ipi_clear = clint_ipi_clear,
+ .timer_init = openpiton_timer_init,
+ .timer_value = clint_timer_value,
+ .timer_event_start = clint_timer_event_start,
+ .timer_event_stop = clint_timer_event_stop,
+};
+
+const struct sbi_platform platform = {
+ .opensbi_version = OPENSBI_VERSION,
+ .platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
+ .name = "OPENPITON RISC-V",
+ .features = SBI_PLATFORM_DEFAULT_FEATURES,
+ .hart_count = OPENPITON_DEFAULT_HART_COUNT,
+ .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
+ .platform_ops_addr = (unsigned long)&platform_ops
+};
diff --git a/roms/opensbi/platform/generic/config.mk b/roms/opensbi/platform/generic/config.mk
new file mode 100644
index 000000000..8151974f2
--- /dev/null
+++ b/roms/opensbi/platform/generic/config.mk
@@ -0,0 +1,40 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2020 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+
+# Compiler flags
+platform-cppflags-y =
+platform-cflags-y =
+platform-asflags-y =
+platform-ldflags-y =
+
+# Command for platform specific "make run"
+platform-runcmd = qemu-system-riscv$(PLATFORM_RISCV_XLEN) -M virt -m 256M \
+ -nographic -bios $(build_dir)/platform/generic/firmware/fw_payload.elf
+
+# Blobs to build
+FW_TEXT_START=0x80000000
+FW_DYNAMIC=y
+FW_JUMP=y
+ifeq ($(PLATFORM_RISCV_XLEN), 32)
+ # This needs to be 4MB aligned for 32-bit system
+ FW_JUMP_ADDR=$(shell printf "0x%X" $$(($(FW_TEXT_START) + 0x400000)))
+else
+ # This needs to be 2MB aligned for 64-bit system
+ FW_JUMP_ADDR=$(shell printf "0x%X" $$(($(FW_TEXT_START) + 0x200000)))
+endif
+FW_JUMP_FDT_ADDR=$(shell printf "0x%X" $$(($(FW_TEXT_START) + 0x2200000)))
+FW_PAYLOAD=y
+ifeq ($(PLATFORM_RISCV_XLEN), 32)
+ # This needs to be 4MB aligned for 32-bit system
+ FW_PAYLOAD_OFFSET=0x400000
+else
+ # This needs to be 2MB aligned for 64-bit system
+ FW_PAYLOAD_OFFSET=0x200000
+endif
+FW_PAYLOAD_FDT_ADDR=$(FW_JUMP_FDT_ADDR)
diff --git a/roms/opensbi/platform/generic/include/platform_override.h b/roms/opensbi/platform/generic/include/platform_override.h
new file mode 100644
index 000000000..77a90d645
--- /dev/null
+++ b/roms/opensbi/platform/generic/include/platform_override.h
@@ -0,0 +1,30 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __PLATFORM_OVERRIDE_H__
+#define __PLATFORM_OVERRIDE_H__
+
+#include <sbi/sbi_types.h>
+
+struct platform_override {
+ const struct fdt_match *match_table;
+ u64 (*features)(const struct fdt_match *match);
+ u64 (*tlbr_flush_limit)(const struct fdt_match *match);
+ int (*early_init)(bool cold_boot, const struct fdt_match *match);
+ 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_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);
+};
+
+#endif
diff --git a/roms/opensbi/platform/generic/objects.mk b/roms/opensbi/platform/generic/objects.mk
new file mode 100644
index 000000000..d6c8a42d6
--- /dev/null
+++ b/roms/opensbi/platform/generic/objects.mk
@@ -0,0 +1,11 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2020 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+
+platform-objs-y += platform.o
+platform-objs-y += sifive_fu540.o
diff --git a/roms/opensbi/platform/generic/platform.c b/roms/opensbi/platform/generic/platform.c
new file mode 100644
index 000000000..8c1e06f12
--- /dev/null
+++ b/roms/opensbi/platform/generic/platform.c
@@ -0,0 +1,241 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <libfdt.h>
+#include <platform_override.h>
+#include <sbi/riscv_asm.h>
+#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>
+#include <sbi_utils/serial/fdt_serial.h>
+#include <sbi_utils/timer/fdt_timer.h>
+#include <sbi_utils/ipi/fdt_ipi.h>
+#include <sbi_utils/reset/fdt_reset.h>
+
+extern const struct platform_override sifive_fu540;
+
+static const struct platform_override *special_platforms[] = {
+ &sifive_fu540,
+};
+
+static const struct platform_override *generic_plat = NULL;
+static const struct fdt_match *generic_plat_match = NULL;
+
+static void fw_platform_lookup_special(void *fdt, int root_offset)
+{
+ int pos, noff;
+ const struct platform_override *plat;
+ const struct fdt_match *match;
+
+ for (pos = 0; pos < array_size(special_platforms); pos++) {
+ plat = special_platforms[pos];
+ if (!plat->match_table)
+ continue;
+
+ noff = fdt_find_match(fdt, -1, plat->match_table, &match);
+ if (noff < 0)
+ continue;
+
+ generic_plat = plat;
+ generic_plat_match = match;
+ break;
+ }
+}
+
+extern struct sbi_platform platform;
+static u32 generic_hart_index2id[SBI_HARTMASK_MAX_BITS] = { 0 };
+
+/*
+ * The fw_platform_init() function is called very early on the boot HART
+ * OpenSBI reference firmwares so that platform specific code get chance
+ * to update "platform" instance before it is used.
+ *
+ * The arguments passed to fw_platform_init() function are boot time state
+ * of A0 to A4 register. The "arg0" will be boot HART id and "arg1" will
+ * be address of FDT passed by previous booting stage.
+ *
+ * The return value of fw_platform_init() function is the FDT location. If
+ * FDT is unchanged (or FDT is modified in-place) then fw_platform_init()
+ * can always return the original FDT location (i.e. 'arg1') unmodified.
+ */
+unsigned long fw_platform_init(unsigned long arg0, unsigned long arg1,
+ unsigned long arg2, unsigned long arg3,
+ unsigned long arg4)
+{
+ const char *model;
+ void *fdt = (void *)arg1;
+ u32 hartid, hart_count = 0;
+ int rc, root_offset, cpus_offset, cpu_offset, len;
+
+ root_offset = fdt_path_offset(fdt, "/");
+ if (root_offset < 0)
+ goto fail;
+
+ fw_platform_lookup_special(fdt, root_offset);
+
+ model = fdt_getprop(fdt, root_offset, "model", &len);
+ if (model)
+ sbi_strncpy(platform.name, model, sizeof(platform.name));
+
+ if (generic_plat && generic_plat->features)
+ platform.features = generic_plat->features(generic_plat_match);
+
+ cpus_offset = fdt_path_offset(fdt, "/cpus");
+ if (cpus_offset < 0)
+ goto fail;
+
+ fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
+ rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
+ if (rc)
+ continue;
+
+ if (SBI_HARTMASK_MAX_BITS <= hartid)
+ continue;
+
+ generic_hart_index2id[hart_count++] = hartid;
+ }
+
+ platform.hart_count = hart_count;
+
+ /* Return original FDT pointer */
+ return arg1;
+
+fail:
+ while (1)
+ wfi();
+}
+
+static int generic_early_init(bool cold_boot)
+{
+ int rc;
+
+ if (generic_plat && generic_plat->early_init) {
+ rc = generic_plat->early_init(cold_boot, generic_plat_match);
+ if (rc)
+ return rc;
+ }
+
+ if (!cold_boot)
+ return 0;
+
+ return fdt_reset_init();
+}
+
+static int generic_final_init(bool cold_boot)
+{
+ void *fdt;
+ int rc;
+
+ if (generic_plat && generic_plat->final_init) {
+ rc = generic_plat->final_init(cold_boot, generic_plat_match);
+ if (rc)
+ return rc;
+ }
+
+ if (!cold_boot)
+ return 0;
+
+ fdt = sbi_scratch_thishart_arg1_ptr();
+
+ 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);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+static void generic_early_exit(void)
+{
+ if (generic_plat && generic_plat->early_exit)
+ generic_plat->early_exit(generic_plat_match);
+}
+
+static void generic_final_exit(void)
+{
+ if (generic_plat && generic_plat->final_exit)
+ 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)
+ return generic_plat->tlbr_flush_limit(generic_plat_match);
+ return SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT;
+}
+
+static int generic_system_reset_check(u32 reset_type, u32 reset_reason)
+{
+ 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 = {
+ .early_init = generic_early_init,
+ .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,
+ .irqchip_init = fdt_irqchip_init,
+ .irqchip_exit = fdt_irqchip_exit,
+ .ipi_send = fdt_ipi_send,
+ .ipi_clear = fdt_ipi_clear,
+ .ipi_init = fdt_ipi_init,
+ .ipi_exit = fdt_ipi_exit,
+ .get_tlbr_flush_limit = generic_tlbr_flush_limit,
+ .timer_value = fdt_timer_value,
+ .timer_event_stop = fdt_timer_event_stop,
+ .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,
+};
+
+struct sbi_platform platform = {
+ .opensbi_version = OPENSBI_VERSION,
+ .platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
+ .name = "Generic",
+ .features = SBI_PLATFORM_DEFAULT_FEATURES,
+ .hart_count = SBI_HARTMASK_MAX_BITS,
+ .hart_index2id = generic_hart_index2id,
+ .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
+ .platform_ops_addr = (unsigned long)&platform_ops
+};
diff --git a/roms/opensbi/platform/generic/sifive_fu540.c b/roms/opensbi/platform/generic/sifive_fu540.c
new file mode 100644
index 000000000..08f7bfc40
--- /dev/null
+++ b/roms/opensbi/platform/generic/sifive_fu540.c
@@ -0,0 +1,47 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <platform_override.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/fdt/fdt_fixup.h>
+
+static u64 sifive_fu540_tlbr_flush_limit(const struct fdt_match *match)
+{
+ /*
+ * The sfence.vma by virtual address does not work on
+ * SiFive FU540 so we return remote TLB flush limit as zero.
+ */
+ return 0;
+}
+
+static int sifive_fu540_fdt_fixup(void *fdt, const struct fdt_match *match)
+{
+ /*
+ * SiFive Freedom U540 has an erratum that prevents S-mode software
+ * to access a PMP protected region using 1GB page table mapping, so
+ * always add the no-map attribute on this platform.
+ */
+ fdt_reserved_memory_nomap_fixup(fdt);
+
+ return 0;
+}
+
+static const struct fdt_match sifive_fu540_match[] = {
+ { .compatible = "sifive,fu540" },
+ { .compatible = "sifive,fu540g" },
+ { .compatible = "sifive,fu540-c000" },
+ { .compatible = "sifive,hifive-unleashed-a00" },
+ { },
+};
+
+const struct platform_override sifive_fu540 = {
+ .match_table = sifive_fu540_match,
+ .tlbr_flush_limit = sifive_fu540_tlbr_flush_limit,
+ .fdt_fixup = sifive_fu540_fdt_fixup,
+};
diff --git a/roms/opensbi/platform/kendryte/k210/config.mk b/roms/opensbi/platform/kendryte/k210/config.mk
new file mode 100644
index 000000000..8a9b81418
--- /dev/null
+++ b/roms/opensbi/platform/kendryte/k210/config.mk
@@ -0,0 +1,19 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2019 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Damien Le Moal <damien.lemoal@wdc.com>
+#
+
+# Compiler flags
+platform-cppflags-y =
+platform-cflags-y =
+platform-asflags-y =
+platform-ldflags-y =
+
+# Blobs to build
+FW_TEXT_START=0x80000000
+FW_PAYLOAD=y
+FW_PAYLOAD_ALIGN=0x1000
diff --git a/roms/opensbi/platform/kendryte/k210/k210.dts b/roms/opensbi/platform/kendryte/k210/k210.dts
new file mode 100644
index 000000000..bcd075bf5
--- /dev/null
+++ b/roms/opensbi/platform/kendryte/k210/k210.dts
@@ -0,0 +1,70 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Damien Le Moal <damien.lemoal@wdc.com>
+ */
+
+/dts-v1/;
+/ {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ compatible = "kendryte,k210";
+
+ chosen {
+ bootargs = "console=hvc0 earlycon=sbi";
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cpu0: cpu@0 {
+ device_type = "cpu";
+ clock-frequency = <390000000>;
+ i-cache-size = <32768>;
+ d-cache-size = <32768>;
+ mmu-type = "none";
+ reg = <0>;
+ riscv,isa = "rv64imafdc";
+ status = "okay";
+ cpu0_intc: interrupt-controller {
+ #interrupt-cells = <1>;
+ compatible = "riscv,cpu-intc";
+ interrupt-controller;
+ };
+ };
+ cpu1: cpu@1 {
+ device_type = "cpu";
+ clock-frequency = <390000000>;
+ d-cache-size = <32768>;
+ i-cache-size = <32768>;
+ mmu-type = "none";
+ reg = <1>;
+ riscv,isa = "rv64imafdc";
+ status = "okay";
+ cpu1_intc: interrupt-controller {
+ #interrupt-cells = <1>;
+ compatible = "riscv,cpu-intc";
+ interrupt-controller;
+ };
+ };
+ };
+
+ memory@80000000 {
+ /* Bank 0: 4 MB, Bank 1: 2 MB, AI chip SRAM: 2MB */
+ device_type = "memory";
+ reg = <0x00000000 0x80000000 0x00000000 0x00800000>;
+ };
+
+ plic0: interrupt-controller@C000000 {
+ #interrupt-cells = <1>;
+ compatible = "riscv,plic0";
+ interrupt-controller;
+ interrupts-extended =
+ <&cpu0_intc 11 &cpu0_intc 9
+ &cpu1_intc 11 &cpu1_intc 9>;
+ reg = <0x0 0xc000000 0x0 0x4000000>;
+ };
+};
diff --git a/roms/opensbi/platform/kendryte/k210/objects.mk b/roms/opensbi/platform/kendryte/k210/objects.mk
new file mode 100644
index 000000000..b74da7407
--- /dev/null
+++ b/roms/opensbi/platform/kendryte/k210/objects.mk
@@ -0,0 +1,14 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2019 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Damien Le Moal <damien.lemoal@wdc.com>
+#
+
+platform-objs-y += platform.o
+
+platform-objs-y += k210.o
+platform-varprefix-k210.o = dt_k210
+platform-padding-k210.o = 2048
diff --git a/roms/opensbi/platform/kendryte/k210/platform.c b/roms/opensbi/platform/kendryte/k210/platform.c
new file mode 100644
index 000000000..944b38885
--- /dev/null
+++ b/roms/opensbi/platform/kendryte/k210/platform.c
@@ -0,0 +1,159 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Damien Le Moal <damien.lemoal@wdc.com>
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#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>
+#include "platform.h"
+
+extern const char dt_k210_start[];
+
+unsigned long fw_platform_init(unsigned long arg0, unsigned long arg1,
+ unsigned long arg2, unsigned long arg3,
+ unsigned long arg4)
+{
+ return (unsigned long)&dt_k210_start[0];
+}
+
+static struct plic_data plic = {
+ .addr = K210_PLIC_BASE_ADDR,
+ .num_src = K210_PLIC_NUM_SOURCES,
+};
+
+static struct clint_data clint = {
+ .addr = K210_CLINT_BASE_ADDR,
+ .first_hartid = 0,
+ .hart_count = K210_HART_COUNT,
+ .has_64bit_mmio = TRUE,
+};
+
+static u32 k210_get_clk_freq(void)
+{
+ u32 clksel0, pll0;
+ u64 pll0_freq, clkr0, clkf0, clkod0, div;
+
+ /*
+ * If the clock selector is not set, use the base frequency.
+ * Otherwise, use PLL0 frequency with a frequency divisor.
+ */
+ clksel0 = k210_read_sysreg(K210_CLKSEL0);
+ if (!(clksel0 & 0x1))
+ return K210_CLK0_FREQ;
+
+ /*
+ * Get PLL0 frequency:
+ * freq = base frequency * clkf0 / (clkr0 * clkod0)
+ */
+ pll0 = k210_read_sysreg(K210_PLL0);
+ clkr0 = 1 + (pll0 & 0x0000000f);
+ clkf0 = 1 + ((pll0 & 0x000003f0) >> 4);
+ clkod0 = 1 + ((pll0 & 0x00003c00) >> 10);
+ pll0_freq = clkf0 * K210_CLK0_FREQ / (clkr0 * clkod0);
+
+ /* Get the frequency divisor from the clock selector */
+ div = 2ULL << ((clksel0 & 0x00000006) >> 1);
+
+ return pll0_freq / div;
+}
+
+static int k210_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(),
+ K210_UART_BAUDRATE);
+}
+
+static int k210_irqchip_init(bool cold_boot)
+{
+ int rc;
+ u32 hartid = current_hartid();
+
+ if (cold_boot) {
+ rc = plic_cold_irqchip_init(&plic);
+ if (rc)
+ return rc;
+ }
+
+ return plic_warm_irqchip_init(&plic, hartid * 2, hartid * 2 + 1);
+}
+
+static int k210_ipi_init(bool cold_boot)
+{
+ int rc;
+
+ if (cold_boot) {
+ rc = clint_cold_ipi_init(&clint);
+ if (rc)
+ return rc;
+ }
+
+ return clint_warm_ipi_init();
+}
+
+static int k210_timer_init(bool cold_boot)
+{
+ int rc;
+
+ if (cold_boot) {
+ rc = clint_cold_timer_init(&clint, NULL);
+ if (rc)
+ return rc;
+ }
+
+ return clint_warm_timer_init();
+}
+
+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,
+
+ .irqchip_init = k210_irqchip_init,
+
+ .ipi_init = k210_ipi_init,
+ .ipi_send = clint_ipi_send,
+ .ipi_clear = clint_ipi_clear,
+
+ .timer_init = k210_timer_init,
+ .timer_value = clint_timer_value,
+ .timer_event_stop = clint_timer_event_stop,
+ .timer_event_start = clint_timer_event_start,
+};
+
+const struct sbi_platform platform = {
+ .opensbi_version = OPENSBI_VERSION,
+ .platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
+ .name = "Kendryte K210",
+ .features = SBI_PLATFORM_HAS_TIMER_VALUE,
+ .hart_count = K210_HART_COUNT,
+ .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
+ .platform_ops_addr = (unsigned long)&platform_ops
+};
diff --git a/roms/opensbi/platform/kendryte/k210/platform.h b/roms/opensbi/platform/kendryte/k210/platform.h
new file mode 100644
index 000000000..5269bc4fd
--- /dev/null
+++ b/roms/opensbi/platform/kendryte/k210/platform.h
@@ -0,0 +1,36 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Damien Le Moal <damien.lemoal@wdc.com>
+ */
+#ifndef _K210_PLATFORM_H_
+#define _K210_PLATFORM_H_
+
+#include <sbi/riscv_io.h>
+
+#define K210_HART_COUNT 2
+
+#define K210_UART_BAUDRATE 115200
+
+#define K210_CLK0_FREQ 26000000UL
+#define K210_PLIC_NUM_SOURCES 65
+
+/* Registers base address */
+#define K210_SYSCTL_BASE_ADDR 0x50440000ULL
+#define K210_UART_BASE_ADDR 0x38000000ULL
+#define K210_CLINT_BASE_ADDR 0x02000000ULL
+#define K210_PLIC_BASE_ADDR 0x0C000000ULL
+
+/* Registers */
+#define K210_PLL0 0x08
+#define K210_CLKSEL0 0x20
+
+static inline u32 k210_read_sysreg(u32 reg)
+{
+ return readl((volatile void *)(K210_SYSCTL_BASE_ADDR + reg));
+}
+
+#endif /* _K210_PLATFORM_H_ */
diff --git a/roms/opensbi/platform/nuclei/ux600/config.mk b/roms/opensbi/platform/nuclei/ux600/config.mk
new file mode 100644
index 000000000..dddcc4ea5
--- /dev/null
+++ b/roms/opensbi/platform/nuclei/ux600/config.mk
@@ -0,0 +1,30 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2020 Nuclei Corporation or its affiliates.
+#
+# Authors:
+# lujun <lujun@nucleisys.com>
+# hqfang <578567190@qq.com>
+#
+
+# Compiler flags
+platform-cppflags-y =
+platform-cflags-y =
+platform-asflags-y =
+platform-ldflags-y =
+
+# Command for platform specific "make run"
+platform-runcmd = xl_spike \
+ $(build_dir)/platform/nuclei/ux600/firmware/fw_payload.elf
+
+# Blobs to build
+FW_TEXT_START=0xA0000000
+FW_DYNAMIC=y
+FW_JUMP=y
+
+FW_JUMP_ADDR=0xA0200000
+FW_JUMP_FDT_ADDR=0xA8000000
+FW_PAYLOAD=y
+FW_PAYLOAD_OFFSET=0x200000
+FW_PAYLOAD_FDT_ADDR=0xA8000000
diff --git a/roms/opensbi/platform/nuclei/ux600/objects.mk b/roms/opensbi/platform/nuclei/ux600/objects.mk
new file mode 100644
index 000000000..8c36c90a7
--- /dev/null
+++ b/roms/opensbi/platform/nuclei/ux600/objects.mk
@@ -0,0 +1,11 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2020 Nuclei Corporation or its affiliates.
+#
+# Authors:
+# lujun <lujun@nuclesys.com>
+# hqfang <578567190@qq.com>
+#
+
+platform-objs-y += platform.o
diff --git a/roms/opensbi/platform/nuclei/ux600/platform.c b/roms/opensbi/platform/nuclei/ux600/platform.c
new file mode 100644
index 000000000..d0a45a2ef
--- /dev/null
+++ b/roms/opensbi/platform/nuclei/ux600/platform.c
@@ -0,0 +1,228 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) Nuclei Corporation or its affiliates.
+ *
+ * Authors:
+ * lujun <lujun@nucleisys.com>
+ * hqfang <578567190@qq.com>
+ */
+
+#include <libfdt.h>
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_io.h>
+#include <sbi/riscv_encoding.h>
+#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>
+
+/* clang-format off */
+
+#define UX600_HART_COUNT 1
+#define UX600_TIMER_FREQ 32768
+
+/* Nuclei timer base address */
+#define UX600_NUCLEI_TIMER_ADDR 0x2000000
+#define UX600_NUCLEI_TIMER_MSFTRST_OFS 0xFF0
+#define UX600_NUCLEI_TIMER_MSFTRST_KEY 0x80000A5F
+/* The clint compatiable timer offset is 0x1000 against nuclei timer */
+#define UX600_CLINT_TIMER_ADDR (UX600_NUCLEI_TIMER_ADDR + 0x1000)
+
+#define UX600_PLIC_ADDR 0x8000000
+#define UX600_PLIC_NUM_SOURCES 0x35
+#define UX600_PLIC_NUM_PRIORITIES 7
+
+#define UX600_UART0_ADDR 0x10013000
+#define UX600_UART1_ADDR 0x10023000
+
+#define UX600_DEBUG_UART UX600_UART0_ADDR
+
+#ifndef UX600_UART_BAUDRATE
+#define UX600_UART_BAUDRATE 57600
+#endif
+
+#define UX600_GPIO_ADDR 0x10012000
+#define UX600_GPIO_IOF_EN_OFS 0x38
+#define UX600_GPIO_IOF_SEL_OFS 0x3C
+#define UX600_GPIO_IOF_UART0_MASK 0x00030000
+
+#define UX600_TIMER_VALUE() readl((void *)UX600_NUCLEI_TIMER_ADDR)
+
+/* clang-format on */
+static u32 ux600_clk_freq = 8000000;
+
+static struct plic_data plic = {
+ .addr = UX600_PLIC_ADDR,
+ .num_src = UX600_PLIC_NUM_SOURCES,
+};
+
+static struct clint_data clint = {
+ .addr = UX600_CLINT_TIMER_ADDR,
+ .first_hartid = 0,
+ .hart_count = UX600_HART_COUNT,
+ .has_64bit_mmio = TRUE,
+};
+static u32 measure_cpu_freq(u32 n)
+{
+ u32 start_mtime, delta_mtime;
+ u32 mtime_freq = UX600_TIMER_FREQ;
+ u32 tmp = (u32)UX600_TIMER_VALUE();
+ u32 start_mcycle, delta_mcycle, freq;
+
+ /* Don't start measuring until we see an mtime tick */
+ do {
+ start_mtime = (u32)UX600_TIMER_VALUE();
+ } while (start_mtime == tmp);
+
+ start_mcycle = csr_read(mcycle);
+
+ do {
+ delta_mtime = (u32)UX600_TIMER_VALUE() - start_mtime;
+ } while (delta_mtime < n);
+
+ delta_mcycle = csr_read(mcycle) - start_mcycle;
+
+ freq = (delta_mcycle / delta_mtime) * mtime_freq
+ + ((delta_mcycle % delta_mtime) * mtime_freq) / delta_mtime;
+
+ return freq;
+}
+
+static u32 ux600_get_clk_freq(void)
+{
+ u32 cpu_freq;
+
+ /* warm up */
+ measure_cpu_freq(1);
+ /* measure for real */
+ cpu_freq = measure_cpu_freq(100);
+
+ return cpu_freq;
+}
+
+static int ux600_early_init(bool cold_boot)
+{
+ u32 regval;
+
+ /* Measure CPU Frequency using Timer */
+ ux600_clk_freq = ux600_get_clk_freq();
+
+ /* Init GPIO UART pinmux */
+ regval = readl((void *)(UX600_GPIO_ADDR + UX600_GPIO_IOF_SEL_OFS)) &
+ ~UX600_GPIO_IOF_UART0_MASK;
+ writel(regval, (void *)(UX600_GPIO_ADDR + UX600_GPIO_IOF_SEL_OFS));
+ regval = readl((void *)(UX600_GPIO_ADDR + UX600_GPIO_IOF_EN_OFS)) |
+ UX600_GPIO_IOF_UART0_MASK;
+ writel(regval, (void *)(UX600_GPIO_ADDR + UX600_GPIO_IOF_EN_OFS));
+ return 0;
+}
+
+static void ux600_modify_dt(void *fdt)
+{
+ fdt_fixups(fdt);
+}
+
+static int ux600_final_init(bool cold_boot)
+{
+ void *fdt;
+
+ if (!cold_boot)
+ return 0;
+
+ fdt = sbi_scratch_thishart_arg1_ptr();
+ ux600_modify_dt(fdt);
+
+ return 0;
+}
+
+static int ux600_console_init(void)
+{
+ return sifive_uart_init(UX600_DEBUG_UART, ux600_clk_freq,
+ UX600_UART_BAUDRATE);
+}
+
+static int ux600_irqchip_init(bool cold_boot)
+{
+ int rc;
+ u32 hartid = current_hartid();
+
+ if (cold_boot) {
+ rc = plic_cold_irqchip_init(&plic);
+ if (rc)
+ return rc;
+ }
+
+ return plic_warm_irqchip_init(&plic, (hartid) ? (2 * hartid - 1) : 0,
+ (hartid) ? (2 * hartid) : -1);
+}
+
+static int ux600_ipi_init(bool cold_boot)
+{
+ int rc;
+
+ if (cold_boot) {
+ rc = clint_cold_ipi_init(&clint);
+ if (rc)
+ return rc;
+ }
+
+ return clint_warm_ipi_init();
+}
+
+static int ux600_timer_init(bool cold_boot)
+{
+ int rc;
+
+ if (cold_boot) {
+ rc = clint_cold_timer_init(&clint, NULL);
+ if (rc)
+ return rc;
+ }
+
+ return clint_warm_timer_init();
+}
+
+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);
+}
+
+const struct sbi_platform_operations platform_ops = {
+ .early_init = ux600_early_init,
+ .final_init = ux600_final_init,
+ .console_putc = sifive_uart_putc,
+ .console_getc = sifive_uart_getc,
+ .console_init = ux600_console_init,
+ .irqchip_init = ux600_irqchip_init,
+ .ipi_send = clint_ipi_send,
+ .ipi_clear = clint_ipi_clear,
+ .ipi_init = ux600_ipi_init,
+ .timer_value = clint_timer_value,
+ .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
+};
+
+const struct sbi_platform platform = {
+ .opensbi_version = OPENSBI_VERSION,
+ .platform_version = SBI_PLATFORM_VERSION(0x0U, 0x01U),
+ .name = "Nuclei UX600",
+ .features = SBI_PLATFORM_DEFAULT_FEATURES,
+ .hart_count = UX600_HART_COUNT,
+ .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
+ .platform_ops_addr = (unsigned long)&platform_ops
+};
diff --git a/roms/opensbi/platform/sifive/fu540/config.mk b/roms/opensbi/platform/sifive/fu540/config.mk
new file mode 100644
index 000000000..23169b1b9
--- /dev/null
+++ b/roms/opensbi/platform/sifive/fu540/config.mk
@@ -0,0 +1,40 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2019 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Atish Patra <atish.patra@wdc.com>
+#
+
+# Compiler flags
+platform-cppflags-y =
+platform-cflags-y =
+platform-asflags-y =
+platform-ldflags-y =
+
+# Command for platform specific "make run"
+platform-runcmd = qemu-system-riscv$(PLATFORM_RISCV_XLEN) -M sifive_u -m 256M \
+ -nographic -bios $(build_dir)/platform/sifive/fu540/firmware/fw_payload.elf
+
+# Blobs to build
+FW_TEXT_START=0x80000000
+FW_DYNAMIC=y
+FW_JUMP=y
+ifeq ($(PLATFORM_RISCV_XLEN), 32)
+ # This needs to be 4MB aligned for 32-bit system
+ FW_JUMP_ADDR=0x80400000
+else
+ # This needs to be 2MB aligned for 64-bit system
+ FW_JUMP_ADDR=0x80200000
+endif
+FW_JUMP_FDT_ADDR=0x88000000
+FW_PAYLOAD=y
+ifeq ($(PLATFORM_RISCV_XLEN), 32)
+ # This needs to be 4MB aligned for 32-bit system
+ FW_PAYLOAD_OFFSET=0x400000
+else
+ # This needs to be 2MB aligned for 64-bit system
+ FW_PAYLOAD_OFFSET=0x200000
+endif
+FW_PAYLOAD_FDT_ADDR=0x88000000
diff --git a/roms/opensbi/platform/sifive/fu540/objects.mk b/roms/opensbi/platform/sifive/fu540/objects.mk
new file mode 100644
index 000000000..e0d058538
--- /dev/null
+++ b/roms/opensbi/platform/sifive/fu540/objects.mk
@@ -0,0 +1,10 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2019 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Atish Patra <atish.patra@wdc.com>
+#
+
+platform-objs-y += platform.o
diff --git a/roms/opensbi/platform/sifive/fu540/platform.c b/roms/opensbi/platform/sifive/fu540/platform.c
new file mode 100644
index 000000000..cdd829363
--- /dev/null
+++ b/roms/opensbi/platform/sifive/fu540/platform.c
@@ -0,0 +1,182 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Atish Patra <atish.patra@wdc.com>
+ */
+
+#include <libfdt.h>
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_io.h>
+#include <sbi/riscv_encoding.h>
+#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>
+
+/* clang-format off */
+
+#define FU540_HART_COUNT 5
+
+#define FU540_SYS_CLK 1000000000
+
+#define FU540_CLINT_ADDR 0x2000000
+
+#define FU540_PLIC_ADDR 0xc000000
+#define FU540_PLIC_NUM_SOURCES 0x35
+#define FU540_PLIC_NUM_PRIORITIES 7
+
+#define FU540_UART0_ADDR 0x10010000
+#define FU540_UART1_ADDR 0x10011000
+#define FU540_UART_BAUDRATE 115200
+
+/* PRCI clock related macros */
+//TODO: Do we need a separate driver for this ?
+#define FU540_PRCI_BASE_ADDR 0x10000000
+#define FU540_PRCI_CLKMUXSTATUSREG 0x002C
+#define FU540_PRCI_CLKMUX_STATUS_TLCLKSEL (0x1 << 1)
+
+/* Full tlb flush always */
+#define FU540_TLB_RANGE_FLUSH_LIMIT 0
+
+/* clang-format on */
+
+static struct plic_data plic = {
+ .addr = FU540_PLIC_ADDR,
+ .num_src = FU540_PLIC_NUM_SOURCES,
+};
+
+static struct clint_data clint = {
+ .addr = FU540_CLINT_ADDR,
+ .first_hartid = 0,
+ .hart_count = FU540_HART_COUNT,
+ .has_64bit_mmio = TRUE,
+};
+
+static void fu540_modify_dt(void *fdt)
+{
+ fdt_cpu_fixup(fdt);
+
+ fdt_fixups(fdt);
+
+ /*
+ * SiFive Freedom U540 has an erratum that prevents S-mode software
+ * to access a PMP protected region using 1GB page table mapping, so
+ * always add the no-map attribute on this platform.
+ */
+ fdt_reserved_memory_nomap_fixup(fdt);
+}
+
+static int fu540_final_init(bool cold_boot)
+{
+ void *fdt;
+
+ if (!cold_boot)
+ return 0;
+
+ fdt = sbi_scratch_thishart_arg1_ptr();
+ fu540_modify_dt(fdt);
+
+ return 0;
+}
+
+static int fu540_console_init(void)
+{
+ unsigned long peri_in_freq;
+
+ if (readl((volatile void *)FU540_PRCI_BASE_ADDR +
+ FU540_PRCI_CLKMUXSTATUSREG) &
+ FU540_PRCI_CLKMUX_STATUS_TLCLKSEL) {
+ peri_in_freq = FU540_SYS_CLK;
+ } else {
+ peri_in_freq = FU540_SYS_CLK / 2;
+ }
+
+ return sifive_uart_init(FU540_UART0_ADDR, peri_in_freq,
+ FU540_UART_BAUDRATE);
+}
+
+static int fu540_irqchip_init(bool cold_boot)
+{
+ int rc;
+ u32 hartid = current_hartid();
+
+ if (cold_boot) {
+ rc = plic_cold_irqchip_init(&plic);
+ if (rc)
+ return rc;
+ }
+
+ return plic_warm_irqchip_init(&plic, (hartid) ? (2 * hartid - 1) : 0,
+ (hartid) ? (2 * hartid) : -1);
+}
+
+static int fu540_ipi_init(bool cold_boot)
+{
+ int rc;
+
+ if (cold_boot) {
+ rc = clint_cold_ipi_init(&clint);
+ if (rc)
+ return rc;
+ }
+
+ return clint_warm_ipi_init();
+}
+
+static u64 fu540_get_tlbr_flush_limit(void)
+{
+ return FU540_TLB_RANGE_FLUSH_LIMIT;
+}
+
+static int fu540_timer_init(bool cold_boot)
+{
+ int rc;
+
+ if (cold_boot) {
+ rc = clint_cold_timer_init(&clint, NULL);
+ if (rc)
+ return rc;
+ }
+
+ return clint_warm_timer_init();
+}
+
+static u32 fu540_hart_index2id[FU540_HART_COUNT - 1] = {
+ [0] = 1,
+ [1] = 2,
+ [2] = 3,
+ [3] = 4,
+};
+
+const struct sbi_platform_operations platform_ops = {
+ .final_init = fu540_final_init,
+ .console_putc = sifive_uart_putc,
+ .console_getc = sifive_uart_getc,
+ .console_init = fu540_console_init,
+ .irqchip_init = fu540_irqchip_init,
+ .ipi_send = clint_ipi_send,
+ .ipi_clear = clint_ipi_clear,
+ .ipi_init = fu540_ipi_init,
+ .get_tlbr_flush_limit = fu540_get_tlbr_flush_limit,
+ .timer_value = clint_timer_value,
+ .timer_event_stop = clint_timer_event_stop,
+ .timer_event_start = clint_timer_event_start,
+ .timer_init = fu540_timer_init,
+};
+
+const struct sbi_platform platform = {
+ .opensbi_version = OPENSBI_VERSION,
+ .platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
+ .name = "SiFive Freedom U540",
+ .features = SBI_PLATFORM_DEFAULT_FEATURES,
+ .hart_count = (FU540_HART_COUNT - 1),
+ .hart_index2id = fu540_hart_index2id,
+ .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
+ .platform_ops_addr = (unsigned long)&platform_ops
+};
diff --git a/roms/opensbi/platform/template/config.mk b/roms/opensbi/platform/template/config.mk
new file mode 100644
index 000000000..f817342c2
--- /dev/null
+++ b/roms/opensbi/platform/template/config.mk
@@ -0,0 +1,77 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2019 Western Digital Corporation or its affiliates.
+#
+
+# Compiler pre-processor flags
+platform-cppflags-y =
+
+# C Compiler and assembler flags.
+platform-cflags-y =
+platform-asflags-y =
+
+# Linker flags: additional libraries and object files that the platform
+# code needs can be added here
+platform-ldflags-y =
+
+#
+# Command for platform specific "make run"
+# Useful for development and debugging on plaftform simulator (such as QEMU)
+#
+# platform-runcmd = your_platform_run.sh
+
+#
+# Platform RISC-V XLEN, ABI, ISA and Code Model configuration.
+# These are optional parameters but platforms can optionaly provide it.
+# Some of these are guessed based on GCC compiler capabilities
+#
+# PLATFORM_RISCV_XLEN = 64
+# PLATFORM_RISCV_ABI = lp64
+# PLATFORM_RISCV_ISA = rv64imafdc
+# PLATFORM_RISCV_CODE_MODEL = medany
+
+# 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
+# as needed.
+#
+FW_DYNAMIC=<y|n>
+
+#
+# Jump firmware configuration.
+# Optional parameters are commented out. Uncomment and define these parameters
+# as needed.
+#
+FW_JUMP=<y|n>
+# This needs to be 4MB aligned for 32-bit support
+# This needs to be 2MB aligned for 64-bit support
+# ifeq ($(PLATFORM_RISCV_XLEN), 32)
+# FW_JUMP_ADDR=0x80400000
+# else
+# FW_JUMP_ADDR=0x80200000
+# endif
+# FW_JUMP_FDT_ADDR=0x82200000
+
+#
+# Firmware with payload configuration.
+# Optional parameters are commented out. Uncomment and define these parameters
+# as needed.
+#
+FW_PAYLOAD=<y|n>
+# This needs to be 4MB aligned for 32-bit support
+# This needs to be 2MB aligned for 64-bit support
+ifeq ($(PLATFORM_RISCV_XLEN), 32)
+FW_PAYLOAD_OFFSET=0x400000
+else
+FW_PAYLOAD_OFFSET=0x200000
+endif
+# FW_PAYLOAD_ALIGN=0x1000
+# FW_PAYLOAD_PATH="path to next boot stage binary image file"
+# FW_PAYLOAD_FDT_ADDR=0x82200000
diff --git a/roms/opensbi/platform/template/objects.mk b/roms/opensbi/platform/template/objects.mk
new file mode 100644
index 000000000..caaec2bee
--- /dev/null
+++ b/roms/opensbi/platform/template/objects.mk
@@ -0,0 +1,15 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2019 Western Digital Corporation or its affiliates.
+#
+
+# Space separated list of object file names to be compiled for the platform
+platform-objs-y += platform.o
+
+#
+# If the platform support requires a builtin device tree file, the name of
+# the device tree compiled file should be specified here. The device tree
+# source file be in the form <dt file name>.dts
+#
+# platform-objs-y += <dt file name>.o
diff --git a/roms/opensbi/platform/template/platform.c b/roms/opensbi/platform/template/platform.c
new file mode 100644
index 000000000..5bdb186c1
--- /dev/null
+++ b/roms/opensbi/platform/template/platform.c
@@ -0,0 +1,223 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_const.h>
+#include <sbi/sbi_platform.h>
+
+/*
+ * Include these files as needed.
+ * See config.mk PLATFORM_xxx configuration parameters.
+ */
+#include <sbi_utils/irqchip/plic.h>
+#include <sbi_utils/serial/uart8250.h>
+#include <sbi_utils/sys/clint.h>
+
+#define PLATFORM_PLIC_ADDR 0xc000000
+#define PLATFORM_PLIC_NUM_SOURCES 128
+#define PLATFORM_HART_COUNT 4
+#define PLATFORM_CLINT_ADDR 0x2000000
+#define PLATFORM_UART_ADDR 0x09000000
+#define PLATFORM_UART_INPUT_FREQ 10000000
+#define PLATFORM_UART_BAUDRATE 115200
+
+static struct plic_data plic = {
+ .addr = PLATFORM_PLIC_ADDR,
+ .num_src = PLATFORM_PLIC_NUM_SOURCES,
+};
+
+static struct clint_data clint = {
+ .addr = PLATFORM_CLINT_ADDR,
+ .first_hartid = 0,
+ .hart_count = PLATFORM_HART_COUNT,
+ .has_64bit_mmio = TRUE,
+};
+
+/*
+ * Platform early initialization.
+ */
+static int platform_early_init(bool cold_boot)
+{
+ return 0;
+}
+
+/*
+ * Platform final initialization.
+ */
+static int platform_final_init(bool cold_boot)
+{
+ return 0;
+}
+
+/*
+ * Initialize the platform console.
+ */
+static int platform_console_init(void)
+{
+ /* Example if the generic UART8250 driver is used */
+ return uart8250_init(PLATFORM_UART_ADDR, PLATFORM_UART_INPUT_FREQ,
+ PLATFORM_UART_BAUDRATE, 0, 1);
+}
+
+/*
+ * Write a character to the platform console output.
+ */
+static void platform_console_putc(char ch)
+{
+ /* Example if the generic UART8250 driver is used */
+ uart8250_putc(ch);
+}
+
+/*
+ * Read a character from the platform console input.
+ */
+static int platform_console_getc(void)
+{
+ return uart8250_getc();
+}
+
+/*
+ * Initialize the platform interrupt controller for current HART.
+ */
+static int platform_irqchip_init(bool cold_boot)
+{
+ u32 hartid = current_hartid();
+ int ret;
+
+ /* Example if the generic PLIC driver is used */
+ if (cold_boot) {
+ ret = plic_cold_irqchip_init(&plic);
+ if (ret)
+ return ret;
+ }
+
+ return plic_warm_irqchip_init(&plic, 2 * hartid, 2 * hartid + 1);
+}
+
+/*
+ * Initialize IPI for current HART.
+ */
+static int platform_ipi_init(bool cold_boot)
+{
+ int ret;
+
+ /* Example if the generic CLINT driver is used */
+ if (cold_boot) {
+ ret = clint_cold_ipi_init(&clint);
+ if (ret)
+ return ret;
+ }
+
+ return clint_warm_ipi_init();
+}
+
+/*
+ * Send IPI to a target HART
+ */
+static void platform_ipi_send(u32 target_hart)
+{
+ /* Example if the generic CLINT driver is used */
+ clint_ipi_send(target_hart);
+}
+
+/*
+ * Clear IPI for a target HART.
+ */
+static void platform_ipi_clear(u32 target_hart)
+{
+ /* Example if the generic CLINT driver is used */
+ clint_ipi_clear(target_hart);
+}
+
+/*
+ * Initialize platform timer for current HART.
+ */
+static int platform_timer_init(bool cold_boot)
+{
+ int ret;
+
+ /* Example if the generic CLINT driver is used */
+ if (cold_boot) {
+ ret = clint_cold_timer_init(&clint, NULL);
+ if (ret)
+ return ret;
+ }
+
+ return clint_warm_timer_init();
+}
+
+/*
+ * Get platform timer value.
+ */
+static u64 platform_timer_value(void)
+{
+ /* Example if the generic CLINT driver is used */
+ return clint_timer_value();
+}
+
+/*
+ * Start platform timer event for current HART.
+ */
+static void platform_timer_event_start(u64 next_event)
+{
+ /* Example if the generic CLINT driver is used */
+ clint_timer_event_start(next_event);
+}
+
+/*
+ * Stop platform timer event for current HART.
+ */
+static void platform_timer_event_stop(void)
+{
+ /* Example if the generic CLINT driver is used */
+ clint_timer_event_stop();
+}
+
+/*
+ * Check reset type and reason supported by the platform.
+ */
+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.
+ */
+const struct sbi_platform_operations platform_ops = {
+ .early_init = platform_early_init,
+ .final_init = platform_final_init,
+ .console_putc = platform_console_putc,
+ .console_getc = platform_console_getc,
+ .console_init = platform_console_init,
+ .irqchip_init = platform_irqchip_init,
+ .ipi_send = platform_ipi_send,
+ .ipi_clear = platform_ipi_clear,
+ .ipi_init = platform_ipi_init,
+ .timer_value = platform_timer_value,
+ .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 = {
+ .opensbi_version = OPENSBI_VERSION,
+ .platform_version = SBI_PLATFORM_VERSION(0x0, 0x00),
+ .name = "platform-name",
+ .features = SBI_PLATFORM_DEFAULT_FEATURES,
+ .hart_count = 1,
+ .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
+ .platform_ops_addr = (unsigned long)&platform_ops
+};
diff --git a/roms/opensbi/platform/thead/c910/config.mk b/roms/opensbi/platform/thead/c910/config.mk
new file mode 100644
index 000000000..bd5eab716
--- /dev/null
+++ b/roms/opensbi/platform/thead/c910/config.mk
@@ -0,0 +1,14 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+# Compiler flags
+platform-cppflags-y =
+platform-cflags-y =
+platform-asflags-y =
+platform-ldflags-y =
+
+# Blobs to build
+FW_TEXT_START?=0x0
+FW_JUMP=y
+FW_JUMP_ADDR?=0x00200000
diff --git a/roms/opensbi/platform/thead/c910/objects.mk b/roms/opensbi/platform/thead/c910/objects.mk
new file mode 100644
index 000000000..d025a3642
--- /dev/null
+++ b/roms/opensbi/platform/thead/c910/objects.mk
@@ -0,0 +1,5 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+platform-objs-y += platform.o
diff --git a/roms/opensbi/platform/thead/c910/platform.c b/roms/opensbi/platform/thead/c910/platform.c
new file mode 100644
index 000000000..dfa484ad2
--- /dev/null
+++ b/roms/opensbi/platform/thead/c910/platform.c
@@ -0,0 +1,156 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_encoding.h>
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_const.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_platform.h>
+#include <sbi_utils/irqchip/plic.h>
+#include <sbi_utils/serial/uart8250.h>
+#include <sbi_utils/sys/clint.h>
+#include "platform.h"
+
+static struct c910_regs_struct c910_regs;
+
+static struct clint_data clint = {
+ .addr = 0, /* Updated at cold boot time */
+ .first_hartid = 0,
+ .hart_count = C910_HART_COUNT,
+ .has_64bit_mmio = FALSE,
+};
+
+static int c910_early_init(bool cold_boot)
+{
+ if (cold_boot) {
+ /* Load from boot core */
+ c910_regs.pmpaddr0 = csr_read(CSR_PMPADDR0);
+ c910_regs.pmpaddr1 = csr_read(CSR_PMPADDR1);
+ c910_regs.pmpaddr2 = csr_read(CSR_PMPADDR2);
+ c910_regs.pmpaddr3 = csr_read(CSR_PMPADDR3);
+ c910_regs.pmpaddr4 = csr_read(CSR_PMPADDR4);
+ c910_regs.pmpaddr5 = csr_read(CSR_PMPADDR5);
+ c910_regs.pmpaddr6 = csr_read(CSR_PMPADDR6);
+ c910_regs.pmpaddr7 = csr_read(CSR_PMPADDR7);
+ c910_regs.pmpcfg0 = csr_read(CSR_PMPCFG0);
+
+ c910_regs.mcor = csr_read(CSR_MCOR);
+ c910_regs.mhcr = csr_read(CSR_MHCR);
+ c910_regs.mccr2 = csr_read(CSR_MCCR2);
+ c910_regs.mhint = csr_read(CSR_MHINT);
+ c910_regs.mxstatus = csr_read(CSR_MXSTATUS);
+
+ c910_regs.plic_base_addr = csr_read(CSR_PLIC_BASE);
+ c910_regs.clint_base_addr =
+ c910_regs.plic_base_addr + C910_PLIC_CLINT_OFFSET;
+ } else {
+ /* Store to other core */
+ csr_write(CSR_PMPADDR0, c910_regs.pmpaddr0);
+ csr_write(CSR_PMPADDR1, c910_regs.pmpaddr1);
+ csr_write(CSR_PMPADDR2, c910_regs.pmpaddr2);
+ csr_write(CSR_PMPADDR3, c910_regs.pmpaddr3);
+ csr_write(CSR_PMPADDR4, c910_regs.pmpaddr4);
+ csr_write(CSR_PMPADDR5, c910_regs.pmpaddr5);
+ csr_write(CSR_PMPADDR6, c910_regs.pmpaddr6);
+ csr_write(CSR_PMPADDR7, c910_regs.pmpaddr7);
+ csr_write(CSR_PMPCFG0, c910_regs.pmpcfg0);
+
+ csr_write(CSR_MCOR, c910_regs.mcor);
+ csr_write(CSR_MHCR, c910_regs.mhcr);
+ csr_write(CSR_MHINT, c910_regs.mhint);
+ csr_write(CSR_MXSTATUS, c910_regs.mxstatus);
+ }
+
+ return 0;
+}
+
+static int c910_final_init(bool cold_boot)
+{
+ return 0;
+}
+
+static int c910_irqchip_init(bool cold_boot)
+{
+ /* Delegate plic enable into S-mode */
+ writel(C910_PLIC_DELEG_ENABLE,
+ (void *)c910_regs.plic_base_addr + C910_PLIC_DELEG_OFFSET);
+
+ return 0;
+}
+
+static int c910_ipi_init(bool cold_boot)
+{
+ int rc;
+
+ if (cold_boot) {
+ clint.addr = c910_regs.clint_base_addr;
+ rc = clint_cold_ipi_init(&clint);
+ if (rc)
+ return rc;
+ }
+
+ return clint_warm_ipi_init();
+}
+
+static int c910_timer_init(bool cold_boot)
+{
+ int ret;
+
+ if (cold_boot) {
+ clint.addr = c910_regs.clint_base_addr;
+ ret = clint_cold_timer_init(&clint, NULL);
+ if (ret)
+ return ret;
+ }
+
+ return clint_warm_timer_init();
+}
+
+static int c910_system_reset_check(u32 type, u32 reason)
+{
+ return 1;
+}
+
+static void c910_system_reset(u32 type, u32 reason)
+{
+ asm volatile ("ebreak");
+}
+
+int c910_hart_start(u32 hartid, ulong saddr)
+{
+ csr_write(CSR_MRVBR, saddr);
+ csr_write(CSR_MRMR, csr_read(CSR_MRMR) | (1 << hartid));
+
+ return 0;
+}
+
+const struct sbi_platform_operations platform_ops = {
+ .early_init = c910_early_init,
+ .final_init = c910_final_init,
+
+ .irqchip_init = c910_irqchip_init,
+
+ .ipi_init = c910_ipi_init,
+ .ipi_send = clint_ipi_send,
+ .ipi_clear = clint_ipi_clear,
+
+ .timer_init = c910_timer_init,
+ .timer_event_start = clint_timer_event_start,
+
+ .system_reset_check = c910_system_reset_check,
+ .system_reset = c910_system_reset,
+
+ .hart_start = c910_hart_start,
+};
+
+const struct sbi_platform platform = {
+ .opensbi_version = OPENSBI_VERSION,
+ .platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
+ .name = "T-HEAD Xuantie c910",
+ .features = SBI_THEAD_FEATURES,
+ .hart_count = C910_HART_COUNT,
+ .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
+ .platform_ops_addr = (unsigned long)&platform_ops
+};
diff --git a/roms/opensbi/platform/thead/c910/platform.h b/roms/opensbi/platform/thead/c910/platform.h
new file mode 100644
index 000000000..354404ef7
--- /dev/null
+++ b/roms/opensbi/platform/thead/c910/platform.h
@@ -0,0 +1,46 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef _C910_PLATFORM_H_
+#define _C910_PLATFORM_H_
+
+#define C910_HART_COUNT 16
+
+#define SBI_THEAD_FEATURES \
+ (SBI_PLATFORM_HAS_MFAULTS_DELEGATION | \
+ SBI_PLATFORM_HAS_HART_SECONDARY_BOOT)
+
+#define CSR_MCOR 0x7c2
+#define CSR_MHCR 0x7c1
+#define CSR_MCCR2 0x7c3
+#define CSR_MHINT 0x7c5
+#define CSR_MXSTATUS 0x7c0
+#define CSR_PLIC_BASE 0xfc1
+#define CSR_MRMR 0x7c6
+#define CSR_MRVBR 0x7c7
+
+#define C910_PLIC_CLINT_OFFSET 0x04000000 /* 64M */
+#define C910_PLIC_DELEG_OFFSET 0x001ffffc
+#define C910_PLIC_DELEG_ENABLE 0x1
+
+struct c910_regs_struct {
+ u64 pmpaddr0;
+ u64 pmpaddr1;
+ u64 pmpaddr2;
+ u64 pmpaddr3;
+ u64 pmpaddr4;
+ u64 pmpaddr5;
+ u64 pmpaddr6;
+ u64 pmpaddr7;
+ u64 pmpcfg0;
+ u64 mcor;
+ u64 mhcr;
+ u64 mccr2;
+ u64 mhint;
+ u64 mxstatus;
+ u64 plic_base_addr;
+ u64 clint_base_addr;
+};
+
+#endif /* _C910_PLATFORM_H_ */
diff --git a/roms/opensbi/scripts/create-binary-archive.sh b/roms/opensbi/scripts/create-binary-archive.sh
new file mode 100755
index 000000000..c19af2698
--- /dev/null
+++ b/roms/opensbi/scripts/create-binary-archive.sh
@@ -0,0 +1,168 @@
+#!/bin/bash
+
+function usage()
+{
+ echo "Usage:"
+ echo " $0 [options]"
+ echo "Options:"
+ echo " -h Display help or usage"
+ echo " -p <opensbi_source_path> OpenSBI source path"
+ echo " -o <output_path> Build output path"
+ echo " -d Build and install documentation"
+ echo " -t Build only with no archive created"
+ echo " -j <num_threads> Number of threads for Make (Default: 1)"
+ echo " -s <archive_suffix> Archive name suffix (Default: unknown)"
+ echo " -x <riscv_xlen> RISC-V XLENs for Build (Default: 0)"
+ echo " 0: RV32 and RV64"
+ echo " 32: RV32 only"
+ echo " 64: RV64 only"
+ exit 1;
+}
+
+# Command line options
+NUM_THREADS=1
+OUTPUT_PATH="$(pwd)/build"
+OPENSBI_SOURCE_PATH="$(pwd)"
+NEED_DOCS="no"
+COMPILE_ONLY="no"
+ARCHIVE_SUFFIX="unknown"
+RISCV_XLEN=0
+
+while getopts "hdtj:o:p:s:x:" o; do
+ case "${o}" in
+ h)
+ usage
+ ;;
+ d)
+ NEED_DOCS="yes"
+ ;;
+ t)
+ COMPILE_ONLY="yes"
+ ;;
+ j)
+ NUM_THREADS=${OPTARG}
+ ;;
+ o)
+ OUTPUT_PATH=${OPTARG}
+ ;;
+ p)
+ OPENSBI_SOURCE_PATH=${OPTARG}
+ ;;
+ s)
+ ARCHIVE_SUFFIX=${OPTARG}
+ ;;
+ x)
+ RISCV_XLEN=${OPTARG}
+ ;;
+ *)
+ usage
+ ;;
+ esac
+done
+shift $((OPTIND-1))
+
+if [ -z "${OPENSBI_SOURCE_PATH}" ]; then
+ echo "Must specify OpenSBI source path"
+ usage
+fi
+
+if [ ! -d "${OPENSBI_SOURCE_PATH}" ]; then
+ echo "OpenSBI source path does not exist"
+ usage
+fi
+
+if [ -z "${ARCHIVE_SUFFIX}" ]; then
+ echo "Archive suffice cannot be empty"
+ usage
+fi
+
+build_opensbi() {
+ # Setup parameters
+ BUILD_NUM_THREADS=$1
+ BUILD_OUTPUT_PATH=$2
+ BUILD_OPENSBI_SOURCE_PATH=$3
+ BUILD_DOCS=$4
+ BUILD_ONLY=$5
+ BUILD_RISCV_XLEN=$6
+ BUILD_ARCHIVE_RISCV_XLEN=$7
+ BUILD_ARCHIVE_SUFFIX=$8
+
+ # Setup derived parameters
+ BUILD_VERSION_MAJOR=$(grep "define OPENSBI_VERSION_MAJOR" "${BUILD_OPENSBI_SOURCE_PATH}/include/sbi/sbi_version.h" | sed 's/.*MAJOR.*\([0-9][0-9]*\)/\1/')
+ BUILD_VERSION_MINOR=$(grep "define OPENSBI_VERSION_MINOR" "${BUILD_OPENSBI_SOURCE_PATH}/include/sbi/sbi_version.h" | sed 's/.*MINOR.*\([0-9][0-9]*\)/\1/')
+ BUILD_NAME="opensbi-${BUILD_VERSION_MAJOR}.${BUILD_VERSION_MINOR}-rv${BUILD_RISCV_XLEN}"
+ BUILD_ARCHIVE_NAME="opensbi-${BUILD_VERSION_MAJOR}.${BUILD_VERSION_MINOR}-rv${BUILD_ARCHIVE_RISCV_XLEN}-${BUILD_ARCHIVE_SUFFIX}"
+ case "${BUILD_RISCV_XLEN}" in
+ 32)
+ # Setup 32-bit platform list
+ BUILD_PLATFORM_SUBDIR=("sifive/fu540")
+ BUILD_PLATFORM_SUBDIR+=("generic")
+ ;;
+ 64)
+ # Setup 64-bit platform list
+ BUILD_PLATFORM_SUBDIR=("sifive/fu540")
+ BUILD_PLATFORM_SUBDIR+=("nuclei/ux600")
+ BUILD_PLATFORM_SUBDIR+=("kendryte/k210")
+ BUILD_PLATFORM_SUBDIR+=("fpga/ariane")
+ BUILD_PLATFORM_SUBDIR+=("fpga/openpiton")
+ BUILD_PLATFORM_SUBDIR+=("andes/ae350")
+ BUILD_PLATFORM_SUBDIR+=("thead/c910")
+ BUILD_PLATFORM_SUBDIR+=("generic")
+ ;;
+ *)
+ echo "Invalid Build RISC-V XLEN"
+ usage
+ ;;
+ esac
+
+ # Ensure output directory is present
+ mkdir -p "${BUILD_OUTPUT_PATH}/${BUILD_NAME}"
+
+ # Build and install generic library
+ echo "Build and install generic library XLEN=${BUILD_RISCV_XLEN}"
+ echo ""
+ make -C "${BUILD_OPENSBI_SOURCE_PATH}" O="${BUILD_OUTPUT_PATH}/${BUILD_NAME}" I="${BUILD_OUTPUT_PATH}/${BUILD_ARCHIVE_NAME}" PLATFORM_RISCV_XLEN="${BUILD_RISCV_XLEN}" install_libsbi install_libsbiutils -j "${BUILD_NUM_THREADS}"
+ echo ""
+
+ # Build and install relevant platforms
+ for INDEX in $(seq 0 1 "$(expr ${#BUILD_PLATFORM_SUBDIR[*]} - 1)")
+ do
+ echo "Build and install PLATFORM=${BUILD_PLATFORM_SUBDIR[${INDEX}]} XLEN=${BUILD_RISCV_XLEN}"
+ echo ""
+ make -C "${BUILD_OPENSBI_SOURCE_PATH}" O="${BUILD_OUTPUT_PATH}/${BUILD_NAME}" I="${BUILD_OUTPUT_PATH}/${BUILD_ARCHIVE_NAME}" PLATFORM="${BUILD_PLATFORM_SUBDIR[${INDEX}]}" PLATFORM_RISCV_XLEN="${BUILD_RISCV_XLEN}" install_libplatsbi install_firmwares -j "${BUILD_NUM_THREADS}"
+ echo ""
+ done
+
+ # Build and install docs
+ if [ "${BUILD_DOCS}" == "yes" ]; then
+ echo "Build and install docs"
+ echo ""
+ make -C "${BUILD_OPENSBI_SOURCE_PATH}" O="${BUILD_OUTPUT_PATH}/${BUILD_NAME}" I="${BUILD_OUTPUT_PATH}/${BUILD_ARCHIVE_NAME}" install_docs
+ echo ""
+ fi
+
+ # Create archive file
+ if [ "${BUILD_ONLY}" == "no" ]; then
+ echo "Create archive ${BUILD_ARCHIVE_NAME}.tar.xz"
+ echo ""
+ tar -C "${BUILD_OUTPUT_PATH}" -cJvf "${BUILD_OUTPUT_PATH}/${BUILD_ARCHIVE_NAME}.tar.xz" "${BUILD_ARCHIVE_NAME}"
+ echo ""
+ fi
+}
+
+case "${RISCV_XLEN}" in
+0)
+ build_opensbi ${NUM_THREADS} ${OUTPUT_PATH} ${OPENSBI_SOURCE_PATH} "no" "yes" "32" "" ${ARCHIVE_SUFFIX}
+ build_opensbi ${NUM_THREADS} ${OUTPUT_PATH} ${OPENSBI_SOURCE_PATH} ${NEED_DOCS} ${COMPILE_ONLY} "64" "" ${ARCHIVE_SUFFIX}
+ ;;
+32)
+ build_opensbi ${NUM_THREADS} ${OUTPUT_PATH} ${OPENSBI_SOURCE_PATH} ${NEED_DOCS} ${COMPILE_ONLY} "32" "32" ${ARCHIVE_SUFFIX}
+ ;;
+64)
+ build_opensbi ${NUM_THREADS} ${OUTPUT_PATH} ${OPENSBI_SOURCE_PATH} ${NEED_DOCS} ${COMPILE_ONLY} "64" "64" ${ARCHIVE_SUFFIX}
+ ;;
+*)
+ echo "Invalid RISC-V XLEN"
+ usage
+ ;;
+esac
diff --git a/roms/opensbi/scripts/d2c.sh b/roms/opensbi/scripts/d2c.sh
new file mode 100755
index 000000000..33a3ccf76
--- /dev/null
+++ b/roms/opensbi/scripts/d2c.sh
@@ -0,0 +1,74 @@
+#!/bin/bash
+
+function usage()
+{
+ echo "Usage:"
+ echo " $0 [options]"
+ echo "Options:"
+ echo " -h Display help or 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;
+}
+
+# Command line options
+INPUT_PATH=""
+OUTPUT_C_ALIGN=""
+OUTPUT_C_PREFIX=""
+NUM_ZERO_BYTES=0
+
+while getopts "hi:a:p:t:" o; do
+ case "${o}" in
+ h)
+ usage
+ ;;
+ i)
+ INPUT_PATH=${OPTARG}
+ ;;
+ a)
+ OUTPUT_C_ALIGN=${OPTARG}
+ ;;
+ p)
+ OUTPUT_C_PREFIX=${OPTARG}
+ ;;
+ t)
+ NUM_ZERO_BYTES=${OPTARG}
+ ;;
+ *)
+ usage
+ ;;
+ esac
+done
+shift $((OPTIND-1))
+
+if [ -z "${INPUT_PATH}" ]; then
+ echo "Must specify input file path"
+ usage
+fi
+
+if [ ! -f "${INPUT_PATH}" ]; then
+ echo "The input path should be a file"
+ usage
+fi
+
+if [ -z "${OUTPUT_C_ALIGN}" ]; then
+ echo "Must provide output C array alignment"
+ usage
+fi
+
+if [ -z "${OUTPUT_C_PREFIX}" ]; then
+ echo "Must provide output C array name prefix"
+ usage
+fi
+
+printf "const char __attribute__((aligned(%s))) %s_start[] = {\n" "${OUTPUT_C_ALIGN}" "${OUTPUT_C_PREFIX}"
+
+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}"