Browse Source

initial opensbi use v0.9 release package from github.com/riscv/opensbi

封欢 3 years ago
commit
c4a0624c3c
100 changed files with 11504 additions and 0 deletions
  1. 16 0
      .clang-format
  2. 11 0
      .gitignore
  3. 27 0
      CONTRIBUTORS.md
  4. 25 0
      COPYING.BSD
  5. 493 0
      Makefile
  6. 286 0
      README.md
  7. 18 0
      ThirdPartyNotices.md
  8. 84 0
      docs/contributing.md
  9. 314 0
      docs/domain_support.md
  10. 2462 0
      docs/doxygen.cfg
  11. 32 0
      docs/external/coreboot.md
  12. 111 0
      docs/firmware/fw.md
  13. 35 0
      docs/firmware/fw_dynamic.md
  14. 51 0
      docs/firmware/fw_jump.md
  15. 72 0
      docs/firmware/fw_payload.md
  16. 9 0
      docs/firmware/payload_linux.md
  17. 15 0
      docs/firmware/payload_uboot.md
  18. 89 0
      docs/library_usage.md
  19. 30 0
      docs/platform/andes-ae350.md
  20. 38 0
      docs/platform/fpga-ariane.md
  21. 33 0
      docs/platform/fpga-openpiton.md
  22. 54 0
      docs/platform/generic.md
  23. 22 0
      docs/platform/nuclei_ux600.md
  24. 59 0
      docs/platform/platform.md
  25. 149 0
      docs/platform/qemu_virt.md
  26. 33 0
      docs/platform/shakti_cclass.md
  27. 195 0
      docs/platform/sifive_fu540.md
  28. 89 0
      docs/platform/spike.md
  29. 34 0
      docs/platform/thead-c910.md
  30. 42 0
      docs/platform_guide.md
  31. 44 0
      docs/platform_requirements.md
  32. 14 0
      firmware/external_deps.mk
  33. 769 0
      firmware/fw_base.S
  34. 81 0
      firmware/fw_base.ldS
  35. 151 0
      firmware/fw_dynamic.S
  36. 18 0
      firmware/fw_dynamic.elf.ldS
  37. 96 0
      firmware/fw_jump.S
  38. 18 0
      firmware/fw_jump.elf.ldS
  39. 97 0
      firmware/fw_payload.S
  40. 32 0
      firmware/fw_payload.elf.ldS
  41. 57 0
      firmware/objects.mk
  42. 19 0
      firmware/payloads/objects.mk
  43. 87 0
      firmware/payloads/test.elf.ldS
  44. 88 0
      firmware/payloads/test_head.S
  45. 48 0
      firmware/payloads/test_main.c
  46. 79 0
      include/sbi/fw_dynamic.h
  47. 187 0
      include/sbi/riscv_asm.h
  48. 70 0
      include/sbi/riscv_atomic.h
  49. 57 0
      include/sbi/riscv_barrier.h
  50. 699 0
      include/sbi/riscv_encoding.h
  51. 94 0
      include/sbi/riscv_fp.h
  52. 114 0
      include/sbi/riscv_io.h
  53. 34 0
      include/sbi/riscv_locks.h
  54. 128 0
      include/sbi/sbi_bitmap.h
  55. 320 0
      include/sbi/sbi_bitops.h
  56. 39 0
      include/sbi/sbi_console.h
  57. 48 0
      include/sbi/sbi_const.h
  58. 50 0
      include/sbi/sbi_csr_detect.h
  59. 165 0
      include/sbi/sbi_domain.h
  60. 61 0
      include/sbi/sbi_ecall.h
  61. 98 0
      include/sbi/sbi_ecall_interface.h
  62. 23 0
      include/sbi/sbi_emulate_csr.h
  63. 38 0
      include/sbi/sbi_error.h
  64. 42 0
      include/sbi/sbi_fifo.h
  65. 56 0
      include/sbi/sbi_hart.h
  66. 141 0
      include/sbi/sbi_hartmask.h
  67. 38 0
      include/sbi/sbi_hfence.h
  68. 38 0
      include/sbi/sbi_hsm.h
  69. 19 0
      include/sbi/sbi_illegal_insn.h
  70. 23 0
      include/sbi/sbi_init.h
  71. 70 0
      include/sbi/sbi_ipi.h
  72. 152 0
      include/sbi/sbi_list.h
  73. 15 0
      include/sbi/sbi_math.h
  74. 23 0
      include/sbi/sbi_misaligned_ldst.h
  75. 757 0
      include/sbi/sbi_platform.h
  76. 128 0
      include/sbi/sbi_scratch.h
  77. 46 0
      include/sbi/sbi_string.h
  78. 19 0
      include/sbi/sbi_system.h
  79. 44 0
      include/sbi/sbi_timer.h
  80. 60 0
      include/sbi/sbi_tlb.h
  81. 214 0
      include/sbi/sbi_trap.h
  82. 109 0
      include/sbi/sbi_types.h
  83. 41 0
      include/sbi/sbi_unpriv.h
  84. 24 0
      include/sbi/sbi_version.h
  85. 73 0
      include/sbi_utils/fdt/fdt_domain.h
  86. 78 0
      include/sbi_utils/fdt/fdt_fixup.h
  87. 68 0
      include/sbi_utils/fdt/fdt_helper.h
  88. 32 0
      include/sbi_utils/ipi/fdt_ipi.h
  89. 26 0
      include/sbi_utils/irqchip/fdt_irqchip.h
  90. 29 0
      include/sbi_utils/irqchip/plic.h
  91. 28 0
      include/sbi_utils/reset/fdt_reset.h
  92. 28 0
      include/sbi_utils/serial/fdt_serial.h
  93. 18 0
      include/sbi_utils/serial/shakti-uart.h
  94. 21 0
      include/sbi_utils/serial/sifive-uart.h
  95. 22 0
      include/sbi_utils/serial/uart8250.h
  96. 51 0
      include/sbi_utils/sys/clint.h
  97. 21 0
      include/sbi_utils/sys/htif.h
  98. 21 0
      include/sbi_utils/sys/sifive_test.h
  99. 35 0
      include/sbi_utils/timer/fdt_timer.h
  100. 43 0
      lib/sbi/objects.mk

+ 16 - 0
.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

+ 11 - 0
.gitignore

@@ -0,0 +1,11 @@
+# Object files
+*.o
+*.a
+*.dep
+
+#Build & install directories
+build/
+install/
+
+# Development friendly files
+tags

+ 27 - 0
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>

+ 25 - 0
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.

+ 493 - 0
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

+ 286 - 0
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

+ 18 - 0
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).

+ 84 - 0
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/

+ 314 - 0
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 {
+        ...
+    };
+```

+ 2462 - 0
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

+ 32 - 0
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

+ 111 - 0
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.

+ 35 - 0
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*.

+ 51 - 0
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

+ 72 - 0
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

+ 9 - 0
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.

+ 15 - 0
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.
+

+ 89 - 0
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.

+ 30 - 0
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>
+```

+ 38 - 0
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.

+ 33 - 0
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.

+ 54 - 0
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

+ 22 - 0
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
+```

+ 59 - 0
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

+ 149 - 0
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"
+```

+ 33 - 0
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>
+```

+ 195 - 0
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

+ 89 - 0
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"
+```

+ 34 - 0
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.

+ 42 - 0
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.

+ 44 - 0
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

+ 14 - 0
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)

+ 769 - 0
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

+ 81 - 0
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 = .);

+ 151 - 0
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

+ 18 - 0
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 = .);
+}

+ 96 - 0
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

+ 18 - 0
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 = .);
+}

+ 97 - 0
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

+ 32 - 0
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 = .);
+}

+ 57 - 0
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

+ 19 - 0
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,$@,$^)

+ 87 - 0
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 = .);
+}

+ 88 - 0
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

+ 48 - 0
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();
+}

+ 79 - 0
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

+ 187 - 0
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

+ 70 - 0
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

+ 57 - 0
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

+ 699 - 0
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

+ 94 - 0
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

+ 114 - 0
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

+ 34 - 0
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

+ 128 - 0
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

+ 320 - 0
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

+ 39 - 0
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

+ 48 - 0
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

+ 50 - 0
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

+ 165 - 0
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

+ 61 - 0
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

+ 98 - 0
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

+ 23 - 0
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

+ 38 - 0
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

+ 42 - 0
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

+ 56 - 0
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

+ 141 - 0
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

+ 38 - 0
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

+ 38 - 0
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

+ 19 - 0
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

+ 23 - 0
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

+ 70 - 0
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

+ 152 - 0
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

+ 15 - 0
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

+ 23 - 0
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

+ 757 - 0
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

+ 128 - 0
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

+ 46 - 0
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

+ 19 - 0
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

+ 44 - 0
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

+ 60 - 0
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

+ 214 - 0
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

+ 109 - 0
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

+ 41 - 0
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

+ 24 - 0
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

+ 73 - 0
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__ */

+ 78 - 0
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__ */
+

+ 68 - 0
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__ */

+ 32 - 0
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

+ 26 - 0
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

+ 29 - 0
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

+ 28 - 0
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

+ 28 - 0
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

+ 18 - 0
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

+ 21 - 0
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

+ 22 - 0
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

+ 51 - 0
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

+ 21 - 0
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

+ 21 - 0
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

+ 35 - 0
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

+ 43 - 0
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

Some files were not shown because too many files changed in this diff